mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 23:23:28 +00:00
basic/bearer proxy authentication
This commit is contained in:
@@ -31,6 +31,7 @@ pub const App = struct {
|
|||||||
tls_verify_host: bool = true,
|
tls_verify_host: bool = true,
|
||||||
http_proxy: ?std.Uri = null,
|
http_proxy: ?std.Uri = null,
|
||||||
proxy_type: ?http.ProxyType = null,
|
proxy_type: ?http.ProxyType = null,
|
||||||
|
proxy_auth: ?http.ProxyAuth = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, config: Config) !*App {
|
pub fn init(allocator: Allocator, config: Config) !*App {
|
||||||
@@ -58,6 +59,7 @@ pub const App = struct {
|
|||||||
.max_concurrent = 3,
|
.max_concurrent = 3,
|
||||||
.http_proxy = config.http_proxy,
|
.http_proxy = config.http_proxy,
|
||||||
.proxy_type = config.proxy_type,
|
.proxy_type = config.proxy_type,
|
||||||
|
.proxy_auth = config.proxy_auth,
|
||||||
.tls_verify_host = config.tls_verify_host,
|
.tls_verify_host = config.tls_verify_host,
|
||||||
}),
|
}),
|
||||||
.config = config,
|
.config = config,
|
||||||
|
|||||||
@@ -46,6 +46,34 @@ pub const ProxyType = enum {
|
|||||||
connect,
|
connect,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ProxyAuth = union(enum) {
|
||||||
|
basic: struct { user_pass: []const u8 },
|
||||||
|
bearer: struct { token: []const u8 },
|
||||||
|
|
||||||
|
pub fn header_value(self: ProxyAuth, allocator: Allocator) ![]const u8 {
|
||||||
|
switch (self) {
|
||||||
|
.basic => |*auth| {
|
||||||
|
if (std.mem.indexOfScalar(u8, auth.user_pass, ':') == null) return error.InvalidProxyAuth;
|
||||||
|
|
||||||
|
const prefix = "Basic ";
|
||||||
|
var encoder = std.base64.standard.Encoder;
|
||||||
|
const size = encoder.calcSize(auth.user_pass.len);
|
||||||
|
var buffer = try allocator.alloc(u8, size + prefix.len);
|
||||||
|
std.mem.copyForwards(u8, buffer, prefix);
|
||||||
|
_ = std.base64.standard.Encoder.encode(buffer[prefix.len..], auth.user_pass);
|
||||||
|
return buffer;
|
||||||
|
},
|
||||||
|
.bearer => |*auth| {
|
||||||
|
const prefix = "Bearer ";
|
||||||
|
var buffer = try allocator.alloc(u8, auth.token.len + prefix.len);
|
||||||
|
std.mem.copyForwards(u8, buffer, prefix);
|
||||||
|
std.mem.copyForwards(u8, buffer[prefix.len..], auth.token);
|
||||||
|
return buffer;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Thread-safe. Holds our root certificate, connection pool and state pool
|
// Thread-safe. Holds our root certificate, connection pool and state pool
|
||||||
// Used to create Requests.
|
// Used to create Requests.
|
||||||
pub const Client = struct {
|
pub const Client = struct {
|
||||||
@@ -54,6 +82,7 @@ pub const Client = struct {
|
|||||||
state_pool: StatePool,
|
state_pool: StatePool,
|
||||||
http_proxy: ?Uri,
|
http_proxy: ?Uri,
|
||||||
proxy_type: ?ProxyType,
|
proxy_type: ?ProxyType,
|
||||||
|
proxy_auth: ?[]const u8, // Basic <user:pass; base64> or Bearer <token>
|
||||||
root_ca: tls.config.CertBundle,
|
root_ca: tls.config.CertBundle,
|
||||||
tls_verify_host: bool = true,
|
tls_verify_host: bool = true,
|
||||||
connection_manager: ConnectionManager,
|
connection_manager: ConnectionManager,
|
||||||
@@ -63,6 +92,7 @@ pub const Client = struct {
|
|||||||
max_concurrent: usize = 3,
|
max_concurrent: usize = 3,
|
||||||
http_proxy: ?std.Uri = null,
|
http_proxy: ?std.Uri = null,
|
||||||
proxy_type: ?ProxyType = null,
|
proxy_type: ?ProxyType = null,
|
||||||
|
proxy_auth: ?ProxyAuth = null,
|
||||||
tls_verify_host: bool = true,
|
tls_verify_host: bool = true,
|
||||||
max_idle_connection: usize = 10,
|
max_idle_connection: usize = 10,
|
||||||
};
|
};
|
||||||
@@ -71,10 +101,10 @@ pub const Client = struct {
|
|||||||
var root_ca: tls.config.CertBundle = if (builtin.is_test) .{} else try tls.config.CertBundle.fromSystem(allocator);
|
var root_ca: tls.config.CertBundle = if (builtin.is_test) .{} else try tls.config.CertBundle.fromSystem(allocator);
|
||||||
errdefer root_ca.deinit(allocator);
|
errdefer root_ca.deinit(allocator);
|
||||||
|
|
||||||
const state_pool = try StatePool.init(allocator, opts.max_concurrent);
|
var state_pool = try StatePool.init(allocator, opts.max_concurrent);
|
||||||
errdefer state_pool.deinit(allocator);
|
errdefer state_pool.deinit(allocator);
|
||||||
|
|
||||||
const connection_manager = ConnectionManager.init(allocator, opts.max_idle_connection);
|
var connection_manager = ConnectionManager.init(allocator, opts.max_idle_connection);
|
||||||
errdefer connection_manager.deinit();
|
errdefer connection_manager.deinit();
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@@ -84,6 +114,7 @@ pub const Client = struct {
|
|||||||
.state_pool = state_pool,
|
.state_pool = state_pool,
|
||||||
.http_proxy = opts.http_proxy,
|
.http_proxy = opts.http_proxy,
|
||||||
.proxy_type = if (opts.http_proxy == null) null else (opts.proxy_type orelse .connect),
|
.proxy_type = if (opts.http_proxy == null) null else (opts.proxy_type orelse .connect),
|
||||||
|
.proxy_auth = if (opts.proxy_auth) |*auth| try auth.header_value(allocator) else null,
|
||||||
.tls_verify_host = opts.tls_verify_host,
|
.tls_verify_host = opts.tls_verify_host,
|
||||||
.connection_manager = connection_manager,
|
.connection_manager = connection_manager,
|
||||||
.request_pool = std.heap.MemoryPool(Request).init(allocator),
|
.request_pool = std.heap.MemoryPool(Request).init(allocator),
|
||||||
@@ -98,6 +129,10 @@ pub const Client = struct {
|
|||||||
self.state_pool.deinit(allocator);
|
self.state_pool.deinit(allocator);
|
||||||
self.connection_manager.deinit();
|
self.connection_manager.deinit();
|
||||||
self.request_pool.deinit();
|
self.request_pool.deinit();
|
||||||
|
|
||||||
|
if (self.proxy_auth) |auth| {
|
||||||
|
allocator.free(auth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(self: *Client, method: Request.Method, uri: *const Uri) !*Request {
|
pub fn request(self: *Client, method: Request.Method, uri: *const Uri) !*Request {
|
||||||
@@ -763,6 +798,13 @@ pub const Request = struct {
|
|||||||
|
|
||||||
try self.headers.append(arena, .{ .name = "User-Agent", .value = "Lightpanda/1.0" });
|
try self.headers.append(arena, .{ .name = "User-Agent", .value = "Lightpanda/1.0" });
|
||||||
try self.headers.append(arena, .{ .name = "Accept", .value = "*/*" });
|
try self.headers.append(arena, .{ .name = "Accept", .value = "*/*" });
|
||||||
|
|
||||||
|
if (self._client.isSimpleProxy()) {
|
||||||
|
if (self._client.proxy_auth) |proxy_auth| {
|
||||||
|
try self.headers.append(arena, .{ .name = "Proxy-Authorization", .value = proxy_auth });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.requestStarting();
|
self.requestStarting();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,7 +929,13 @@ pub const Request = struct {
|
|||||||
var writer = fbs.writer();
|
var writer = fbs.writer();
|
||||||
|
|
||||||
try writer.print("CONNECT {s}:{d} HTTP/1.1\r\n", .{ self._request_host, self._request_port });
|
try writer.print("CONNECT {s}:{d} HTTP/1.1\r\n", .{ self._request_host, self._request_port });
|
||||||
try writer.print("Host: {s}:{d}\r\n\r\n", .{ self._request_host, self._request_port });
|
try writer.print("Host: {s}:{d}\r\n", .{ self._request_host, self._request_port });
|
||||||
|
|
||||||
|
if (self._client.proxy_auth) |proxy_auth| {
|
||||||
|
try writer.print("Proxy-Authorization: {s}\r\n", .{proxy_auth});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = try writer.write("\r\n");
|
||||||
return buf[0..fbs.pos];
|
return buf[0..fbs.pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/main.zig
42
src/main.zig
@@ -85,6 +85,7 @@ fn run(alloc: Allocator) !void {
|
|||||||
.run_mode = args.mode,
|
.run_mode = args.mode,
|
||||||
.http_proxy = args.httpProxy(),
|
.http_proxy = args.httpProxy(),
|
||||||
.proxy_type = args.proxyType(),
|
.proxy_type = args.proxyType(),
|
||||||
|
.proxy_auth = args.proxyAuth(),
|
||||||
.tls_verify_host = args.tlsVerifyHost(),
|
.tls_verify_host = args.tlsVerifyHost(),
|
||||||
});
|
});
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
@@ -164,6 +165,13 @@ const Command = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn proxyAuth(self: *const Command) ?http.ProxyAuth {
|
||||||
|
return switch (self.mode) {
|
||||||
|
inline .serve, .fetch => |opts| opts.common.proxy_auth,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn logLevel(self: *const Command) ?log.Level {
|
fn logLevel(self: *const Command) ?log.Level {
|
||||||
return switch (self.mode) {
|
return switch (self.mode) {
|
||||||
inline .serve, .fetch => |opts| opts.common.log_level,
|
inline .serve, .fetch => |opts| opts.common.log_level,
|
||||||
@@ -208,6 +216,7 @@ const Command = struct {
|
|||||||
const Common = struct {
|
const Common = struct {
|
||||||
http_proxy: ?std.Uri = null,
|
http_proxy: ?std.Uri = null,
|
||||||
proxy_type: ?http.ProxyType = null,
|
proxy_type: ?http.ProxyType = null,
|
||||||
|
proxy_auth: ?http.ProxyAuth = null,
|
||||||
tls_verify_host: bool = true,
|
tls_verify_host: bool = true,
|
||||||
log_level: ?log.Level = null,
|
log_level: ?log.Level = null,
|
||||||
log_format: ?log.Format = null,
|
log_format: ?log.Format = null,
|
||||||
@@ -233,6 +242,14 @@ const Command = struct {
|
|||||||
\\ and expects the proxy to MITM the request.
|
\\ and expects the proxy to MITM the request.
|
||||||
\\ Defaults to connect when --http_proxy is set.
|
\\ Defaults to connect when --http_proxy is set.
|
||||||
\\
|
\\
|
||||||
|
\\--proxy_bearer_token
|
||||||
|
\\ The token to send for bearer authentication with the proxy
|
||||||
|
\\ Proxy-Authorization: Bearer <token>
|
||||||
|
\\
|
||||||
|
\\--proxy_basic_auth
|
||||||
|
\\ The user:password to send for basic authentication with the proxy
|
||||||
|
\\ Proxy-Authorization: Basic <base64(user:password)>
|
||||||
|
\\
|
||||||
\\--log_level The log level: debug, info, warn, error or fatal.
|
\\--log_level The log level: debug, info, warn, error or fatal.
|
||||||
\\ Defaults to
|
\\ Defaults to
|
||||||
++ (if (builtin.mode == .Debug) " info." else "warn.") ++
|
++ (if (builtin.mode == .Debug) " info." else "warn.") ++
|
||||||
@@ -492,6 +509,31 @@ fn parseCommonArg(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, "--proxy_bearer_token", opt)) {
|
||||||
|
if (common.proxy_auth != null) {
|
||||||
|
log.fatal(.app, "proxy auth already set", .{ .arg = "--proxy_bearer_token" });
|
||||||
|
return error.InvalidArgument;
|
||||||
|
}
|
||||||
|
const str = args.next() orelse {
|
||||||
|
log.fatal(.app, "missing argument value", .{ .arg = "--proxy_bearer_token" });
|
||||||
|
return error.InvalidArgument;
|
||||||
|
};
|
||||||
|
common.proxy_auth = .{ .bearer = .{ .token = str } };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, "--proxy_basic_auth", opt)) {
|
||||||
|
if (common.proxy_auth != null) {
|
||||||
|
log.fatal(.app, "proxy auth already set", .{ .arg = "--proxy_basic_auth" });
|
||||||
|
return error.InvalidArgument;
|
||||||
|
}
|
||||||
|
const str = args.next() orelse {
|
||||||
|
log.fatal(.app, "missing argument value", .{ .arg = "--proxy_basic_auth" });
|
||||||
|
return error.InvalidArgument;
|
||||||
|
};
|
||||||
|
common.proxy_auth = .{ .basic = .{ .user_pass = str } };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, "--log_level", opt)) {
|
if (std.mem.eql(u8, "--log_level", opt)) {
|
||||||
const str = args.next() orelse {
|
const str = args.next() orelse {
|
||||||
log.fatal(.app, "missing argument value", .{ .arg = "--log_level" });
|
log.fatal(.app, "missing argument value", .{ .arg = "--log_level" });
|
||||||
|
|||||||
Reference in New Issue
Block a user