mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 23:23:28 +00:00
Merge pull request #593 from lightpanda-io/crypto_web_api
add crypto web api
This commit is contained in:
82
src/browser/crypto/crypto.zig
Normal file
82
src/browser/crypto/crypto.zig
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const uuidv4 = @import("../../id.zig").uuidv4;
|
||||||
|
|
||||||
|
// https://w3c.github.io/webcrypto/#crypto-interface
|
||||||
|
pub const Crypto = struct {
|
||||||
|
pub fn _getRandomValues(_: *const Crypto, into: RandomValues) !void {
|
||||||
|
const buf = into.asBuffer();
|
||||||
|
if (buf.len > 65_536) {
|
||||||
|
return error.QuotaExceededError;
|
||||||
|
}
|
||||||
|
std.crypto.random.bytes(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _randomUUID(_: *const Crypto) [36]u8 {
|
||||||
|
var hex: [36]u8 = undefined;
|
||||||
|
uuidv4(&hex);
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const RandomValues = union(enum) {
|
||||||
|
int8: []i8,
|
||||||
|
uint8: []u8,
|
||||||
|
int16: []i16,
|
||||||
|
uint16: []u16,
|
||||||
|
int32: []i32,
|
||||||
|
uint32: []u32,
|
||||||
|
int64: []i64,
|
||||||
|
uint64: []u64,
|
||||||
|
|
||||||
|
fn asBuffer(self: RandomValues) []u8 {
|
||||||
|
switch (self) {
|
||||||
|
.int8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len],
|
||||||
|
.uint8 => |b| return (@as([]u8, @ptrCast(b)))[0..b.len],
|
||||||
|
.int16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
|
||||||
|
.uint16 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 2],
|
||||||
|
.int32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
|
||||||
|
.uint32 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 4],
|
||||||
|
.int64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
|
||||||
|
.uint64 => |b| return (@as([]u8, @ptrCast(b)))[0 .. b.len * 8],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testing = @import("../../testing.zig");
|
||||||
|
test "Browser.Crypto" {
|
||||||
|
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
|
||||||
|
defer runner.deinit();
|
||||||
|
|
||||||
|
try runner.testCases(&.{
|
||||||
|
.{ "const a = crypto.randomUUID();", "undefined" },
|
||||||
|
.{ "const b = crypto.randomUUID();", "undefined" },
|
||||||
|
.{ "a.length;", "36" },
|
||||||
|
.{ "a.length;", "36" },
|
||||||
|
.{ "a == b;", "false" },
|
||||||
|
}, .{});
|
||||||
|
|
||||||
|
try runner.testCases(&.{
|
||||||
|
.{ "try { crypto.getRandomValues(new BigUint64Array(8193)) } catch(e) { e.message == 'QuotaExceededError' }", "true" },
|
||||||
|
.{ "let r1 = new Int32Array(5)", "undefined" },
|
||||||
|
.{ "crypto.getRandomValues(r1)", "undefined" },
|
||||||
|
.{ "new Set(r1).size", "5" },
|
||||||
|
}, .{});
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ const HttpClient = @import("../http/client.zig").Client;
|
|||||||
const Renderer = @import("browser.zig").Renderer;
|
const Renderer = @import("browser.zig").Renderer;
|
||||||
|
|
||||||
const Interfaces = generate.Tuple(.{
|
const Interfaces = generate.Tuple(.{
|
||||||
|
@import("crypto/crypto.zig").Crypto,
|
||||||
@import("console/console.zig").Console,
|
@import("console/console.zig").Console,
|
||||||
@import("dom/dom.zig").Interfaces,
|
@import("dom/dom.zig").Interfaces,
|
||||||
@import("events/event.zig").Interfaces,
|
@import("events/event.zig").Interfaces,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const SessionState = @import("../env.zig").SessionState;
|
|||||||
const Navigator = @import("navigator.zig").Navigator;
|
const Navigator = @import("navigator.zig").Navigator;
|
||||||
const History = @import("history.zig").History;
|
const History = @import("history.zig").History;
|
||||||
const Location = @import("location.zig").Location;
|
const Location = @import("location.zig").Location;
|
||||||
|
const Crypto = @import("../crypto/crypto.zig").Crypto;
|
||||||
const Console = @import("../console/console.zig").Console;
|
const Console = @import("../console/console.zig").Console;
|
||||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ pub const Window = struct {
|
|||||||
timeoutid: u32 = 0,
|
timeoutid: u32 = 0,
|
||||||
timeoutids: [512]u64 = undefined,
|
timeoutids: [512]u64 = undefined,
|
||||||
|
|
||||||
|
crypto: Crypto = .{},
|
||||||
console: Console = .{},
|
console: Console = .{},
|
||||||
navigator: Navigator = .{},
|
navigator: Navigator = .{},
|
||||||
|
|
||||||
@@ -91,6 +93,10 @@ pub const Window = struct {
|
|||||||
return &self.console;
|
return &self.console;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_crypto(self: *Window) *Crypto {
|
||||||
|
return &self.crypto;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_self(self: *Window) *Window {
|
pub fn get_self(self: *Window) *Window {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2532,9 +2532,14 @@ fn Caller(comptime E: type) type {
|
|||||||
|
|
||||||
// We settle for just probing the first value. Ok, actually
|
// We settle for just probing the first value. Ok, actually
|
||||||
// not tricky in this case either.
|
// not tricky in this case either.
|
||||||
const context = self.contxt;
|
const context = self.context;
|
||||||
const js_obj = js_arr.castTo(v8.Object);
|
const js_obj = js_arr.castTo(v8.Object);
|
||||||
return self.probeJsValueToZig(named_function, ptr.child, try js_obj.getAtIndex(context, 0));
|
switch (try self.probeJsValueToZig(named_function, ptr.child, try js_obj.getAtIndex(context, 0))) {
|
||||||
|
.value, .ok => return .{ .ok = {} },
|
||||||
|
.compatible => return .{ .compatible = {} },
|
||||||
|
.coerce => return .{ .coerce = {} },
|
||||||
|
.invalid => return .{ .invalid = {} },
|
||||||
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user