aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/webcore/response.zig11
-rw-r--r--src/cli/create_command.zig4
-rw-r--r--src/cli/upgrade_command.zig2
-rw-r--r--src/deps/uws.zig1
-rw-r--r--src/env_loader.zig7
-rw-r--r--src/http_client_async.zig54
-rw-r--r--src/install/install.zig6
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();
}