Merge pull request #813 from lightpanda-io/crypto_get_random_values_fix
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / puppeteer-perf (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled

Crypto.getRandomValues consistency
This commit is contained in:
Karl Seguin
2025-06-26 11:43:39 +08:00
committed by GitHub
2 changed files with 27 additions and 12 deletions

View File

@@ -17,19 +17,21 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std"); const std = @import("std");
const Env = @import("../env.zig").Env;
const uuidv4 = @import("../../id.zig").uuidv4; const uuidv4 = @import("../../id.zig").uuidv4;
// https://w3c.github.io/webcrypto/#crypto-interface // https://w3c.github.io/webcrypto/#crypto-interface
pub const Crypto = struct { pub const Crypto = struct {
_not_empty: bool = true, _not_empty: bool = true,
pub fn _getRandomValues(_: *const Crypto, into: RandomValues) !RandomValues { pub fn _getRandomValues(_: *const Crypto, js_obj: Env.JsObject) !Env.JsObject {
var into = try js_obj.toZig(Crypto, "getRandomValues", RandomValues);
const buf = into.asBuffer(); const buf = into.asBuffer();
if (buf.len > 65_536) { if (buf.len > 65_536) {
return error.QuotaExceededError; return error.QuotaExceededError;
} }
std.crypto.random.bytes(buf); std.crypto.random.bytes(buf);
return into; return js_obj;
} }
pub fn _randomUUID(_: *const Crypto) [36]u8 { pub fn _randomUUID(_: *const Crypto) [36]u8 {
@@ -50,16 +52,16 @@ const RandomValues = union(enum) {
uint64: []u64, uint64: []u64,
fn asBuffer(self: RandomValues) []u8 { fn asBuffer(self: RandomValues) []u8 {
switch (self) { return switch (self) {
.int8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len], .int8 => |b| (@as([]u8, @ptrCast(b)))[0..b.len],
.uint8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len], .uint8 => |b| (@as([]u8, @ptrCast(b)))[0..b.len],
.int16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2], .int16 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
.uint16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2], .uint16 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
.int32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4], .int32 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
.uint32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4], .uint32 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
.int64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8], .int64 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
.uint64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8], .uint64 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
} };
} }
}; };
@@ -84,4 +86,12 @@ test "Browser.Crypto" {
.{ "new Set(r2).size", "5" }, .{ "new Set(r2).size", "5" },
.{ "r1.every((v, i) => v === r2[i])", "true" }, .{ "r1.every((v, i) => v === r2[i])", "true" },
}, .{}); }, .{});
try runner.testCases(&.{
.{ "var r3 = new Uint8Array(16)", null },
.{ "let r4 = crypto.getRandomValues(r3)", "undefined" },
.{ "r4[6] = 10", null },
.{ "r4[6]", "10" },
.{ "r3[6]", "10" },
}, .{});
} }

View File

@@ -1603,6 +1603,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
const str = try self.js_obj.getConstructorName(); const str = try self.js_obj.getConstructorName();
return jsStringToZig(allocator, str, self.js_context.isolate); return jsStringToZig(allocator, str, self.js_context.isolate);
} }
pub fn toZig(self: JsObject, comptime Struct: type, comptime name: []const u8, comptime T: type) !T {
const named_function = comptime NamedFunction.init(Struct, name);
return self.js_context.jsValueToZig(named_function, T, self.js_obj.toValue());
}
}; };
// This only exists so that we know whether a function wants the opaque // This only exists so that we know whether a function wants the opaque