diff options
author | 2022-12-29 05:53:12 -0800 | |
---|---|---|
committer | 2022-12-29 06:05:43 -0800 | |
commit | 85eda2058755261bf5ac64a3d82112d7bad5419c (patch) | |
tree | 924056e03bab81bf3d991fceaa2bee1b97b8181b | |
parent | 940ecd05a8a3a1f0326256148a93306b71936c1e (diff) | |
download | bun-85eda2058755261bf5ac64a3d82112d7bad5419c.tar.gz bun-85eda2058755261bf5ac64a3d82112d7bad5419c.tar.zst bun-85eda2058755261bf5ac64a3d82112d7bad5419c.zip |
Introduce `Bun.CryptoHasher`
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | bench/snippets/crypto-hasher.mjs | 30 | ||||
-rw-r--r-- | packages/bun-types/bun.d.ts | 100 | ||||
-rw-r--r-- | src/bun.js/api/bun.zig | 439 | ||||
-rw-r--r-- | src/bun.js/api/crypto.classes.ts | 40 | ||||
-rw-r--r-- | src/bun.js/base.zig | 72 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h | 12 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 243 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.h | 27 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 70 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 120 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes_list.zig | 2 | ||||
-rw-r--r-- | src/bun.js/node/types.zig | 106 | ||||
-rw-r--r-- | src/bun.js/webcore/encoding.zig | 3 | ||||
-rw-r--r-- | src/deps/boringssl.translated.zig | 17 | ||||
-rw-r--r-- | test/bun.js/crypto.test.js | 47 |
19 files changed, 1142 insertions, 206 deletions
@@ -416,9 +416,9 @@ MINIMUM_ARCHIVE_FILES = -L$(BUN_DEPS_OUT_DIR) \ -lz \ $(BUN_DEPS_OUT_DIR)/picohttpparser.o \ $(_MIMALLOC_LINK) \ + -ldecrepit \ -lssl \ -lcrypto \ - -ldecrepit \ -llolhtml ARCHIVE_FILES_WITHOUT_LIBCRYPTO = $(MINIMUM_ARCHIVE_FILES) \ diff --git a/bench/snippets/crypto-hasher.mjs b/bench/snippets/crypto-hasher.mjs new file mode 100644 index 000000000..1e850e19f --- /dev/null +++ b/bench/snippets/crypto-hasher.mjs @@ -0,0 +1,30 @@ +// so it can run in environments without node module resolution +import { bench, run } from "mitata"; + +import crypto from "node:crypto"; + +var foo = new Uint8Array(65536); +crypto.getRandomValues(foo); + +// if ("Bun" in globalThis) { +// const { CryptoHasher } = Bun; +// bench("CryptoHasher Blake2b256", () => { +// var hasher = new CryptoHasher("blake2b256"); +// hasher.update(foo); +// hasher.digest(); +// }); +// } + +bench('crypto.createHash("sha512")', () => { + var hasher = crypto.createHash("sha512"); + hasher.update(foo); + hasher.digest(); +}); + +bench('crypto.createHash("sha512")', () => { + var hasher = crypto.createHash("sha512"); + hasher.update(foo); + hasher.digest(); +}); + +await run(); diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 2d93cf8a8..1a23d7326 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1,3 +1,5 @@ +import { Encoding } from "crypto"; + interface VoidFunction { (): void; } @@ -1924,6 +1926,96 @@ declare module "bun" { static hash(input: StringOrBuffer, encoding: DigestEncoding): string; } + type SupportedCryptoAlgorithms = + | "blake2b256" + | "md4" + | "md5" + | "ripemd160" + | "sha1" + | "sha224" + | "sha256" + | "sha384" + | "sha512" + | "sha512-256"; + /** + * Hardware-accelerated cryptographic hash functions + * + * Used for `crypto.createHash()` + */ + export class CryptoHasher { + /** + * The algorithm chosen to hash the data + * + */ + readonly algorithm: SupportedCryptoAlgorithms; + + /** + * The length of the output hash in bytes + */ + readonly byteLength: number; + + /** + * Create a new hasher + * + * @param algorithm The algorithm to use. See {@link algorithms} for a list of supported algorithms + */ + constructor(algorithm: SupportedCryptoAlgorithms); + + /** + * Update the hash with data + * + * @param input + */ + update(input: StringOrBuffer, inputEncoding?: Encoding): CryptoHasher; + + /** + * Finalize the hash + * + * @param encoding `DigestEncoding` to return the hash in. If none is provided, it will return a `Uint8Array`. + */ + digest(encoding: DigestEncoding): string; + + /** + * Finalize the hash + * + * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time + */ + digest(hashInto?: TypedArray): TypedArray; + + /** + * Run the hash over the given data + * + * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. + * + * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time + */ + static hash( + algorithm: SupportedCryptoAlgorithms, + input: StringOrBuffer, + hashInto?: TypedArray, + ): TypedArray; + + /** + * Run the hash over the given data + * + * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. + * + * @param encoding `DigestEncoding` to return the hash in + */ + static hash( + algorithm: SupportedCryptoAlgorithms, + input: StringOrBuffer, + encoding: DigestEncoding, + ): string; + + /** + * List of supported hash algorithms + * + * These are hardware accelerated with BoringSSL + */ + static readonly algorithms: SupportedCryptoAlgorithms[]; + } + /** * Sleep the thread for a given number of milliseconds * @@ -2045,14 +2137,6 @@ declare module "bun" { */ static readonly byteLength: 32; } - export class RIPEMD160 extends CryptoHashInterface<RIPEMD160> { - constructor(); - - /** - * The number of bytes the hash will produce - */ - static readonly byteLength: 20; - } /** Compression options for `Bun.deflateSync` and `Bun.gzipSync` */ export type ZlibCompressionOptions = { diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index fc66098a4..31d536000 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1279,12 +1279,12 @@ pub const Class = NewClass( .SHA256 = .{ .get = Crypto.SHA256.getter, }, - .RIPEMD160 = .{ - .get = Crypto.RIPEMD160.getter, - }, .SHA512_256 = .{ .get = Crypto.SHA512_256.getter, }, + .CryptoHasher = .{ + .get = Crypto.CryptoHasher.getter, + }, .FFI = .{ .get = FFI.getter, }, @@ -1366,7 +1366,415 @@ pub fn indexOfLine( pub const Crypto = struct { const Hashers = @import("../../sha.zig"); - fn CryptoHasher(comptime Hasher: type, comptime name: [:0]const u8) type { + const BoringSSL = bun.BoringSSL; + const EVP = struct { + ctx: BoringSSL.EVP_MD_CTX = undefined, + md: *const BoringSSL.EVP_MD = undefined, + algorithm: Algorithm, + + // we do this to avoid asking BoringSSL what the digest name is + // because that API is confusing + pub const Algorithm = enum { + // @"DSA-SHA", + // @"DSA-SHA1", + // @"MD5-SHA1", + // @"RSA-MD5", + // @"RSA-RIPEMD160", + // @"RSA-SHA1", + // @"RSA-SHA1-2", + // @"RSA-SHA224", + // @"RSA-SHA256", + // @"RSA-SHA384", + // @"RSA-SHA512", + // @"ecdsa-with-SHA1", + blake2b256, + md4, + md5, + ripemd160, + sha1, + sha224, + sha256, + sha384, + sha512, + @"sha512-256", + + pub const names: std.EnumArray(Algorithm, ZigString) = brk: { + var all = std.EnumArray(Algorithm, ZigString).initUndefined(); + var iter = all.iterator(); + while (iter.next()) |entry| { + entry.value.* = ZigString.init(std.mem.span(@tagName(entry.key))); + } + break :brk all; + }; + + pub const map = bun.ComptimeStringMap(Algorithm, .{ + .{ "blake2b256", .blake2b256 }, + .{ "ripemd160", .ripemd160 }, + .{ "rmd160", .ripemd160 }, + .{ "md4", .md4 }, + .{ "md5", .md5 }, + .{ "sha1", .sha1 }, + .{ "sha128", .sha1 }, + .{ "sha224", .sha224 }, + .{ "sha256", .sha256 }, + .{ "sha384", .sha384 }, + .{ "sha512", .sha512 }, + .{ "sha-1", .sha1 }, + .{ "sha-224", .sha224 }, + .{ "sha-256", .sha256 }, + .{ "sha-384", .sha384 }, + .{ "sha-512", .sha512 }, + .{ "sha-512/256", .@"sha512-256" }, + .{ "sha-512_256", .@"sha512-256" }, + .{ "sha-512256", .@"sha512-256" }, + .{ "sha512-256", .@"sha512-256" }, + .{ "sha384", .sha384 }, + // .{ "md5-sha1", .@"MD5-SHA1" }, + // .{ "dsa-sha", .@"DSA-SHA" }, + // .{ "dsa-sha1", .@"DSA-SHA1" }, + // .{ "ecdsa-with-sha1", .@"ecdsa-with-SHA1" }, + // .{ "rsa-md5", .@"RSA-MD5" }, + // .{ "rsa-sha1", .@"RSA-SHA1" }, + // .{ "rsa-sha1-2", .@"RSA-SHA1-2" }, + // .{ "rsa-sha224", .@"RSA-SHA224" }, + // .{ "rsa-sha256", .@"RSA-SHA256" }, + // .{ "rsa-sha384", .@"RSA-SHA384" }, + // .{ "rsa-sha512", .@"RSA-SHA512" }, + // .{ "rsa-ripemd160", .@"RSA-RIPEMD160" }, + }); + }; + + pub const Digest = [BoringSSL.EVP_MAX_MD_SIZE]u8; + + pub fn init(algorithm: Algorithm, md: *const BoringSSL.EVP_MD, engine: *BoringSSL.ENGINE) EVP { + var ctx: BoringSSL.EVP_MD_CTX = undefined; + BoringSSL.EVP_MD_CTX_init(&ctx); + _ = BoringSSL.EVP_DigestInit_ex(&ctx, md, engine); + + return .{ + .ctx = ctx, + .md = md, + .algorithm = algorithm, + }; + } + + pub fn hash(this: *EVP, engine: *BoringSSL.ENGINE, input: []const u8, output: []u8) ?u32 { + var outsize: c_uint = @min(@truncate(u16, output.len), this.size()); + if (BoringSSL.EVP_Digest(input.ptr, input.len, output.ptr, &outsize, this.md, engine) != 1) { + return null; + } + + return outsize; + } + + pub fn final(this: *EVP, output: []u8) []const u8 { + var outsize: u32 = @min(@truncate(u16, output.len), this.size()); + if (BoringSSL.EVP_DigestFinal_ex( + &this.ctx, + output.ptr, + &outsize, + ) != 1) { + return ""; + } + + return output[0..outsize]; + } + + pub fn update(this: *EVP, input: []const u8) void { + _ = BoringSSL.EVP_DigestUpdate(&this.ctx, input.ptr, input.len); + } + + pub fn size(this: *EVP) u16 { + return @truncate(u16, BoringSSL.EVP_MD_CTX_size(&this.ctx)); + } + + pub fn byNameAndEngine(engine: *BoringSSL.ENGINE, name: []const u8) ?EVP { + + // none of the names are longer than 255 + var buf: [256]u8 = undefined; + const len = @min(name.len, buf.len - 1); + _ = strings.copyLowercase(name, &buf); + + if (Algorithm.map.get(buf[0..len])) |algorithm| { + if (algorithm == .blake2b256) { + return EVP.init(algorithm, BoringSSL.EVP_blake2b256(), engine); + } + + if (BoringSSL.EVP_get_digestbyname(@tagName(algorithm))) |md| { + return EVP.init(algorithm, md, engine); + } + } + + return null; + } + + pub fn byName(name: ZigString, global: *JSC.JSGlobalObject) ?EVP { + var name_str = name.toSlice(global.allocator()); + defer name_str.deinit(); + return byNameAndEngine(global.bunVM().rareData().boringEngine(), name_str.slice()); + } + }; + + fn createCryptoError(globalThis: *JSC.JSGlobalObject, err_code: u32) JSValue { + var outbuf: [128 + 1 + "BoringSSL error: ".len]u8 = undefined; + @memset(&outbuf, 0, outbuf.len); + outbuf[0.."BoringSSL error: ".len].* = "BoringSSL error: ".*; + var message_buf = outbuf["BoringSSL error: ".len..]; + + _ = BoringSSL.ERR_error_string_n(err_code, message_buf, message_buf.len); + + const error_message: []const u8 = bun.span(std.meta.assumeSentinel(&outbuf, 0)); + if (error_message.len == "BoringSSL error: ".len) { + return ZigString.static("Unknown BoringSSL error").toErrorInstance(globalThis); + } + + return ZigString.fromUTF8(error_message).toErrorInstance(globalThis); + } + pub const CryptoHasher = struct { + evp: EVP = undefined, + + const Digest = EVP.Digest; + + pub usingnamespace JSC.Codegen.JSCryptoHasher; + + pub const digest = JSC.wrapInstanceMethod(CryptoHasher, "digest_", false); + pub const hash = JSC.wrapStaticMethod(CryptoHasher, "hash_", false); + + pub fn getByteLength( + this: *CryptoHasher, + _: *JSC.JSGlobalObject, + ) callconv(.C) JSC.JSValue { + return JSC.JSValue.jsNumber(@truncate(u16, this.evp.size())); + } + + pub fn getAlgorithm( + this: *CryptoHasher, + globalObject: *JSC.JSGlobalObject, + ) callconv(.C) JSC.JSValue { + return ZigString.fromUTF8(std.mem.span(@tagName(this.evp.algorithm))).toValueGC(globalObject); + } + + pub fn getAlgorithms( + globalThis_: *JSC.JSGlobalObject, + _: JSValue, + _: JSValue, + ) callconv(.C) JSC.JSValue { + var values = EVP.Algorithm.names.values; + return JSC.JSValue.createStringArray(globalThis_, &values, values.len, true); + } + + fn hashToEncoding( + globalThis: *JSGlobalObject, + evp: *EVP, + input: JSC.Node.StringOrBuffer, + encoding: JSC.Node.Encoding, + ) JSC.JSValue { + var output_digest_buf: Digest = undefined; + + const len = evp.hash(globalThis.bunVM().rareData().boringEngine(), input.slice(), &output_digest_buf) orelse { + const err = BoringSSL.ERR_get_error(); + const instance = createCryptoError(globalThis, err); + BoringSSL.ERR_clear_error(); + globalThis.throwValue(instance); + return .zero; + }; + return encoding.encodeWithMaxSize(globalThis, len, BoringSSL.EVP_MAX_MD_SIZE, &output_digest_buf); + } + + fn hashToBytes( + globalThis: *JSGlobalObject, + evp: *EVP, + input: JSC.Node.StringOrBuffer, + output: ?JSC.ArrayBuffer, + ) JSC.JSValue { + var output_digest_buf: Digest = undefined; + var output_digest_slice: []u8 = &output_digest_buf; + if (output) |output_buf| { + const size = evp.size(); + var bytes = output_buf.byteSlice(); + if (bytes.len < size) { + globalThis.throwInvalidArguments("TypedArray must be at least {d} bytes", .{size}); + return JSC.JSValue.zero; + } + output_digest_slice = bytes[0..size]; + } + + const len = evp.hash(globalThis.bunVM().rareData().boringEngine(), input.slice(), output_digest_slice) orelse { + const err = BoringSSL.ERR_get_error(); + const instance = createCryptoError(globalThis, err); + BoringSSL.ERR_clear_error(); + globalThis.throwValue(instance); + return .zero; + }; + + if (output) |output_buf| { + return output_buf.value; + } else { + var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, output_digest_slice[0..len]) catch unreachable, .Uint8Array); + return array_buffer_out.toJSUnchecked(globalThis, null); + } + } + + pub fn hash_( + globalThis: *JSGlobalObject, + algorithm: ZigString, + input: JSC.Node.StringOrBuffer, + output: ?JSC.Node.StringOrBuffer, + ) JSC.JSValue { + var evp = EVP.byName(algorithm, globalThis) orelse { + globalThis.throwInvalidArguments("Unsupported algorithm \"{any}\"", .{algorithm}); + return .zero; + }; + + if (output) |string_or_buffer| { + switch (string_or_buffer) { + .string => |str| { + const encoding = JSC.Node.Encoding.from(str) orelse { + globalThis.throwInvalidArguments("Unknown encoding: {s}", .{str}); + return JSC.JSValue.zero; + }; + + return hashToEncoding(globalThis, &evp, input, encoding); + }, + .buffer => |buffer| { + return hashToBytes(globalThis, &evp, input, buffer.buffer); + }, + } + } else { + return hashToBytes(globalThis, &evp, input, null); + } + } + + pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) ?*CryptoHasher { + var arguments = callframe.arguments(2); + if (arguments.len == 0) { + globalThis.throwInvalidArguments("Expected an algorithm name as an argument", .{}); + return null; + } + + const algorithm_name = arguments.ptr[0]; + if (algorithm_name.isEmptyOrUndefinedOrNull() or !algorithm_name.isString()) { + globalThis.throwInvalidArguments("algorithm must be a string", .{}); + return null; + } + + const algorithm = algorithm_name.getZigString(globalThis); + + if (algorithm.len == 0) { + globalThis.throwInvalidArguments("Invalid algorithm name", .{}); + return null; + } + + const evp = EVP.byName(algorithm, globalThis) orelse { + globalThis.throwInvalidArguments("Unsupported algorithm {any}", .{algorithm}); + return null; + }; + var this = bun.default_allocator.create(CryptoHasher) catch return null; + this.evp = evp; + return this; + } + + pub fn getter( + _: void, + ctx: js.JSContextRef, + _: js.JSValueRef, + _: js.JSStringRef, + _: js.ExceptionRef, + ) js.JSValueRef { + return CryptoHasher.getConstructor(ctx).asObjectRef(); + } + + pub fn update(this: *CryptoHasher, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callframe.this(); + const arguments = callframe.arguments(2); + const input = arguments.ptr[0]; + const encoding = arguments.ptr[1]; + const buffer = JSC.Node.SliceOrBuffer.fromJSWithEncoding(globalThis.ptr(), globalThis.bunVM().allocator, input, encoding) orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + return JSC.JSValue.zero; + }; + + defer buffer.deinit(); + + this.evp.update(buffer.slice()); + const err = BoringSSL.ERR_get_error(); + if (err != 0) { + const instance = createCryptoError(globalThis, err); + BoringSSL.ERR_clear_error(); + globalThis.throwValue(instance); + return .zero; + } + + return thisValue; + } + + pub fn digest_( + this: *@This(), + globalThis: *JSGlobalObject, + output: ?JSC.Node.StringOrBuffer, + ) JSC.JSValue { + if (output) |string_or_buffer| { + switch (string_or_buffer) { + .string => |str| { + const encoding = JSC.Node.Encoding.from(str) orelse { + globalThis.throwInvalidArguments("Unknown encoding: {s}", .{str}); + return JSC.JSValue.zero; + }; + + return this.digestToEncoding(globalThis, encoding); + }, + .buffer => |buffer| { + return this.digestToBytes( + globalThis, + buffer.buffer, + ); + }, + } + } else { + return this.digestToBytes(globalThis, null); + } + } + + fn digestToBytes(this: *CryptoHasher, globalThis: *JSGlobalObject, output: ?JSC.ArrayBuffer) JSC.JSValue { + var output_digest_buf: EVP.Digest = undefined; + var output_digest_slice: []u8 = &output_digest_buf; + if (output) |output_buf| { + var bytes = output_buf.byteSlice(); + if (bytes.len < output_digest_buf.len) { + globalThis.throwInvalidArguments(comptime std.fmt.comptimePrint("TypedArray must be at least {d} bytes", .{output_digest_buf.len}), .{}); + return JSC.JSValue.zero; + } + output_digest_slice = bytes[0..bytes.len]; + } else { + output_digest_buf = std.mem.zeroes(EVP.Digest); + } + + const result = this.evp.final(output_digest_slice); + + if (output) |output_buf| { + return output_buf.value; + } else { + var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, result) catch unreachable, .Uint8Array); + return array_buffer_out.toJSUnchecked(globalThis, null); + } + } + + fn digestToEncoding(this: *CryptoHasher, globalThis: *JSGlobalObject, encoding: JSC.Node.Encoding) JSC.JSValue { + var output_digest_buf: EVP.Digest = std.mem.zeroes(EVP.Digest); + + var output_digest_slice: []u8 = &output_digest_buf; + + const out = this.evp.final(output_digest_slice); + + return encoding.encodeWithMaxSize(globalThis, out.len, BoringSSL.EVP_MAX_MD_SIZE, out); + } + + pub fn finalize(this: *CryptoHasher) callconv(.C) void { + VirtualMachine.get().allocator.destroy(this); + } + }; + + fn StaticCryptoHasher(comptime Hasher: type, comptime name: [:0]const u8) type { return struct { hashing: Hasher = Hasher{}, @@ -1494,13 +1902,13 @@ pub const Crypto = struct { pub fn digest_( this: *@This(), globalThis: *JSGlobalObject, - output: ?JSC.Node.StringOrBuffer, + output: ?JSC.Node.SliceOrBuffer, ) JSC.JSValue { if (output) |string_or_buffer| { switch (string_or_buffer) { .string => |str| { - const encoding = JSC.Node.Encoding.from(str) orelse { - globalThis.throwInvalidArguments("Unknown encoding: {s}", .{str}); + const encoding = JSC.Node.Encoding.from(str.slice()) orelse { + globalThis.throwInvalidArguments("Unknown encoding: \"{s}\"", .{str.slice()}); return JSC.JSValue.zero; }; @@ -1574,15 +1982,14 @@ pub const Crypto = struct { }; } - pub const SHA1 = CryptoHasher(Hashers.SHA1, "SHA1"); - pub const MD5 = CryptoHasher(Hashers.MD5, "MD5"); - pub const MD4 = CryptoHasher(Hashers.MD4, "MD4"); - pub const SHA224 = CryptoHasher(Hashers.SHA224, "SHA224"); - pub const SHA512 = CryptoHasher(Hashers.SHA512, "SHA512"); - pub const SHA384 = CryptoHasher(Hashers.SHA384, "SHA384"); - pub const SHA256 = CryptoHasher(Hashers.SHA256, "SHA256"); - pub const SHA512_256 = CryptoHasher(Hashers.SHA512_256, "SHA512_256"); - pub const RIPEMD160 = CryptoHasher(Hashers.Hashers.RIPEMD160, "RIPEMD160"); + pub const SHA1 = StaticCryptoHasher(Hashers.SHA1, "SHA1"); + pub const MD5 = StaticCryptoHasher(Hashers.MD5, "MD5"); + pub const MD4 = StaticCryptoHasher(Hashers.MD4, "MD4"); + pub const SHA224 = StaticCryptoHasher(Hashers.SHA224, "SHA224"); + pub const SHA512 = StaticCryptoHasher(Hashers.SHA512, "SHA512"); + pub const SHA384 = StaticCryptoHasher(Hashers.SHA384, "SHA384"); + pub const SHA256 = StaticCryptoHasher(Hashers.SHA256, "SHA256"); + pub const SHA512_256 = StaticCryptoHasher(Hashers.SHA512_256, "SHA512_256"); }; pub fn nanoseconds( diff --git a/src/bun.js/api/crypto.classes.ts b/src/bun.js/api/crypto.classes.ts index 8ddd11caf..b3852157a 100644 --- a/src/bun.js/api/crypto.classes.ts +++ b/src/bun.js/api/crypto.classes.ts @@ -9,9 +9,8 @@ const names = [ "SHA384", "SHA256", "SHA512_256", - "RIPEMD160", ]; -export default names.map((name) => { +const named = names.map((name) => { return define({ name: name, construct: true, @@ -41,3 +40,40 @@ export default names.map((name) => { }, }); }); + +export default [ + ...named, + define({ + name: "CryptoHasher", + construct: true, + finalize: true, + klass: { + hash: { + fn: "hash", + length: 2, + }, + algorithms: { + getter: "getAlgorithms", + cache: true, + }, + }, + JSType: "0b11101110", + proto: { + digest: { + fn: "digest", + length: 0, + }, + algorithm: { + getter: "getAlgorithm", + cache: true, + }, + update: { + fn: "update", + length: 2, + }, + byteLength: { + getter: "getByteLength", + }, + }, + }), +]; diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 79f1fe46a..427def275 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -2669,11 +2669,30 @@ pub fn wrapWithHasContainer( }, ?JSC.Node.StringOrBuffer => { if (iter.nextEat()) |arg| { - args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse { - exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef(); - iter.deinit(); - return null; - }; + if (!arg.isEmptyOrUndefinedOrNull()) { + args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse { + exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef(); + iter.deinit(); + return null; + }; + } else { + args[i] = null; + } + } else { + args[i] = null; + } + }, + ?JSC.Node.SliceOrBuffer => { + if (iter.nextEat()) |arg| { + if (!arg.isEmptyOrUndefinedOrNull()) { + args[i] = JSC.Node.SliceOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse { + exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef(); + iter.deinit(); + return null; + }; + } else { + args[i] = null; + } } else { args[i] = null; } @@ -2693,11 +2712,15 @@ pub fn wrapWithHasContainer( }, ?JSC.ArrayBuffer => { if (iter.nextEat()) |arg| { - args[i] = arg.asArrayBuffer(ctx.ptr()) orelse { - exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef(); - iter.deinit(); - return null; - }; + if (!arg.isEmptyOrUndefinedOrNull()) { + args[i] = arg.asArrayBuffer(ctx.ptr()) orelse { + exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef(); + iter.deinit(); + return null; + }; + } else { + args[i] = null; + } } else { args[i] = null; } @@ -2855,11 +2878,30 @@ pub fn wrapInstanceMethod( }, ?JSC.Node.StringOrBuffer => { if (iter.nextEat()) |arg| { - args[i] = JSC.Node.StringOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg, null) orelse { - globalThis.throwInvalidArguments("expected string or buffer", .{}); - iter.deinit(); - return JSC.JSValue.zero; - }; + if (!arg.isEmptyOrUndefinedOrNull()) { + args[i] = JSC.Node.StringOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg, null) orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + iter.deinit(); + return JSC.JSValue.zero; + }; + } else { + args[i] = null; + } + } else { + args[i] = null; + } + }, + ?JSC.Node.SliceOrBuffer => { + if (iter.nextEat()) |arg| { + if (!arg.isEmptyOrUndefinedOrNull()) { + args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + iter.deinit(); + return JSC.JSValue.zero; + }; + } else { + args[i] = null; + } } else { args[i] = null; } diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h index 484ae9c48..f74d54b02 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h @@ -10,8 +10,8 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA224Constructor;std: std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA384; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA384Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256; -std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRIPEMD160; -std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRIPEMD160Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocket; +std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCryptoHasher; +std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCryptoHasherConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocket; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemRouter; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemRouterConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMatchedRoute; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpect; diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h index ebbb2f7b7..cda555fa9 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h @@ -10,8 +10,8 @@ std::unique_ptr<IsoSubspace> m_subspaceForSHA224Constructor;std::unique_ptr<IsoS std::unique_ptr<IsoSubspace> m_subspaceForSHA512Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA384; std::unique_ptr<IsoSubspace> m_subspaceForSHA384Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA256; std::unique_ptr<IsoSubspace> m_subspaceForSHA256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256; -std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForRIPEMD160; -std::unique_ptr<IsoSubspace> m_subspaceForRIPEMD160Constructor;std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocket; +std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForCryptoHasher; +std::unique_ptr<IsoSubspace> m_subspaceForCryptoHasherConstructor;std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocket; std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForFileSystemRouter; std::unique_ptr<IsoSubspace> m_subspaceForFileSystemRouterConstructor;std::unique_ptr<IsoSubspace> m_subspaceForMatchedRoute; std::unique_ptr<IsoSubspace> m_subspaceForExpect; diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h index 73b96e5f6..2c0cf9929 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h @@ -70,12 +70,12 @@ JSC::Structure* JSSHA512_256Structure() { return m_JSSHA512_256.getInitializedOn JSC::LazyClassStructure m_JSSHA512_256; bool hasJSSHA512_256SetterValue { false }; mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA512_256SetterValue; -JSC::Structure* JSRIPEMD160Structure() { return m_JSRIPEMD160.getInitializedOnMainThread(this); } - JSC::JSObject* JSRIPEMD160Constructor() { return m_JSRIPEMD160.constructorInitializedOnMainThread(this); } - JSC::JSValue JSRIPEMD160Prototype() { return m_JSRIPEMD160.prototypeInitializedOnMainThread(this); } - JSC::LazyClassStructure m_JSRIPEMD160; - bool hasJSRIPEMD160SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSRIPEMD160SetterValue; +JSC::Structure* JSCryptoHasherStructure() { return m_JSCryptoHasher.getInitializedOnMainThread(this); } + JSC::JSObject* JSCryptoHasherConstructor() { return m_JSCryptoHasher.constructorInitializedOnMainThread(this); } + JSC::JSValue JSCryptoHasherPrototype() { return m_JSCryptoHasher.prototypeInitializedOnMainThread(this); } + JSC::LazyClassStructure m_JSCryptoHasher; + bool hasJSCryptoHasherSetterValue { false }; + mutable JSC::WriteBarrier<JSC::Unknown> m_JSCryptoHasherSetterValue; JSC::Structure* JSServerWebSocketStructure() { return m_JSServerWebSocket.getInitializedOnMainThread(this); } JSC::JSObject* JSServerWebSocketConstructor() { return m_JSServerWebSocket.constructorInitializedOnMainThread(this); } JSC::JSValue JSServerWebSocketPrototype() { return m_JSServerWebSocket.prototypeInitializedOnMainThread(this); } diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h index e0a13622a..8b4240876 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h @@ -71,11 +71,11 @@ void GlobalObject::initGeneratedLazyClasses() { init.setStructure(WebCore::JSSHA512_256::createStructure(init.vm, init.global, init.prototype)); init.setConstructor(WebCore::JSSHA512_256::createConstructor(init.vm, init.global, init.prototype)); }); - m_JSRIPEMD160.initLater( + m_JSCryptoHasher.initLater( [](LazyClassStructure::Initializer& init) { - init.setPrototype(WebCore::JSRIPEMD160::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); - init.setStructure(WebCore::JSRIPEMD160::createStructure(init.vm, init.global, init.prototype)); - init.setConstructor(WebCore::JSRIPEMD160::createConstructor(init.vm, init.global, init.prototype)); + init.setPrototype(WebCore::JSCryptoHasher::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); + init.setStructure(WebCore::JSCryptoHasher::createStructure(init.vm, init.global, init.prototype)); + init.setConstructor(WebCore::JSCryptoHasher::createConstructor(init.vm, init.global, init.prototype)); }); m_JSServerWebSocket.initLater( [](LazyClassStructure::Initializer& init) { @@ -153,7 +153,7 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& thisObject->m_JSSHA384.visit(visitor); visitor.append(thisObject->m_JSSHA384SetterValue); thisObject->m_JSSHA256.visit(visitor); visitor.append(thisObject->m_JSSHA256SetterValue); thisObject->m_JSSHA512_256.visit(visitor); visitor.append(thisObject->m_JSSHA512_256SetterValue); - thisObject->m_JSRIPEMD160.visit(visitor); visitor.append(thisObject->m_JSRIPEMD160SetterValue); + thisObject->m_JSCryptoHasher.visit(visitor); visitor.append(thisObject->m_JSCryptoHasherSetterValue); thisObject->m_JSServerWebSocket.visit(visitor); visitor.append(thisObject->m_JSServerWebSocketSetterValue); thisObject->m_JSFileSystemRouter.visit(visitor); visitor.append(thisObject->m_JSFileSystemRouterSetterValue); thisObject->m_JSMatchedRoute.visit(visitor); visitor.append(thisObject->m_JSMatchedRouteSetterValue); diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index df82bb7f0..b649229d4 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -4265,13 +4265,13 @@ extern "C" EncodedJSValue SHA512_256__create(Zig::GlobalObject* globalObject, vo return JSValue::encode(instance); } -class JSRIPEMD160Prototype final : public JSC::JSNonFinalObject { +class JSCryptoHasherPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; - static JSRIPEMD160Prototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + static JSCryptoHasherPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) { - JSRIPEMD160Prototype* ptr = new (NotNull, JSC::allocateCell<JSRIPEMD160Prototype>(vm)) JSRIPEMD160Prototype(vm, globalObject, structure); + JSCryptoHasherPrototype* ptr = new (NotNull, JSC::allocateCell<JSCryptoHasherPrototype>(vm)) JSCryptoHasherPrototype(vm, globalObject, structure); ptr->finishCreation(vm, globalObject); return ptr; } @@ -4288,7 +4288,7 @@ public: } private: - JSRIPEMD160Prototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + JSCryptoHasherPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) : Base(vm, structure) { } @@ -4296,10 +4296,10 @@ private: void finishCreation(JSC::VM&, JSC::JSGlobalObject*); }; -class JSRIPEMD160Constructor final : public JSC::InternalFunction { +class JSCryptoHasherConstructor final : public JSC::InternalFunction { public: using Base = JSC::InternalFunction; - static JSRIPEMD160Constructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSRIPEMD160Prototype* prototype); + static JSCryptoHasherConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSCryptoHasherPrototype* prototype); static constexpr unsigned StructureFlags = Base::StructureFlags; static constexpr bool needsDestruction = false; @@ -4313,15 +4313,15 @@ public: { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; - return WebCore::subspaceForImpl<JSRIPEMD160Constructor, WebCore::UseCustomHeapCellType::No>( + return WebCore::subspaceForImpl<JSCryptoHasherConstructor, WebCore::UseCustomHeapCellType::No>( vm, - [](auto& spaces) { return spaces.m_clientSubspaceForRIPEMD160Constructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForRIPEMD160Constructor = WTFMove(space); }, - [](auto& spaces) { return spaces.m_subspaceForRIPEMD160Constructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForRIPEMD160Constructor = WTFMove(space); }); + [](auto& spaces) { return spaces.m_clientSubspaceForCryptoHasherConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForCryptoHasherConstructor = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForCryptoHasherConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForCryptoHasherConstructor = WTFMove(space); }); } - void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSRIPEMD160Prototype* prototype); + void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSCryptoHasherPrototype* prototype); // Must be defined for each specialization class. static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); @@ -4329,62 +4329,97 @@ public: DECLARE_EXPORT_INFO; private: - JSRIPEMD160Constructor(JSC::VM& vm, JSC::Structure* structure); - void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSRIPEMD160Prototype* prototype); + JSCryptoHasherConstructor(JSC::VM& vm, JSC::Structure* structure); + void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSCryptoHasherPrototype* prototype); }; -extern "C" void* RIPEMD160Class__construct(JSC::JSGlobalObject*, JSC::CallFrame*); -JSC_DECLARE_CUSTOM_GETTER(jsRIPEMD160Constructor); -extern "C" void RIPEMD160Class__finalize(void*); +extern "C" void* CryptoHasherClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*); +JSC_DECLARE_CUSTOM_GETTER(jsCryptoHasherConstructor); +extern "C" void CryptoHasherClass__finalize(void*); -extern "C" JSC::EncodedJSValue RIPEMD160Prototype__getByteLength(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); -JSC_DECLARE_CUSTOM_GETTER(RIPEMD160Prototype__byteLengthGetterWrap); +extern "C" JSC::EncodedJSValue CryptoHasherPrototype__getAlgorithm(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(CryptoHasherPrototype__algorithmGetterWrap); -extern "C" EncodedJSValue RIPEMD160Prototype__digest(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); -JSC_DECLARE_HOST_FUNCTION(RIPEMD160Prototype__digestCallback); +extern "C" JSC::EncodedJSValue CryptoHasherPrototype__getByteLength(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(CryptoHasherPrototype__byteLengthGetterWrap); -extern "C" EncodedJSValue RIPEMD160Prototype__update(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); -JSC_DECLARE_HOST_FUNCTION(RIPEMD160Prototype__updateCallback); +extern "C" EncodedJSValue CryptoHasherPrototype__digest(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(CryptoHasherPrototype__digestCallback); -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSRIPEMD160Prototype, JSRIPEMD160Prototype::Base); +extern "C" EncodedJSValue CryptoHasherPrototype__update(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(CryptoHasherPrototype__updateCallback); -static const HashTableValue JSRIPEMD160PrototypeTableValues[] = { - { "byteLength"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, RIPEMD160Prototype__byteLengthGetterWrap, 0 } }, - { "digest"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RIPEMD160Prototype__digestCallback, 0 } }, - { "update"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RIPEMD160Prototype__updateCallback, 1 } } +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCryptoHasherPrototype, JSCryptoHasherPrototype::Base); + +static const HashTableValue JSCryptoHasherPrototypeTableValues[] = { + { "algorithm"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, CryptoHasherPrototype__algorithmGetterWrap, 0 } }, + { "byteLength"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, CryptoHasherPrototype__byteLengthGetterWrap, 0 } }, + { "digest"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, CryptoHasherPrototype__digestCallback, 0 } }, + { "update"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, CryptoHasherPrototype__updateCallback, 2 } } }; -const ClassInfo JSRIPEMD160Prototype::s_info = { "RIPEMD160"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRIPEMD160Prototype) }; +const ClassInfo JSCryptoHasherPrototype::s_info = { "CryptoHasher"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCryptoHasherPrototype) }; -JSC_DEFINE_CUSTOM_GETTER(jsRIPEMD160Constructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName)) +JSC_DEFINE_CUSTOM_GETTER(jsCryptoHasherConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName)) { VM& vm = JSC::getVM(lexicalGlobalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); - auto* prototype = jsDynamicCast<JSRIPEMD160Prototype*>(JSValue::decode(thisValue)); + auto* prototype = jsDynamicCast<JSCryptoHasherPrototype*>(JSValue::decode(thisValue)); if (UNLIKELY(!prototype)) return throwVMTypeError(lexicalGlobalObject, throwScope); - return JSValue::encode(globalObject->JSRIPEMD160Constructor()); + return JSValue::encode(globalObject->JSCryptoHasherConstructor()); +} + +JSC_DEFINE_CUSTOM_GETTER(CryptoHasherPrototype__algorithmGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSCryptoHasher* thisObject = jsCast<JSCryptoHasher*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_algorithm.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + CryptoHasherPrototype__getAlgorithm(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_algorithm.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); } -JSC_DEFINE_CUSTOM_GETTER(RIPEMD160Prototype__byteLengthGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +extern "C" void CryptoHasherPrototype__algorithmSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSCryptoHasher*>(JSValue::decode(thisValue)); + thisObject->m_algorithm.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue CryptoHasherPrototype__algorithmGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSCryptoHasher*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_algorithm.get()); +} + +JSC_DEFINE_CUSTOM_GETTER(CryptoHasherPrototype__byteLengthGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); - JSRIPEMD160* thisObject = jsCast<JSRIPEMD160*>(JSValue::decode(thisValue)); + JSCryptoHasher* thisObject = jsCast<JSCryptoHasher*>(JSValue::decode(thisValue)); JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - JSC::EncodedJSValue result = RIPEMD160Prototype__getByteLength(thisObject->wrapped(), globalObject); + JSC::EncodedJSValue result = CryptoHasherPrototype__getByteLength(thisObject->wrapped(), globalObject); RETURN_IF_EXCEPTION(throwScope, {}); RELEASE_AND_RETURN(throwScope, result); } -JSC_DEFINE_HOST_FUNCTION(RIPEMD160Prototype__digestCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +JSC_DEFINE_HOST_FUNCTION(CryptoHasherPrototype__digestCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); - JSRIPEMD160* thisObject = jsDynamicCast<JSRIPEMD160*>(callFrame->thisValue()); + JSCryptoHasher* thisObject = jsDynamicCast<JSCryptoHasher*>(callFrame->thisValue()); if (UNLIKELY(!thisObject)) { auto throwScope = DECLARE_THROW_SCOPE(vm); @@ -4393,14 +4428,14 @@ JSC_DEFINE_HOST_FUNCTION(RIPEMD160Prototype__digestCallback, (JSGlobalObject * l JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - return RIPEMD160Prototype__digest(thisObject->wrapped(), lexicalGlobalObject, callFrame); + return CryptoHasherPrototype__digest(thisObject->wrapped(), lexicalGlobalObject, callFrame); } -JSC_DEFINE_HOST_FUNCTION(RIPEMD160Prototype__updateCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +JSC_DEFINE_HOST_FUNCTION(CryptoHasherPrototype__updateCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); - JSRIPEMD160* thisObject = jsDynamicCast<JSRIPEMD160*>(callFrame->thisValue()); + JSCryptoHasher* thisObject = jsDynamicCast<JSCryptoHasher*>(callFrame->thisValue()); if (UNLIKELY(!thisObject)) { auto throwScope = DECLARE_THROW_SCOPE(vm); @@ -4409,51 +4444,51 @@ JSC_DEFINE_HOST_FUNCTION(RIPEMD160Prototype__updateCallback, (JSGlobalObject * l JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - return RIPEMD160Prototype__update(thisObject->wrapped(), lexicalGlobalObject, callFrame); + return CryptoHasherPrototype__update(thisObject->wrapped(), lexicalGlobalObject, callFrame); } -void JSRIPEMD160Prototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +void JSCryptoHasherPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { Base::finishCreation(vm); - reifyStaticProperties(vm, JSRIPEMD160::info(), JSRIPEMD160PrototypeTableValues, *this); + reifyStaticProperties(vm, JSCryptoHasher::info(), JSCryptoHasherPrototypeTableValues, *this); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } -extern "C" JSC_DECLARE_CUSTOM_GETTER(RIPEMD160Class__getByteLengthStatic); -extern "C" JSC_DECLARE_HOST_FUNCTION(RIPEMD160Class__hash); +extern "C" JSC_DECLARE_CUSTOM_GETTER(CryptoHasherClass__getAlgorithms); +extern "C" JSC_DECLARE_HOST_FUNCTION(CryptoHasherClass__hash); -static const HashTableValue JSRIPEMD160ConstructorTableValues[] = { - { "byteLength"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, RIPEMD160Class__getByteLengthStatic, 0 } }, - { "hash"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RIPEMD160Class__hash, 2 } } +static const HashTableValue JSCryptoHasherConstructorTableValues[] = { + { "algorithms"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, CryptoHasherClass__getAlgorithms, 0 } }, + { "hash"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, CryptoHasherClass__hash, 2 } } }; -void JSRIPEMD160Constructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSRIPEMD160Prototype* prototype) +void JSCryptoHasherConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSCryptoHasherPrototype* prototype) { - Base::finishCreation(vm, 0, "RIPEMD160"_s, PropertyAdditionMode::WithoutStructureTransition); - reifyStaticProperties(vm, &JSRIPEMD160Constructor::s_info, JSRIPEMD160ConstructorTableValues, *this); + Base::finishCreation(vm, 0, "CryptoHasher"_s, PropertyAdditionMode::WithoutStructureTransition); + reifyStaticProperties(vm, &JSCryptoHasherConstructor::s_info, JSCryptoHasherConstructorTableValues, *this); putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); ASSERT(inherits(info())); } -JSRIPEMD160Constructor::JSRIPEMD160Constructor(JSC::VM& vm, JSC::Structure* structure) +JSCryptoHasherConstructor::JSCryptoHasherConstructor(JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure, construct, construct) { } -JSRIPEMD160Constructor* JSRIPEMD160Constructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSRIPEMD160Prototype* prototype) +JSCryptoHasherConstructor* JSCryptoHasherConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSCryptoHasherPrototype* prototype) { - JSRIPEMD160Constructor* ptr = new (NotNull, JSC::allocateCell<JSRIPEMD160Constructor>(vm)) JSRIPEMD160Constructor(vm, structure); + JSCryptoHasherConstructor* ptr = new (NotNull, JSC::allocateCell<JSCryptoHasherConstructor>(vm)) JSCryptoHasherConstructor(vm, structure); ptr->finishCreation(vm, globalObject, prototype); return ptr; } -JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSRIPEMD160Constructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSCryptoHasherConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) { Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); JSC::VM& vm = globalObject->vm(); JSObject* newTarget = asObject(callFrame->newTarget()); - auto* constructor = globalObject->JSRIPEMD160Constructor(); - Structure* structure = globalObject->JSRIPEMD160Structure(); + auto* constructor = globalObject->JSCryptoHasherConstructor(); + Structure* structure = globalObject->JSCryptoHasherStructure(); if (constructor != newTarget) { auto scope = DECLARE_THROW_SCOPE(vm); @@ -4464,64 +4499,64 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSRIPEMD160Constructor::construct(J structure = InternalFunction::createSubclassStructure( globalObject, newTarget, - functionGlobalObject->JSRIPEMD160Structure()); + functionGlobalObject->JSCryptoHasherStructure()); } - void* ptr = RIPEMD160Class__construct(globalObject, callFrame); + void* ptr = CryptoHasherClass__construct(globalObject, callFrame); if (UNLIKELY(!ptr)) { return JSValue::encode(JSC::jsUndefined()); } - JSRIPEMD160* instance = JSRIPEMD160::create(vm, globalObject, structure, ptr); + JSCryptoHasher* instance = JSCryptoHasher::create(vm, globalObject, structure, ptr); return JSValue::encode(instance); } -void JSRIPEMD160Constructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSRIPEMD160Prototype* prototype) +void JSCryptoHasherConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSCryptoHasherPrototype* prototype) { } -const ClassInfo JSRIPEMD160Constructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRIPEMD160Constructor) }; +const ClassInfo JSCryptoHasherConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCryptoHasherConstructor) }; -extern "C" EncodedJSValue RIPEMD160__getConstructor(Zig::GlobalObject* globalObject) +extern "C" EncodedJSValue CryptoHasher__getConstructor(Zig::GlobalObject* globalObject) { - return JSValue::encode(globalObject->JSRIPEMD160Constructor()); + return JSValue::encode(globalObject->JSCryptoHasherConstructor()); } -JSRIPEMD160::~JSRIPEMD160() +JSCryptoHasher::~JSCryptoHasher() { if (m_ctx) { - RIPEMD160Class__finalize(m_ctx); + CryptoHasherClass__finalize(m_ctx); } } -void JSRIPEMD160::destroy(JSCell* cell) +void JSCryptoHasher::destroy(JSCell* cell) { - static_cast<JSRIPEMD160*>(cell)->JSRIPEMD160::~JSRIPEMD160(); + static_cast<JSCryptoHasher*>(cell)->JSCryptoHasher::~JSCryptoHasher(); } -const ClassInfo JSRIPEMD160::s_info = { "RIPEMD160"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRIPEMD160) }; +const ClassInfo JSCryptoHasher::s_info = { "CryptoHasher"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCryptoHasher) }; -void JSRIPEMD160::finishCreation(VM& vm) +void JSCryptoHasher::finishCreation(VM& vm) { Base::finishCreation(vm); ASSERT(inherits(info())); } -JSRIPEMD160* JSRIPEMD160::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) +JSCryptoHasher* JSCryptoHasher::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) { - JSRIPEMD160* ptr = new (NotNull, JSC::allocateCell<JSRIPEMD160>(vm)) JSRIPEMD160(vm, structure, ctx); + JSCryptoHasher* ptr = new (NotNull, JSC::allocateCell<JSCryptoHasher>(vm)) JSCryptoHasher(vm, structure, ctx); ptr->finishCreation(vm); return ptr; } -extern "C" void* RIPEMD160__fromJS(JSC::EncodedJSValue value) +extern "C" void* CryptoHasher__fromJS(JSC::EncodedJSValue value) { JSC::JSValue decodedValue = JSC::JSValue::decode(value); if (!decodedValue || decodedValue.isUndefinedOrNull()) return nullptr; - JSRIPEMD160* object = JSC::jsDynamicCast<JSRIPEMD160*>(decodedValue); + JSCryptoHasher* object = JSC::jsDynamicCast<JSCryptoHasher*>(decodedValue); if (!object) return nullptr; @@ -4529,9 +4564,9 @@ extern "C" void* RIPEMD160__fromJS(JSC::EncodedJSValue value) return object->wrapped(); } -extern "C" bool RIPEMD160__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) +extern "C" bool CryptoHasher__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) { - JSRIPEMD160* object = JSC::jsDynamicCast<JSRIPEMD160*>(JSValue::decode(value)); + JSCryptoHasher* object = JSC::jsDynamicCast<JSCryptoHasher*>(JSValue::decode(value)); if (!object) return false; @@ -4539,11 +4574,11 @@ extern "C" bool RIPEMD160__dangerouslySetPtr(JSC::EncodedJSValue value, void* pt return true; } -extern "C" const size_t RIPEMD160__ptrOffset = JSRIPEMD160::offsetOfWrapped(); +extern "C" const size_t CryptoHasher__ptrOffset = JSCryptoHasher::offsetOfWrapped(); -void JSRIPEMD160::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) +void JSCryptoHasher::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) { - auto* thisObject = jsCast<JSRIPEMD160*>(cell); + auto* thisObject = jsCast<JSCryptoHasher*>(cell); if (void* wrapped = thisObject->wrapped()) { // if (thisObject->scriptExecutionContext()) // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string()); @@ -4551,24 +4586,60 @@ void JSRIPEMD160::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) Base::analyzeHeap(cell, analyzer); } -JSObject* JSRIPEMD160::createConstructor(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +JSObject* JSCryptoHasher::createConstructor(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return WebCore::JSRIPEMD160Constructor::create(vm, globalObject, WebCore::JSRIPEMD160Constructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<WebCore::JSRIPEMD160Prototype*>(prototype)); + return WebCore::JSCryptoHasherConstructor::create(vm, globalObject, WebCore::JSCryptoHasherConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<WebCore::JSCryptoHasherPrototype*>(prototype)); } -JSObject* JSRIPEMD160::createPrototype(VM& vm, JSDOMGlobalObject* globalObject) +JSObject* JSCryptoHasher::createPrototype(VM& vm, JSDOMGlobalObject* globalObject) { - return JSRIPEMD160Prototype::create(vm, globalObject, JSRIPEMD160Prototype::createStructure(vm, globalObject, globalObject->objectPrototype())); + return JSCryptoHasherPrototype::create(vm, globalObject, JSCryptoHasherPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); } -extern "C" EncodedJSValue RIPEMD160__create(Zig::GlobalObject* globalObject, void* ptr) +extern "C" EncodedJSValue CryptoHasher__create(Zig::GlobalObject* globalObject, void* ptr) { auto& vm = globalObject->vm(); - JSC::Structure* structure = globalObject->JSRIPEMD160Structure(); - JSRIPEMD160* instance = JSRIPEMD160::create(vm, globalObject, structure, ptr); + JSC::Structure* structure = globalObject->JSCryptoHasherStructure(); + JSCryptoHasher* instance = JSCryptoHasher::create(vm, globalObject, structure, ptr); return JSValue::encode(instance); } + +template<typename Visitor> +void JSCryptoHasher::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSCryptoHasher* thisObject = jsCast<JSCryptoHasher*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + visitor.append(thisObject->m_algorithms); + visitor.append(thisObject->m_algorithm); +} + +DEFINE_VISIT_CHILDREN(JSCryptoHasher); + +template<typename Visitor> +void JSCryptoHasher::visitAdditionalChildren(Visitor& visitor) +{ + JSCryptoHasher* thisObject = this; + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + + visitor.append(thisObject->m_algorithms); + visitor.append(thisObject->m_algorithm); + ; +} + +DEFINE_VISIT_ADDITIONAL_CHILDREN(JSCryptoHasher); + +template<typename Visitor> +void JSCryptoHasher::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) +{ + JSCryptoHasher* thisObject = jsCast<JSCryptoHasher*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + thisObject->visitAdditionalChildren<Visitor>(visitor); +} + +DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSCryptoHasher); class JSServerWebSocketPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index 9046a002e..aee32a315 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -725,22 +725,22 @@ public: void finishCreation(JSC::VM&); }; -class JSRIPEMD160 final : public JSC::JSDestructibleObject { +class JSCryptoHasher final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; - static JSRIPEMD160* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx); + static JSCryptoHasher* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx); DECLARE_EXPORT_INFO; template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; - return WebCore::subspaceForImpl<JSRIPEMD160, WebCore::UseCustomHeapCellType::No>( + return WebCore::subspaceForImpl<JSCryptoHasher, WebCore::UseCustomHeapCellType::No>( vm, - [](auto& spaces) { return spaces.m_clientSubspaceForRIPEMD160.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForRIPEMD160 = WTFMove(space); }, - [](auto& spaces) { return spaces.m_subspaceForRIPEMD160.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForRIPEMD160 = WTFMove(space); }); + [](auto& spaces) { return spaces.m_clientSubspaceForCryptoHasher.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForCryptoHasher = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForCryptoHasher.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForCryptoHasher = WTFMove(space); }); } static void destroy(JSC::JSCell*); @@ -752,7 +752,7 @@ public: static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject); static JSObject* createConstructor(VM& vm, JSGlobalObject* globalObject, JSValue prototype); - ~JSRIPEMD160(); + ~JSCryptoHasher(); void* wrapped() const { return m_ctx; } @@ -762,17 +762,24 @@ public: } static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSRIPEMD160, m_ctx); } + static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSCryptoHasher, m_ctx); } void* m_ctx { nullptr }; - JSRIPEMD160(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + JSCryptoHasher(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) : Base(vm, structure) { m_ctx = sinkPtr; } void finishCreation(JSC::VM&); + + DECLARE_VISIT_CHILDREN; + template<typename Visitor> void visitAdditionalChildren(Visitor&); + DECLARE_VISIT_OUTPUT_CONSTRAINTS; + + mutable JSC::WriteBarrier<JSC::Unknown> m_algorithms; + mutable JSC::WriteBarrier<JSC::Unknown> m_algorithm; }; class JSServerWebSocket final : public JSC::JSDestructibleObject { diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 2226d0fb5..5713a530b 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -91,6 +91,68 @@ pub const ZigString = extern struct { ptr: [*]const u8, len: usize, + /// This function is not optimized! + pub fn eqlCaseInsensitive(this: ZigString, other: ZigString) bool { + var fallback = std.heap.stackFallback(1024, bun.default_allocator); + var fallback_allocator = fallback.get(); + + var utf16_slice = this.toSliceLowercase(fallback_allocator); + var latin1_slice = other.toSliceLowercase(fallback_allocator); + defer utf16_slice.deinit(); + defer latin1_slice.deinit(); + return strings.eqlLong(utf16_slice.slice(), latin1_slice.slice(), true); + } + + pub fn toSliceLowercase(this: ZigString, allocator: std.mem.Allocator) Slice { + if (this.len == 0) + return Slice.empty; + var fallback = std.heap.stackFallback(512, allocator); + var fallback_allocator = fallback.get(); + + var uppercase_buffer = this.toOwnedSlice(fallback_allocator) catch unreachable; + var buffer = allocator.alloc(u8, uppercase_buffer.len) catch unreachable; + var out = strings.copyLowercase(uppercase_buffer, buffer); + + return Slice{ + .allocator = NullableAllocator.init(allocator), + .ptr = out.ptr, + .len = @truncate(u32, out.len), + }; + } + + pub fn eql(this: ZigString, other: ZigString) bool { + const left_utf16 = this.is16Bit(); + const right_utf16 = other.is16Bit(); + + if (left_utf16 == right_utf16 and left_utf16) { + return strings.eqlLong(std.mem.sliceAsBytes(this.utf16SliceAligned()), std.mem.sliceAsBytes(other.utf16SliceAligned()), true); + } else if (left_utf16 == right_utf16) { + return strings.eqlLong(this.slice(), other.slice(), true); + } + + const utf16: ZigString = if (left_utf16) this else other; + const latin1: ZigString = if (left_utf16) other else this; + + if (latin1.isAllASCII()) { + return strings.utf16EqlString(utf16.utf16SliceAligned(), latin1.slice()); + } + + // slow path + var utf16_slice = utf16.toSlice(bun.default_allocator); + var latin1_slice = latin1.toSlice(bun.default_allocator); + defer utf16_slice.deinit(); + defer latin1_slice.deinit(); + return strings.eqlLong(utf16_slice.slice(), latin1_slice.slice(), true); + } + + pub fn isAllASCII(this: ZigString) bool { + if (this.is16Bit()) { + return strings.firstNonASCII16([]const u16, this.utf16SliceAligned()) == null; + } + + return strings.isAllASCII(this.slice()); + } + pub fn clone(this: ZigString, allocator: std.mem.Allocator) !ZigString { var sliced = this.toSlice(allocator); if (!sliced.isAllocated()) { @@ -209,6 +271,14 @@ pub const ZigString = extern struct { ptr: [*]const u8 = undefined, len: u32 = 0, + pub fn from(input: []u8, allocator: std.mem.Allocator) Slice { + return .{ + .ptr = input.ptr, + .len = @truncate(u32, input.len), + .allocator = NullableAllocator.init(allocator), + }; + } + pub fn fromUTF8NeverFree(input: []const u8) Slice { return .{ .ptr = input.ptr, diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index 87ab124ce..c64acbef5 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -1284,88 +1284,114 @@ pub const JSSHA512_256 = struct { } } }; -pub const JSRIPEMD160 = struct { - const RIPEMD160 = Classes.RIPEMD160; - const GetterType = fn (*RIPEMD160, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; - const GetterTypeWithThisValue = fn (*RIPEMD160, JSC.JSValue, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; - const SetterType = fn (*RIPEMD160, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; - const SetterTypeWithThisValue = fn (*RIPEMD160, JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; - const CallbackType = fn (*RIPEMD160, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue; +pub const JSCryptoHasher = struct { + const CryptoHasher = Classes.CryptoHasher; + const GetterType = fn (*CryptoHasher, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + const GetterTypeWithThisValue = fn (*CryptoHasher, JSC.JSValue, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + const SetterType = fn (*CryptoHasher, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; + const SetterTypeWithThisValue = fn (*CryptoHasher, JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; + const CallbackType = fn (*CryptoHasher, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue; /// Return the pointer to the wrapped object. /// If the object does not match the type, return null. - pub fn fromJS(value: JSC.JSValue) ?*RIPEMD160 { + pub fn fromJS(value: JSC.JSValue) ?*CryptoHasher { JSC.markBinding(@src()); - return RIPEMD160__fromJS(value); + return CryptoHasher__fromJS(value); } - /// Get the RIPEMD160 constructor value. + extern fn CryptoHasherPrototype__algorithmSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn CryptoHasherPrototype__algorithmGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `CryptoHasher.algorithm` setter + /// This value will be visited by the garbage collector. + pub fn algorithmSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + CryptoHasherPrototype__algorithmSetCachedValue(thisValue, globalObject, value); + } + + /// `CryptoHasher.algorithm` getter + /// This value will be visited by the garbage collector. + pub fn algorithmGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = CryptoHasherPrototype__algorithmGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + + /// Get the CryptoHasher constructor value. /// This loads lazily from the global object. pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); - return RIPEMD160__getConstructor(globalObject); + return CryptoHasher__getConstructor(globalObject); } - /// Create a new instance of RIPEMD160 - pub fn toJS(this: *RIPEMD160, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + /// Create a new instance of CryptoHasher + pub fn toJS(this: *CryptoHasher, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); if (comptime Environment.allow_assert) { - const value__ = RIPEMD160__create(globalObject, this); - std.debug.assert(value__.as(RIPEMD160).? == this); // If this fails, likely a C ABI issue. + const value__ = CryptoHasher__create(globalObject, this); + std.debug.assert(value__.as(CryptoHasher).? == this); // If this fails, likely a C ABI issue. return value__; } else { - return RIPEMD160__create(globalObject, this); + return CryptoHasher__create(globalObject, this); } } - /// Modify the internal ptr to point to a new instance of RIPEMD160. - pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*RIPEMD160) bool { + /// Modify the internal ptr to point to a new instance of CryptoHasher. + pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*CryptoHasher) bool { JSC.markBinding(@src()); - return RIPEMD160__dangerouslySetPtr(value, ptr); + return CryptoHasher__dangerouslySetPtr(value, ptr); } /// Detach the ptr from the thisValue - pub fn detachPtr(_: *RIPEMD160, value: JSC.JSValue) void { + pub fn detachPtr(_: *CryptoHasher, value: JSC.JSValue) void { JSC.markBinding(@src()); - std.debug.assert(RIPEMD160__dangerouslySetPtr(value, null)); + std.debug.assert(CryptoHasher__dangerouslySetPtr(value, null)); } - extern fn RIPEMD160__fromJS(JSC.JSValue) ?*RIPEMD160; - extern fn RIPEMD160__getConstructor(*JSC.JSGlobalObject) JSC.JSValue; + extern fn CryptoHasher__fromJS(JSC.JSValue) ?*CryptoHasher; + extern fn CryptoHasher__getConstructor(*JSC.JSGlobalObject) JSC.JSValue; - extern fn RIPEMD160__create(globalObject: *JSC.JSGlobalObject, ptr: ?*RIPEMD160) JSC.JSValue; + extern fn CryptoHasher__create(globalObject: *JSC.JSGlobalObject, ptr: ?*CryptoHasher) JSC.JSValue; - extern fn RIPEMD160__dangerouslySetPtr(JSC.JSValue, ?*RIPEMD160) bool; + extern fn CryptoHasher__dangerouslySetPtr(JSC.JSValue, ?*CryptoHasher) bool; comptime { - if (@TypeOf(RIPEMD160.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*RIPEMD160)) { - @compileLog("RIPEMD160.constructor is not a constructor"); + if (@TypeOf(CryptoHasher.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*CryptoHasher)) { + @compileLog("CryptoHasher.constructor is not a constructor"); } - if (@TypeOf(RIPEMD160.finalize) != (fn (*RIPEMD160) callconv(.C) void)) { - @compileLog("RIPEMD160.finalize is not a finalizer"); + if (@TypeOf(CryptoHasher.finalize) != (fn (*CryptoHasher) callconv(.C) void)) { + @compileLog("CryptoHasher.finalize is not a finalizer"); } - if (@TypeOf(RIPEMD160.getByteLength) != GetterType) - @compileLog("Expected RIPEMD160.getByteLength to be a getter"); + if (@TypeOf(CryptoHasher.getAlgorithm) != GetterType) + @compileLog("Expected CryptoHasher.getAlgorithm to be a getter"); + + if (@TypeOf(CryptoHasher.getByteLength) != GetterType) + @compileLog("Expected CryptoHasher.getByteLength to be a getter"); - if (@TypeOf(RIPEMD160.digest) != CallbackType) - @compileLog("Expected RIPEMD160.digest to be a callback but received " ++ @typeName(@TypeOf(RIPEMD160.digest))); - if (@TypeOf(RIPEMD160.update) != CallbackType) - @compileLog("Expected RIPEMD160.update to be a callback but received " ++ @typeName(@TypeOf(RIPEMD160.update))); - if (@TypeOf(RIPEMD160.getByteLengthStatic) != StaticGetterType) - @compileLog("Expected RIPEMD160.getByteLengthStatic to be a static getter"); + if (@TypeOf(CryptoHasher.digest) != CallbackType) + @compileLog("Expected CryptoHasher.digest to be a callback but received " ++ @typeName(@TypeOf(CryptoHasher.digest))); + if (@TypeOf(CryptoHasher.update) != CallbackType) + @compileLog("Expected CryptoHasher.update to be a callback but received " ++ @typeName(@TypeOf(CryptoHasher.update))); + if (@TypeOf(CryptoHasher.getAlgorithms) != StaticGetterType) + @compileLog("Expected CryptoHasher.getAlgorithms to be a static getter"); - if (@TypeOf(RIPEMD160.hash) != StaticCallbackType) - @compileLog("Expected RIPEMD160.hash to be a static callback"); + if (@TypeOf(CryptoHasher.hash) != StaticCallbackType) + @compileLog("Expected CryptoHasher.hash to be a static callback"); if (!JSC.is_bindgen) { - @export(RIPEMD160.constructor, .{ .name = "RIPEMD160Class__construct" }); - @export(RIPEMD160.digest, .{ .name = "RIPEMD160Prototype__digest" }); - @export(RIPEMD160.finalize, .{ .name = "RIPEMD160Class__finalize" }); - @export(RIPEMD160.getByteLength, .{ .name = "RIPEMD160Prototype__getByteLength" }); - @export(RIPEMD160.getByteLengthStatic, .{ .name = "RIPEMD160Class__getByteLengthStatic" }); - @export(RIPEMD160.hash, .{ .name = "RIPEMD160Class__hash" }); - @export(RIPEMD160.update, .{ .name = "RIPEMD160Prototype__update" }); + @export(CryptoHasher.constructor, .{ .name = "CryptoHasherClass__construct" }); + @export(CryptoHasher.digest, .{ .name = "CryptoHasherPrototype__digest" }); + @export(CryptoHasher.finalize, .{ .name = "CryptoHasherClass__finalize" }); + @export(CryptoHasher.getAlgorithm, .{ .name = "CryptoHasherPrototype__getAlgorithm" }); + @export(CryptoHasher.getAlgorithms, .{ .name = "CryptoHasherClass__getAlgorithms" }); + @export(CryptoHasher.getByteLength, .{ .name = "CryptoHasherPrototype__getByteLength" }); + @export(CryptoHasher.hash, .{ .name = "CryptoHasherClass__hash" }); + @export(CryptoHasher.update, .{ .name = "CryptoHasherPrototype__update" }); } } }; @@ -3276,7 +3302,7 @@ comptime { _ = JSSHA384; _ = JSSHA256; _ = JSSHA512_256; - _ = JSRIPEMD160; + _ = JSCryptoHasher; _ = JSServerWebSocket; _ = JSFileSystemRouter; _ = JSMatchedRoute; diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index bb386816d..2eaf30e04 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -11,7 +11,7 @@ pub const Classes = struct { pub const SHA384 = JSC.API.Bun.Crypto.SHA384; pub const SHA256 = JSC.API.Bun.Crypto.SHA256; pub const SHA512_256 = JSC.API.Bun.Crypto.SHA512_256; - pub const RIPEMD160 = JSC.API.Bun.Crypto.RIPEMD160; + pub const CryptoHasher = JSC.API.Bun.Crypto.CryptoHasher; pub const TextDecoder = JSC.WebCore.TextDecoder; pub const Blob = JSC.WebCore.Blob; pub const Subprocess = JSC.Subprocess; diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index ed202830c..deacd6d1e 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -373,6 +373,82 @@ pub const SliceOrBuffer = union(Tag) { else => null, }; } + + pub fn fromJSWithEncoding(global: *JSC.JSGlobalObject, allocator: std.mem.Allocator, value: JSC.JSValue, encoding_value: JSC.JSValue) ?SliceOrBuffer { + if (encoding_value.isEmptyOrUndefinedOrNull()) + return fromJS(global, allocator, value); + + switch (value.jsType()) { + .ArrayBuffer, + .Int8Array, + .Uint8Array, + .Uint8ClampedArray, + .Int16Array, + .Uint16Array, + .Int32Array, + .Uint32Array, + .Float32Array, + .Float64Array, + .BigInt64Array, + .BigUint64Array, + .DataView, + => return SliceOrBuffer{ + .buffer = JSC.MarkedArrayBuffer{ + .buffer = value.asArrayBuffer(global) orelse return null, + .allocator = null, + }, + }, + else => {}, + } + + var encoding_str = encoding_value.toSlice(global, allocator); + if (encoding_str.len == 0) + return fromJS(global, allocator, value); + + defer encoding_str.deinit(); + // TODO: better error + const encoding = Encoding.from(encoding_str.slice()) orelse return null; + if (encoding == .utf8) { + return fromJS(global, allocator, value); + } + + var zig_str = value.getZigString(global); + if (zig_str.len == 0) { + return fromJS(global, allocator, value); + } + + const out = brk: { + if (zig_str.is16Bit()) { + const buf = zig_str.slice(); + break :brk switch (encoding) { + Encoding.utf8 => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .utf8), + Encoding.ucs2 => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .ucs2), + Encoding.utf16le => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .utf16le), + Encoding.latin1 => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .latin1), + Encoding.ascii => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .ascii), + Encoding.base64 => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .base64), + Encoding.hex => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .hex), + Encoding.buffer => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .buffer), + Encoding.base64url => JSC.WebCore.Encoder.constructFromU8(buf.ptr, buf.len, .base64url), + }; + } else { + const buf = zig_str.utf16SliceAligned(); + break :brk switch (encoding) { + Encoding.utf8 => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .utf8), + Encoding.ucs2 => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .ucs2), + Encoding.utf16le => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .utf16le), + Encoding.latin1 => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .latin1), + Encoding.ascii => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .ascii), + Encoding.base64 => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .base64), + Encoding.hex => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .hex), + Encoding.buffer => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .buffer), + Encoding.base64url => JSC.WebCore.Encoder.constructFromU16(buf.ptr, buf.len, .base64url), + }; + } + }; + + return .{ .string = JSC.ZigString.Slice.from(out, allocator) }; + } }; pub const ErrorCode = @import("./nodejs_error_code.zig").Code; @@ -459,6 +535,36 @@ pub const Encoding = enum(u8) { }, } } + + pub fn encodeWithMaxSize(encoding: Encoding, globalThis: *JSC.JSGlobalObject, size: usize, comptime max_size: usize, input: []const u8) JSC.JSValue { + switch (encoding) { + .base64 => { + var base64_buf: [std.base64.standard.Encoder.calcSize(max_size)]u8 = undefined; + var base64 = base64_buf[0..std.base64.standard.Encoder.calcSize(size)]; + const result = JSC.ZigString.init(std.base64.standard.Encoder.encode(base64, input)).toValueGC(globalThis); + return result; + }, + .base64url => { + var buf_: [std.base64.url_safe.Encoder.calcSize(max_size) + "data:;base64,".len]u8 = undefined; + var buf = buf_[0 .. std.base64.url_safe.Encoder.calcSize(size) + "data:;base64,".len]; + var encoded = std.base64.url_safe.Encoder.encode(buf["data:;base64,".len..], input); + buf[0.."data:;base64,".len].* = "data:;base64,".*; + + const result = JSC.ZigString.init(buf[0 .. "data:;base64,".len + encoded.len]).toValueGC(globalThis); + return result; + }, + .hex => { + var buf: [max_size * 4]u8 = undefined; + var out = std.fmt.bufPrint(&buf, "{}", .{std.fmt.fmtSliceHexLower(input)}) catch unreachable; + const result = JSC.ZigString.init(out).toValueGC(globalThis); + return result; + }, + else => { + globalThis.throwInvalidArguments("Unexpected encoding", .{}); + return JSC.JSValue.zero; + }, + } + } }; const PathOrBuffer = union(Tag) { diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig index 9573b1f3a..19c370143 100644 --- a/src/bun.js/webcore/encoding.zig +++ b/src/bun.js/webcore/encoding.zig @@ -1145,7 +1145,8 @@ pub const Encoder = struct { }, JSC.Node.Encoding.latin1, JSC.Node.Encoding.buffer, JSC.Node.Encoding.ascii => { var to = allocator.alloc(u8, len) catch return &[_]u8{}; - @memcpy(to.ptr, input, len); + var input_bytes = std.mem.sliceAsBytes(input[0..len]); + @memcpy(to.ptr, input_bytes.ptr, input_bytes.len); for (to[0..len]) |c, i| { to[i] = @as(u8, @truncate(u7, c)); } diff --git a/src/deps/boringssl.translated.zig b/src/deps/boringssl.translated.zig index a26a64154..d2b863e2f 100644 --- a/src/deps/boringssl.translated.zig +++ b/src/deps/boringssl.translated.zig @@ -1339,9 +1339,22 @@ pub extern fn EVP_MD_CTX_move(out: [*c]EVP_MD_CTX, in: [*c]EVP_MD_CTX) void; pub extern fn EVP_MD_CTX_reset(ctx: *EVP_MD_CTX) c_int; pub extern fn EVP_DigestInit_ex(ctx: *EVP_MD_CTX, @"type": ?*const EVP_MD, engine: ?*ENGINE) c_int; pub extern fn EVP_DigestInit(ctx: *EVP_MD_CTX, @"type": ?*const EVP_MD) c_int; +/// EVP_DigestUpdate hashes |len| bytes from |data| into the hashing operation +/// in |ctx|. It returns one. pub extern fn EVP_DigestUpdate(ctx: *EVP_MD_CTX, data: ?[*]const u8, len: usize) c_int; -pub extern fn EVP_DigestFinal_ex(ctx: *EVP_MD_CTX, md_out: [*]u8, out_size: ?[*]c_uint) c_int; -pub extern fn EVP_DigestFinal(ctx: *EVP_MD_CTX, md_out: [*]u8, out_size: ?[*]c_uint) c_int; +/// EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to +/// |md_out|. |EVP_MD_CTX_size| bytes are written, which is at most +/// |EVP_MAX_MD_SIZE|. If |out_size| is not NULL then |*out_size| is set to the +/// number of bytes written. It returns one. After this call, the hash cannot be +/// updated or finished again until |EVP_DigestInit_ex| is called to start +/// another hashing operation. +pub extern fn EVP_DigestFinal_ex(ctx: *EVP_MD_CTX, md_out: [*]u8, out_size: ?*u32) c_int; +pub extern fn EVP_DigestFinal(ctx: *EVP_MD_CTX, md_out: [*]u8, out_size: ?*u32) c_int; +/// EVP_Digest performs a complete hashing operation in one call. It hashes |len| +/// bytes from |data| and writes the digest to |md_out|. |EVP_MD_CTX_size| bytes +/// are written, which is at most |EVP_MAX_MD_SIZE|. If |out_size| is not NULL +/// then |*out_size| is set to the number of bytes written. It returns one on +/// success and zero otherwise. pub extern fn EVP_Digest(data: ?[*]const u8, len: usize, md_out: [*c]u8, md_out_size: [*c]c_uint, @"type": ?*const EVP_MD, impl: ?*ENGINE) c_int; pub extern fn EVP_MD_type(md: ?*const EVP_MD) c_int; pub extern fn EVP_MD_flags(md: ?*const EVP_MD) u32; diff --git a/test/bun.js/crypto.test.js b/test/bun.js/crypto.test.js index 30a0f227d..8b93dab64 100644 --- a/test/bun.js/crypto.test.js +++ b/test/bun.js/crypto.test.js @@ -8,8 +8,8 @@ import { SHA384, SHA512, SHA512_256, - RIPEMD160, gc, + CryptoHasher, } from "bun"; import { it, expect, describe } from "bun:test"; import { readFileSync } from "fs"; @@ -23,9 +23,52 @@ const HashClasses = [ SHA384, SHA512, SHA512_256, - RIPEMD160, ]; +describe("CryptoHasher", () => { + it("CryptoHasher.algorithms", () => { + expect(CryptoHasher.algorithms).toEqual([ + "blake2b256", + "md4", + "md5", + "ripemd160", + "sha1", + "sha224", + "sha256", + "sha384", + "sha512", + "sha512-256", + ]); + }); + + it("CryptoHasher md5", () => { + var hasher = new CryptoHasher("md5"); + hasher.update("hello world"); + expect(hasher.digest("hex")).toBe("5eb63bbbe01eeed093cb22bb8f5acdc3"); + expect(hasher.algorithm).toBe("md5"); + }); + + it("CryptoHasher blake2b256", () => { + var hasher = new CryptoHasher("blake2b256"); + hasher.update("hello world"); + expect(hasher.algorithm).toBe("blake2b256"); + + expect(hasher.digest("hex")).toBe( + // b2sum --length=256 + "256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610", + ); + }); + + it("CryptoHasher sha512", () => { + var hasher = new CryptoHasher("sha512"); + hasher.update("hello world"); + expect(hasher.digest("hex")).toBe( + "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f", + ); + expect(hasher.algorithm).toBe("sha512"); + }); +}); + describe("crypto", () => { for (let Hash of HashClasses) { for (let [input, label] of [ |