From 79c6b1ed0a42674c0e53d01e8c7f107498005725 Mon Sep 17 00:00:00 2001 From: Muki Kiboigo Date: Thu, 19 Feb 2026 12:30:03 -0800 Subject: [PATCH] add support for WebBotAuth in Client --- src/App.zig | 11 ++++++++++- src/Config.zig | 6 +++--- src/http/Client.zig | 20 +++++++++++++++++++- src/http/Http.zig | 12 ++++++++++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/App.zig b/src/App.zig index bb797ec5..3e8fc439 100644 --- a/src/App.zig +++ b/src/App.zig @@ -26,6 +26,7 @@ const Snapshot = @import("browser/js/Snapshot.zig"); const Platform = @import("browser/js/Platform.zig"); const Telemetry = @import("telemetry/telemetry.zig").Telemetry; const RobotStore = @import("browser/Robots.zig").RobotStore; +const WebBotAuth = @import("browser/WebBotAuth.zig"); pub const Http = @import("http/Http.zig"); pub const ArenaPool = @import("ArenaPool.zig"); @@ -40,6 +41,7 @@ telemetry: Telemetry, allocator: Allocator, arena_pool: ArenaPool, robots: RobotStore, +web_bot_auth: ?WebBotAuth, app_dir_path: ?[]const u8, shutdown: bool = false, @@ -52,7 +54,14 @@ pub fn init(allocator: Allocator, config: *const Config) !*App { app.robots = RobotStore.init(allocator); - app.http = try Http.init(allocator, &app.robots, config); + if (config.webBotAuth()) |wba_cfg| { + app.web_bot_auth = try WebBotAuth.fromConfig(allocator, &wba_cfg); + } else { + app.web_bot_auth = null; + } + errdefer if (app.web_bot_auth) |wba| wba.deinit(allocator); + + app.http = try Http.init(allocator, &app.robots, &app.web_bot_auth, config); errdefer app.http.deinit(); app.platform = try Platform.init(); diff --git a/src/Config.zig b/src/Config.zig index 3f4e797f..8aed2e68 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -23,7 +23,7 @@ const Allocator = std.mem.Allocator; const log = @import("log.zig"); const dump = @import("browser/dump.zig"); -const WebBotAuth = @import("browser/WebBotAuth.zig"); +const WebBotAuthConfig = @import("browser/WebBotAuth.zig").Config; pub const RunMode = enum { help, @@ -155,9 +155,9 @@ pub fn userAgentSuffix(self: *const Config) ?[]const u8 { }; } -pub fn webBotAuth(self: *const Config) ?WebBotAuth { +pub fn webBotAuth(self: *const Config) ?WebBotAuthConfig { return switch (self.mode) { - inline .serve, .fetch, .mcp => |opts| WebBotAuth{ + inline .serve, .fetch, .mcp => |opts| WebBotAuthConfig{ .key_file = opts.common.web_bot_auth_key_file orelse return null, .keyid = opts.common.web_bot_auth_keyid orelse return null, .domain = opts.common.web_bot_auth_domain orelse return null, diff --git a/src/http/Client.zig b/src/http/Client.zig index 326635f4..bb3fed47 100644 --- a/src/http/Client.zig +++ b/src/http/Client.zig @@ -29,6 +29,8 @@ const Notification = @import("../Notification.zig"); const CookieJar = @import("../browser/webapi/storage/Cookie.zig").Jar; const Robots = @import("../browser/Robots.zig"); const RobotStore = Robots.RobotStore; +const WebBotAuth = @import("../browser/WebBotAuth.zig"); + const posix = std.posix; const Allocator = std.mem.Allocator; @@ -83,6 +85,9 @@ robot_store: *RobotStore, // Allows us to fetch the robots.txt just once. pending_robots_queue: std.StringHashMapUnmanaged(std.ArrayList(Request)) = .empty, +// Reference to the App-owned WebBotAuth. +web_bot_auth: *const ?WebBotAuth, + // Once we have a handle/easy to process a request with, we create a Transfer // which contains the Request as well as any state we need to process the // request. These wil come and go with each request. @@ -121,7 +126,13 @@ pub const CDPClient = struct { const TransferQueue = std.DoublyLinkedList; -pub fn init(allocator: Allocator, ca_blob: ?Net.Blob, robot_store: *RobotStore, config: *const Config) !*Client { +pub fn init( + allocator: Allocator, + ca_blob: ?Net.Blob, + robot_store: *RobotStore, + web_bot_auth: *const ?WebBotAuth, + config: *const Config, +) !*Client { var transfer_pool = std.heap.MemoryPool(Transfer).init(allocator); errdefer transfer_pool.deinit(); @@ -145,6 +156,7 @@ pub fn init(allocator: Allocator, ca_blob: ?Net.Blob, robot_store: *RobotStore, .handles = handles, .allocator = allocator, .robot_store = robot_store, + .web_bot_auth = web_bot_auth, .http_proxy = http_proxy, .use_proxy = http_proxy != null, .config = config, @@ -709,6 +721,12 @@ fn makeRequest(self: *Client, conn: *Net.Connection, transfer: *Transfer) anyerr try conn.secretHeaders(&header_list, &self.config.http_headers); // Add headers that must be hidden from intercepts try conn.setHeaders(&header_list); + // If we have WebBotAuth, sign our request. + if (self.web_bot_auth.*) |wba| { + const authority = URL.getHost(req.url); + try wba.signRequest(self.allocator, &header_list, authority); + } + // Add cookies. if (header_list.cookies) |cookies| { try conn.setCookies(cookies); diff --git a/src/http/Http.zig b/src/http/Http.zig index 778a1be4..87075b78 100644 --- a/src/http/Http.zig +++ b/src/http/Http.zig @@ -29,6 +29,7 @@ pub const Headers = Net.Headers; const Config = @import("../Config.zig"); const RobotStore = @import("../browser/Robots.zig").RobotStore; +const WebBotAuth = @import("../browser/WebBotAuth.zig"); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; @@ -45,8 +46,14 @@ allocator: Allocator, config: *const Config, ca_blob: ?Net.Blob, robot_store: *RobotStore, +web_bot_auth: *const ?WebBotAuth, -pub fn init(allocator: Allocator, robot_store: *RobotStore, config: *const Config) !Http { +pub fn init( + allocator: Allocator, + robot_store: *RobotStore, + web_bot_auth: *const ?WebBotAuth, + config: *const Config, +) !Http { try Net.globalInit(); errdefer Net.globalDeinit(); @@ -68,6 +75,7 @@ pub fn init(allocator: Allocator, robot_store: *RobotStore, config: *const Confi .config = config, .ca_blob = ca_blob, .robot_store = robot_store, + .web_bot_auth = web_bot_auth, }; } @@ -81,7 +89,7 @@ pub fn deinit(self: *Http) void { } pub fn createClient(self: *Http, allocator: Allocator) !*Client { - return Client.init(allocator, self.ca_blob, self.robot_store, self.config); + return Client.init(allocator, self.ca_blob, self.robot_store, self.web_bot_auth, self.config); } pub fn newConnection(self: *Http) !Net.Connection {