Skip to content

Commit 8d3a042

Browse files
committed
Crypto.getRandomValues consistency
Crypto.getRandomValues should mutate the given parameter as well as return the value. This return value must be the same (JsObject) as the input parameter. There might be more magical ways to solve this, but I opted for both the simplest and most flexible: adding a `toZig` function to JsObject which does what js.zig does internally when mapping js values to Zig (and, of course, it uses the same code). This allows a caller to receive a JsObject (not too common, but we already do that in a few places) and return that same JsObject (again, not too common, but we do have support for returning JsObject directly already). With the main addition that the JsObjet can now be turned into a Zig type by the caller.
1 parent 2815f02 commit 8d3a042

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed

src/browser/crypto/crypto.zig

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

1919
const std = @import("std");
20+
const Env = @import("../env.zig").Env;
2021
const uuidv4 = @import("../../id.zig").uuidv4;
2122

2223
// https://w3c.github.io/webcrypto/#crypto-interface
2324
pub const Crypto = struct {
24-
pub fn _getRandomValues(_: *const Crypto, into: RandomValues) !RandomValues {
25+
_not_empty: bool = true,
26+
27+
pub fn _getRandomValues(_: *const Crypto, js_obj: Env.JsObject) !Env.JsObject {
28+
var into = try js_obj.toZig(Crypto, "getRandomValues", RandomValues);
2529
const buf = into.asBuffer();
2630
if (buf.len > 65_536) {
2731
return error.QuotaExceededError;
2832
}
2933
std.crypto.random.bytes(buf);
30-
return into;
34+
return js_obj;
3135
}
3236

3337
pub fn _randomUUID(_: *const Crypto) [36]u8 {
@@ -48,16 +52,16 @@ const RandomValues = union(enum) {
4852
uint64: []u64,
4953

5054
fn asBuffer(self: RandomValues) []u8 {
51-
switch (self) {
52-
.int8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len],
53-
.uint8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len],
54-
.int16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
55-
.uint16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
56-
.int32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
57-
.uint32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
58-
.int64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
59-
.uint64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
60-
}
55+
return switch (self) {
56+
.int8 => |b| (@as([]u8, @ptrCast(b)))[0..b.len],
57+
.uint8 => |b| (@as([]u8, @ptrCast(b)))[0..b.len],
58+
.int16 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
59+
.uint16 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
60+
.int32 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
61+
.uint32 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
62+
.int64 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
63+
.uint64 => |b| (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
64+
};
6165
}
6266
};
6367

@@ -82,4 +86,12 @@ test "Browser.Crypto" {
8286
.{ "new Set(r2).size", "5" },
8387
.{ "r1.every((v, i) => v === r2[i])", "true" },
8488
}, .{});
89+
90+
try runner.testCases(&.{
91+
.{ "var r3 = new Uint8Array(16)", null },
92+
.{ "let r4 = crypto.getRandomValues(r3)", "undefined" },
93+
.{ "r4[6] = 10", null },
94+
.{ "r4[6]", "10" },
95+
.{ "r3[6]", "10" },
96+
}, .{});
8597
}

src/runtime/js.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
16011601
const str = try self.js_obj.getConstructorName();
16021602
return jsStringToZig(allocator, str, self.js_context.isolate);
16031603
}
1604+
1605+
pub fn toZig(self: JsObject, comptime Struct: type, comptime name: []const u8, comptime T: type) !T {
1606+
const named_function = comptime NamedFunction.init(Struct, name);
1607+
return self.js_context.jsValueToZig(named_function, T, self.js_obj.toValue());
1608+
}
16041609
};
16051610

16061611
// This only exists so that we know whether a function wants the opaque

0 commit comments

Comments
 (0)