Support digest("base64" | "hex") in the hashings

This commit is contained in:
Jarred Sumner
2022-04-13 04:20:05 -07:00
parent f6d73cb06e
commit 3db3057d42
10 changed files with 746 additions and 144 deletions

View File

@@ -1118,19 +1118,7 @@ pub const Class = NewClass(
.rfn = JSC.WebCore.Blob.writeFile,
.ts = d.ts{},
},
.sha1 = .{
.rfn = JSC.wrapWithHasContainer(Crypto.SHA1, "hash", false, false),
},
.sha256 = .{
.rfn = JSC.wrapWithHasContainer(Crypto.SHA256, "hash", false, false),
},
.sha384 = .{
.rfn = JSC.wrapWithHasContainer(Crypto.SHA384, "hash", false, false),
},
.sha512 = .{
.rfn = JSC.wrapWithHasContainer(Crypto.SHA512, "hash", false, false),
},
.sha512_256 = .{
.sha = .{
.rfn = JSC.wrapWithHasContainer(Crypto.SHA512_256, "hash", false, false),
},
},
@@ -1189,17 +1177,27 @@ pub const Class = NewClass(
.unsafe = .{
.get = getUnsafe,
},
.SHA1 = .{
.get = Crypto.SHA1.getter,
},
.SHA256 = .{
.get = Crypto.SHA256.getter,
.MD5 = .{
.get = Crypto.MD5.getter,
},
.MD4 = .{
.get = Crypto.MD4.getter,
},
.SHA224 = .{
.get = Crypto.SHA224.getter,
},
.SHA512 = .{
.get = Crypto.SHA512.getter,
},
.SHA384 = .{
.get = Crypto.SHA384.getter,
},
.SHA512 = .{
.get = Crypto.SHA512.getter,
.SHA256 = .{
.get = Crypto.SHA256.getter,
},
.SHA512_256 = .{
.get = Crypto.SHA512_256.getter,
@@ -1238,7 +1236,7 @@ pub const Crypto = struct {
@This(),
.{
.hash = .{
.rfn = JSC.wrapSync(@This(), "hash"),
.rfn = JSC.wrapWithHasContainer(@This(), "hash", false, false),
},
.constructor = .{ .rfn = constructor },
},
@@ -1258,8 +1256,8 @@ pub const Crypto = struct {
.update = .{
.rfn = JSC.wrapSync(@This(), "update"),
},
.final = .{
.rfn = JSC.wrapSync(@This(), "final"),
.digest = .{
.rfn = JSC.wrapSync(@This(), "digest"),
},
.finalize = finalize,
},
@@ -1270,7 +1268,20 @@ pub const Crypto = struct {
},
);
pub fn hash(
fn hashToEncoding(
globalThis: *JSGlobalObject,
input: JSC.Node.StringOrBuffer,
encoding: JSC.Node.Encoding,
exception: JSC.C.ExceptionRef,
) JSC.JSValue {
var output_digest_buf: Hasher.Digest = undefined;
Hasher.hash(input.slice(), &output_digest_buf, JSC.VirtualMachine.vm.rareData().boringEngine());
return encoding.encodeWithSize(globalThis, Hasher.digest, &output_digest_buf, exception);
}
fn hashToBytes(
globalThis: *JSGlobalObject,
input: JSC.Node.StringOrBuffer,
output: ?JSC.ArrayBuffer,
@@ -1293,7 +1304,7 @@ pub const Crypto = struct {
output_digest_slice = bytes[0..Hasher.digest];
}
Hasher.hash(input.slice(), output_digest_slice);
Hasher.hash(input.slice(), output_digest_slice, JSC.VirtualMachine.vm.rareData().boringEngine());
if (output) |output_buf| {
return output_buf.value;
@@ -1303,6 +1314,37 @@ pub const Crypto = struct {
}
}
pub fn hash(
globalThis: *JSGlobalObject,
input: JSC.Node.StringOrBuffer,
output: ?JSC.Node.StringOrBuffer,
exception: JSC.C.ExceptionRef,
) JSC.JSValue {
if (output) |string_or_buffer| {
switch (string_or_buffer) {
.string => |str| {
const encoding = JSC.Node.Encoding.from(str) orelse {
JSC.JSError(
bun.default_allocator,
"Unknown encoding",
.{},
globalThis.ref(),
exception,
);
return JSC.JSValue.zero;
};
return hashToEncoding(globalThis, input, encoding, exception);
},
.buffer => |buffer| {
return hashToBytes(globalThis, input, buffer.buffer, exception);
},
}
} else {
return hashToBytes(globalThis, input, null, exception);
}
}
pub fn constructor(
ctx: js.JSContextRef,
_: js.JSObjectRef,
@@ -1336,12 +1378,47 @@ pub const Crypto = struct {
return existing.asObjectRef();
}
pub fn update(this: *@This(), buffer: JSC.Node.StringOrBuffer) JSC.JSValue {
pub fn update(this: *@This(), thisObj: JSC.C.JSObjectRef, buffer: JSC.Node.StringOrBuffer) JSC.JSValue {
this.hashing.update(buffer.slice());
return JSC.JSValue.jsUndefined();
return JSC.JSValue.c(thisObj);
}
pub fn final(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, output: ?JSC.ArrayBuffer) JSC.JSValue {
pub fn digest(
this: *@This(),
globalThis: *JSGlobalObject,
output: ?JSC.Node.StringOrBuffer,
exception: JSC.C.ExceptionRef,
) JSC.JSValue {
if (output) |string_or_buffer| {
switch (string_or_buffer) {
.string => |str| {
const encoding = JSC.Node.Encoding.from(str) orelse {
JSC.JSError(
bun.default_allocator,
"Unknown encoding",
.{},
globalThis.ref(),
exception,
);
return JSC.JSValue.zero;
};
return this.digestToEncoding(globalThis, exception, encoding);
},
.buffer => |buffer| {
return this.digestToBytes(
globalThis,
exception,
buffer.buffer,
);
},
}
} else {
return this.digestToBytes(globalThis, exception, null);
}
}
fn digestToBytes(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, output: ?JSC.ArrayBuffer) JSC.JSValue {
var output_digest_buf: Hasher.Digest = undefined;
var output_digest_slice: *Hasher.Digest = &output_digest_buf;
if (output) |output_buf| {
@@ -1370,6 +1447,7 @@ pub const Crypto = struct {
}
this.hashing.final(output_digest_slice);
if (output) |output_buf| {
return output_buf.value;
} else {
@@ -1378,17 +1456,39 @@ pub const Crypto = struct {
}
}
fn digestToEncoding(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, encoding: JSC.Node.Encoding) JSC.JSValue {
var output_digest_buf: Hasher.Digest = comptime brk: {
var bytes: Hasher.Digest = undefined;
var i: usize = 0;
while (i < Hasher.digest) {
bytes[i] = 0;
i += 1;
}
break :brk bytes;
};
var output_digest_slice: *Hasher.Digest = &output_digest_buf;
this.hashing.final(output_digest_slice);
return encoding.encodeWithSize(globalThis, Hasher.digest, output_digest_slice, exception);
}
pub fn finalize(this: *@This()) void {
VirtualMachine.vm.allocator.destroy(this);
}
};
}
pub const SHA1 = CryptoHasher(Hashers.SHA1, "SHA1", "Bun_SHA1");
pub const SHA256 = CryptoHasher(Hashers.SHA256, "SHA256", "Bun_SHA256");
pub const SHA384 = CryptoHasher(Hashers.SHA384, "SHA384", "Bun_SHA384");
pub const SHA512 = CryptoHasher(Hashers.SHA512, "SHA512", "Bun_SHA512");
pub const SHA512_256 = CryptoHasher(Hashers.SHA512_256, "SHA512_256", "Bun_SHA512_256");
pub const SHA1 = CryptoHasher(Hashers.SHA1, "SHA1", "Bun_Crypto_SHA1");
pub const MD5 = CryptoHasher(Hashers.MD5, "MD5", "Bun_Crypto_MD5");
pub const MD4 = CryptoHasher(Hashers.MD4, "MD4", "Bun_Crypto_MD4");
pub const SHA224 = CryptoHasher(Hashers.SHA224, "SHA224", "Bun_Crypto_SHA224");
pub const SHA512 = CryptoHasher(Hashers.SHA512, "SHA512", "Bun_Crypto_SHA512");
pub const SHA384 = CryptoHasher(Hashers.SHA384, "SHA384", "Bun_Crypto_SHA384");
pub const SHA256 = CryptoHasher(Hashers.SHA256, "SHA256", "Bun_Crypto_SHA256");
pub const SHA512_256 = CryptoHasher(Hashers.SHA512_256, "SHA512_256", "Bun_Crypto_SHA512_256");
pub const MD5_SHA1 = CryptoHasher(Hashers.MD5_SHA1, "MD5_SHA1", "Bun_Crypto_MD5_SHA1");
};
pub fn serve(

View File

@@ -2557,10 +2557,14 @@ const SSLServer = JSC.API.SSLServer;
const DebugServer = JSC.API.DebugServer;
const DebugSSLServer = JSC.API.DebugSSLServer;
const SHA1 = JSC.API.Bun.Crypto.SHA1;
const SHA256 = JSC.API.Bun.Crypto.SHA256;
const SHA384 = JSC.API.Bun.Crypto.SHA384;
const MD5 = JSC.API.Bun.Crypto.MD5;
const MD4 = JSC.API.Bun.Crypto.MD4;
const SHA224 = JSC.API.Bun.Crypto.SHA224;
const SHA512 = JSC.API.Bun.Crypto.SHA512;
const SHA384 = JSC.API.Bun.Crypto.SHA384;
const SHA256 = JSC.API.Bun.Crypto.SHA256;
const SHA512_256 = JSC.API.Bun.Crypto.SHA512_256;
const MD5_SHA1 = JSC.API.Bun.Crypto.MD5_SHA1;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
AttributeIterator,
@@ -2584,6 +2588,9 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
HTMLRewriter,
JSNode,
LazyPropertiesObject,
MD4,
MD5_SHA1,
MD5,
ModuleNamespace,
NodeFS,
Request,
@@ -2591,6 +2598,12 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Response,
Router,
Server,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512_256,
SHA512,
SSLServer,
Stats,
TextChunk,
@@ -2598,11 +2611,6 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
TextEncoder,
TimeoutTask,
Transpiler,
SHA1,
SHA256,
SHA384,
SHA512,
SHA512_256,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {

View File

@@ -193,6 +193,11 @@ pub const Encoding = enum(u8) {
var str = JSC.ZigString.Empty;
value.toZigString(&str, global);
const slice = str.slice();
return from(slice);
}
/// Caller must verify the value is a string
pub fn from(slice: []const u8) ?Encoding {
return switch (slice.len) {
0...2 => null,
else => switch (Eight.matchLower(slice)) {
@@ -214,6 +219,34 @@ pub const Encoding = enum(u8) {
},
};
}
pub fn encodeWithSize(encoding: Encoding, globalThis: *JSC.JSGlobalObject, comptime size: usize, input: *const [size]u8, exception: JSC.C.ExceptionRef) JSC.JSValue {
switch (encoding) {
.base64 => {
var base64: [std.base64.standard.Encoder.calcSize(size)]u8 = undefined;
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(size) + "data:;base64,".len]u8 = undefined;
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: [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 => {
JSC.throwInvalidArguments("Unexpected encoding", .{}, globalThis.ref(), exception);
return JSC.JSValue.zero;
},
}
}
};
const PathOrBuffer = union(Tag) {

View File

@@ -6,12 +6,21 @@ const RareData = @This();
const Syscall = @import("./node/syscall.zig");
const JSC = @import("javascript_core");
const std = @import("std");
const BoringSSL = @import("boringssl");
boring_ssl_engine: ?*BoringSSL.ENGINE = null,
editor_context: EditorContext = EditorContext{},
stderr_store: ?*Blob.Store = null,
stdin_store: ?*Blob.Store = null,
stdout_store: ?*Blob.Store = null,
pub fn boringEngine(rare: *RareData) *BoringSSL.ENGINE {
return rare.boring_ssl_engine orelse brk: {
rare.boring_ssl_engine = BoringSSL.ENGINE_new();
break :brk rare.boring_ssl_engine.?;
};
}
pub fn stderr(rare: *RareData) *Blob.Store {
return rare.stderr_store orelse brk: {
var store = default_allocator.create(Blob.Store) catch unreachable;