srctree

Gregory Mullen parent 1bc1d370 e8d0159a
add the "browser" msie

inlinesplit
src/bot-detection.zig added: 70, removed: 36, total 34
@@ -34,7 +34,12 @@ pub fn init(r: *const Request) BotDetection {
}
 
switch (ua.resolved) {
.bot => bot.bot = true,
.bot => {
bot.bot = true;
inline for (rules.bots) |rule| {
rule(ua, r, &bot.score) catch @panic("not implemented");
}
},
.browser => |browser| {
// Any bot that masqurades as a browser is by definition malign
if (bot.score >= ANOMALY_MAX) {
@@ -43,6 +48,10 @@ pub fn init(r: *const Request) BotDetection {
}
switch (browser.name) {
.chrome => {},
.msie => {
bot.bot = true;
bot.malicious = true;
},
else => {},
}
},
@@ -62,6 +71,9 @@ const rules = struct {
const global = [_]RuleFn{
browsers.browserAge,
};
const bots = [_]RuleFn{
//
};
};
 
pub const browsers = @import("bot-detection/browsers.zig");
 
src/bot-detection/browsers.zig added: 70, removed: 36, total 34
@@ -5,15 +5,14 @@ const browser_count = @typeInfo(UA.Browser.Name).@"enum".fields.len;
 
pub const Versions: [browser_count][]const Date = brk: {
var v: [browser_count][]const Date = undefined;
v[@intFromEnum(UA.Browser.Name.brave)] = &.{};
v[@intFromEnum(UA.Browser.Name.chrome)] = &Chrome.Version.Dates;
v[@intFromEnum(UA.Browser.Name.edge)] = &.{};
v[@intFromEnum(UA.Browser.Name.firefox)] = &Firefox.Version.Dates;
v[@intFromEnum(UA.Browser.Name.hastur)] = &.{};
v[@intFromEnum(UA.Browser.Name.ladybird)] = &.{};
v[@intFromEnum(UA.Browser.Name.opera)] = &.{};
v[@intFromEnum(UA.Browser.Name.safari)] = &.{};
v[@intFromEnum(UA.Browser.Name.unknown)] = &.{};
for (@typeInfo(UA.Browser.Name).@"enum".fields) |field| {
var name: [field.name.len]u8 = field.name[0..].*;
name[0] ^= 0b100000;
v[field.value] = if (@hasDecl(@This(), &name))
&@field(@This(), &name).Version.Dates
else
&.{};
}
 
break :brk v;
};
@@ -22,6 +21,7 @@ pub const Chrome = struct {
pub const Version = enum(u16) {
_,
 
pub const Dates = compileDates(&VerDates);
pub const VerDates = [_]VerDate{
.{ 0, 1227513600 }, .{ 1, 1228982400 }, .{ 2, 1243148400 }, .{ 3, 1255330800 },
.{ 4, 1264406400 }, .{ 5, 1274425200 }, .{ 6, 1283410800 }, .{ 7, 1287644400 },
@@ -59,15 +59,6 @@ pub const Chrome = struct {
.{ 128, 1723618800 }, .{ 129, 1726038000 }, .{ 130, 1728457200 }, .{ 131, 1730880000 },
.{ 132, 1736323200 }, .{ 133, 1738137600 }, .{ 134, 1740556800 }, .{ 135, 1743465600 },
};
pub const Dates: [VerDates.len]Date = brk: {
var list: [VerDates.len]Date = @splat(0);
 
for (VerDates) |line| {
std.debug.assert(list[line[0]] == 0);
list[line[0]] = line[1];
}
break :brk list;
};
};
};
 
@@ -75,6 +66,7 @@ pub const Firefox = struct {
pub const Version = enum(u16) {
_,
 
pub const Dates = compileDates(&VerDates);
pub const VerDates = [_]VerDate{
.{ 0, 1099980000 }, .{ 1, 1099987200 }, .{ 2, 1161673200 }, .{ 3, 1213686000 },
.{ 4, 1300777200 }, .{ 5, 1308639600 }, .{ 6, 1313478000 }, .{ 7, 1317106800 },
@@ -112,18 +104,31 @@ pub const Firefox = struct {
.{ 132, 1730185200 }, .{ 133, 1732608000 }, .{ 134, 1736236800 }, .{ 135, 1738656000 },
.{ 136, 1741075200 }, .{ 137, 1743490800 },
};
pub const Dates: [VerDates.len]Date = brk: {
var list: [VerDates.len]Date = @splat(0);
};
};
 
for (VerDates) |line| {
std.debug.assert(list[line[0]] == 0);
list[line[0]] = line[1];
}
break :brk list;
pub const Msie = struct {
pub const Version = enum(u16) {
_,
pub const Dates = compileDates(&VerDates);
pub const VerDates = [_]VerDate{
.{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 }, .{ 4, 0 },
.{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 }, .{ 9, 0 },
.{ 10, 0 }, .{ 11, 0 },
};
};
};
 
fn compileDates(comptime vd: []const VerDate) [vd.len]Date {
var list: [vd.len]Date = @splat(0);
 
for (vd) |line| {
std.debug.assert(list[line[0]] == 0);
list[line[0]] = line[1];
}
return list;
}
 
pub fn browserAge(ua: UA, _: *const Request, score: *f16) !void {
if (ua.resolved != .browser) return;
if (ua.resolved.browser.name == .unknown) return;
 
src/user-agent.zig added: 70, removed: 36, total 34
@@ -16,7 +16,8 @@ pub fn botDetectionDump(ua: UserAgent, r: *const Request) void {
std.debug.print("ua detection: {} \n", .{ua.resolved});
std.debug.print("bot detection: {} \n", .{bd});
if (ua.resolved == .browser) {
std.debug.print("age: {} \n", .{ua.resolved.browser.age() catch 0});
const age = ua.resolved.browser.age() catch 0;
std.debug.print("age: days {} seconds {} \n", .{ @divTrunc(age, 86400), age });
}
}
 
@@ -36,12 +37,15 @@ pub const Resolved = union(enum) {
}
 
fn mozilla(str: []const u8) Resolved {
if (indexOf(u8, str, "bot/") != null or
indexOf(u8, str, "Bot/") != null or
indexOf(u8, str, "bot.html") != null or
indexOf(u8, str, "Bot.html") != null)
{
return asBot(str);
const idx: ?usize = indexOf(u8, str, "bot") orelse indexOf(u8, str, "Bot");
 
if (idx) |i| {
if (str.len == i + 3 or (str.len > i + 4 and (str[i + 3] == '/' or
str[i + 3] == '.' or
str[i + 3] == ')')))
{
return asBot(str);
}
}
return asBrowser(str);
}
@@ -82,6 +86,7 @@ pub const Resolved = union(enum) {
.{ .chrome, "Chrome/", "Chrome/" },
.{ .firefox, "Firefox/", "Firefox/" },
.{ .safari, "Safari/", "Version/" },
.{ .msie, "MSIE ", "MSIE " },
};
 
inline for (options) |opt| {
@@ -164,6 +169,16 @@ test Resolved {
} },
Resolved.init(lin_ff),
);
 
const msie = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)";
try std.testing.expectEqualDeep(
Resolved{ .browser = .{
.name = .msie,
.version = 9,
.version_string = "9.0;",
} },
Resolved.init(msie),
);
}
 
pub const Bot = struct {
@@ -195,6 +210,8 @@ pub const Browser = struct {
opera,
safari,
unknown,
// lol, ok bro
msie,
};
 
test Name {}