diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/webcore/response.zig | 11 | ||||
-rw-r--r-- | src/cli/create_command.zig | 4 | ||||
-rw-r--r-- | src/cli/upgrade_command.zig | 2 | ||||
-rw-r--r-- | src/deps/uws.zig | 1 | ||||
-rw-r--r-- | src/env_loader.zig | 7 | ||||
-rw-r--r-- | src/http_client_async.zig | 54 | ||||
-rw-r--r-- | src/install/install.zig | 6 |
7 files changed, 83 insertions, 2 deletions
diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 8ad5442ae..3eb436e68 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -1504,6 +1504,7 @@ pub const Fetch = struct { fetch_tasklet.http.?.client.disable_keepalive = fetch_options.disable_keepalive; fetch_tasklet.http.?.client.disable_decompression = fetch_options.disable_decompression; fetch_tasklet.http.?.client.reject_unauthorized = fetch_options.reject_unauthorized; + fetch_tasklet.http.?.client.ca_store = fetch_options.ca_store; fetch_tasklet.http.?.client.tls_props = fetch_options.ssl_config; @@ -1556,6 +1557,7 @@ pub const Fetch = struct { memory_reporter: *JSC.MemoryReportingAllocator, check_server_identity: JSC.Strong = .{}, ssl_config: ?SSLConfig = null, + ca_store: bun.HTTP.HTTPCAStore = .{}, }; pub fn queue( @@ -1715,6 +1717,7 @@ pub const Fetch = struct { var url_proxy_buffer: []const u8 = undefined; var is_file_url = false; var reject_unauthorized = script_ctx.bundler.env.getTLSRejectUnauthorized(); + var ca_store = script_ctx.bundler.env.getTLSCAStore(); var check_server_identity: JSValue = .zero; // TODO: move this into a DRYer implementation // The status quo is very repetitive and very bug prone @@ -1880,6 +1883,9 @@ pub const Fetch = struct { check_server_identity = checkServerIdentity; } } + if (tls.get(ctx, "caStore")) |caStore| { + ca_store = bun.HTTP.HTTPCAStore.fromJS(globalThis, caStore); + } } } @@ -2089,6 +2095,10 @@ pub const Fetch = struct { check_server_identity = checkServerIdentity; } } + + if (tls.get(ctx, "caStore")) |caStore| { + ca_store = bun.HTTP.HTTPCAStore.fromJS(globalThis, caStore); + } } } @@ -2361,6 +2371,7 @@ pub const Fetch = struct { .hostname = hostname, .memory_reporter = memory_reporter, .check_server_identity = if (check_server_identity.isEmptyOrUndefinedOrNull()) .{} else JSC.Strong.create(check_server_identity, globalThis), + .ca_store = ca_store, }, // Pass the Strong value instead of creating a new one, or else we // will leak it diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig index b11a85b1e..5de433e24 100644 --- a/src/cli/create_command.zig +++ b/src/cli/create_command.zig @@ -1881,6 +1881,7 @@ pub const Example = struct { ); async_http.client.progress_node = progress; async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); const response = try async_http.sendSync(true); @@ -1959,6 +1960,7 @@ pub const Example = struct { ); async_http.client.progress_node = progress; async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); var response = try async_http.sendSync(true); @@ -2049,6 +2051,7 @@ pub const Example = struct { ); async_http.client.progress_node = progress; async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); refresher.maybeRefresh(); @@ -2091,6 +2094,7 @@ pub const Example = struct { HTTP.FetchRedirect.follow, ); async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); if (Output.enable_ansi_colors) { async_http.client.progress_node = progress_node; diff --git a/src/cli/upgrade_command.zig b/src/cli/upgrade_command.zig index d865d990d..78bab4500 100644 --- a/src/cli/upgrade_command.zig +++ b/src/cli/upgrade_command.zig @@ -244,6 +244,7 @@ pub const UpgradeCommand = struct { HTTP.FetchRedirect.follow, ); async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); if (!silent) async_http.client.progress_node = progress; const response = try async_http.sendSync(true); @@ -491,6 +492,7 @@ pub const UpgradeCommand = struct { async_http.client.timeout = timeout; async_http.client.progress_node = progress; async_http.client.reject_unauthorized = env_loader.getTLSRejectUnauthorized(); + async_http.client.ca_store = env_loader.getTLSCAStore(); const response = try async_http.sendSync(true); diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 8ca0f260b..0c05e811d 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -1025,6 +1025,7 @@ pub const us_bun_socket_context_options_t = extern struct { ca_file_name: [*c]const u8 = null, ssl_ciphers: [*c]const u8 = null, ssl_prefer_low_memory_usage: i32 = 0, + ca_store: u32 = 1, key: [*c][*c]const u8 = null, key_count: u32 = 0, cert: [*c][*c]const u8 = null, diff --git a/src/env_loader.zig b/src/env_loader.zig index f0bb91148..431e445c7 100644 --- a/src/env_loader.zig +++ b/src/env_loader.zig @@ -101,6 +101,13 @@ pub const Loader = struct { return true; } + pub fn getTLSCAStore(this: *Loader) bun.HTTP.HTTPCAStore { + if (this.map.get("BUN_TLS_CA_STORE")) |ca| { + return bun.HTTP.HTTPCAStore.parse(ca); + } + return bun.HTTP.HTTPCAStore{ .mozilla = true }; + } + pub fn getHttpProxy(this: *Loader, url: URL) ?URL { // TODO: When Web Worker support is added, make sure to intern these strings var http_proxy: ?URL = null; diff --git a/src/http_client_async.zig b/src/http_client_async.zig index 0a18297b6..8c6cd09ee 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -365,9 +365,14 @@ fn NewHTTPContext(comptime ssl: bool) type { unreachable; } - var opts = client.tls_props.?.asUSockets(); + var opts: uws.us_bun_socket_context_options_t = .{}; + if (client.tls_props != null) { + opts = client.tls_props.?.asUSockets(); + } opts.request_cert = 1; opts.reject_unauthorized = 0; + opts.ca_store = client.ca_store.raw(); + var socket = uws.us_create_bun_socket_context(ssl_int, http_thread.loop, @sizeOf(usize), opts); if (socket == null) { return error.FailedToOpenSocket; @@ -767,7 +772,7 @@ pub const HTTPThread = struct { pub fn connect(this: *@This(), client: *HTTPClient, comptime is_ssl: bool) !NewHTTPContext(is_ssl).HTTPSocket { if (comptime is_ssl) { const needs_own_context = client.tls_props != null and client.tls_props.?.requires_custom_request_ctx; - if (needs_own_context) { + if (needs_own_context or client.ca_store.raw() != 1) { var custom_context = try bun.default_allocator.create(NewHTTPContext(is_ssl)); client.custom_context = custom_context; try custom_context.initWithClientConfig(client); @@ -1557,6 +1562,7 @@ signals: Signals = .{}, async_http_id: u32 = 0, hostname: ?[]u8 = null, reject_unauthorized: bool = true, +ca_store: HTTPCAStore = .{}, custom_context: ?*NewHTTPContext(true) = null, pub fn init( @@ -1720,6 +1726,50 @@ pub const HTTPChannelContext = struct { } }; +pub const HTTPCAStore = packed struct(u32) { + mozilla: bool = true, + system: bool = false, + + _padding: u30 = 0, + + pub fn raw(this: HTTPCAStore) u32 { + return @bitCast(this); + } + + pub fn parse(s: []const u8) HTTPCAStore { + var store = HTTPCAStore{ .mozilla = false, .system = false }; + + if (std.mem.eql(u8, s, "none")) return store; + + var split = std.mem.split(u8, s, ","); + while (split.next()) |value| { + if (std.mem.eql(u8, value, "mozilla")) store.mozilla = true; + if (std.mem.eql(u8, value, "system")) store.system = true; + } + + return store; + } + + pub fn fromJS(global: *JSC.JSGlobalObject, obj: JSC.JSValue) HTTPCAStore { + if (obj.isNumber()) { + return @bitCast(obj.to(u32)); + } else if (obj.jsTypeLoose().isArray()) { + var store = HTTPCAStore{ .mozilla = false, .system = false }; + var iter = obj.arrayIterator(global); + while (iter.next()) |value| { + if (bun.String.tryFromJS(value, global)) |str| { + store = @bitCast(store.raw() | HTTPCAStore.parse(str.byteSlice()).raw()); + } + } + return store; + } else if (bun.String.tryFromJS(obj, global)) |str| { + return HTTPCAStore.parse(str.byteSlice()); + } else { + return .{}; + } + } +}; + pub const AsyncHTTP = struct { request: ?picohttp.Request = null, response: ?picohttp.Response = null, diff --git a/src/install/install.zig b/src/install/install.zig index 17c5bc4ee..38c0de64e 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -372,6 +372,7 @@ const NetworkTask = struct { null, ); this.http.client.reject_unauthorized = this.package_manager.tlsRejectUnauthorized(); + this.http.client.ca_store = this.package_manager.tlsCAStore(); if (PackageManager.verbose_install) { this.http.client.verbose = true; @@ -456,6 +457,7 @@ const NetworkTask = struct { null, ); this.http.client.reject_unauthorized = this.package_manager.tlsRejectUnauthorized(); + this.http.client.ca_store = this.package_manager.tlsCAStore(); if (PackageManager.verbose_install) { this.http.client.verbose = true; } @@ -1742,6 +1744,10 @@ pub const PackageManager = struct { return this.env.getTLSRejectUnauthorized(); } + pub fn tlsCAStore(this: *PackageManager) HTTP.HTTPCAStore { + return this.env.getTLSCAStore(); + } + pub fn computeIsContinuousIntegration(this: *PackageManager) bool { return this.env.isCI(); } |