summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--ext/node/Cargo.toml1
-rw-r--r--ext/node/crypto/mod.rs55
-rw-r--r--ext/node/lib.rs2
-rw-r--r--ext/node/polyfills/internal/crypto/hash.ts32
5 files changed, 70 insertions, 27 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9c6c30f3d..8b9dd991f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1228,6 +1228,7 @@ version = "0.28.0"
dependencies = [
"deno_core",
"digest 0.10.6",
+ "hex",
"idna 0.3.0",
"indexmap",
"md-5",
@@ -2242,6 +2243,12 @@ dependencies = [
]
[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
name = "hexf-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index e21c8c304..1ce6dd443 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -16,6 +16,7 @@ path = "lib.rs"
[dependencies]
deno_core.workspace = true
digest = { version = "0.10.5", features = ["core-api", "std"] }
+hex = "0.4.3"
idna = "0.3.0"
indexmap.workspace = true
md-5 = "0.10.5"
diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs
index 597779328..f9a61b456 100644
--- a/ext/node/crypto/mod.rs
+++ b/ext/node/crypto/mod.rs
@@ -17,23 +17,38 @@ use rsa::RsaPublicKey;
mod digest;
-#[op]
-pub fn op_node_create_hash(
- state: &mut OpState,
- algorithm: String,
-) -> Result<ResourceId, AnyError> {
- Ok(state.resource_table.add(digest::Context::new(&algorithm)?))
+#[op(fast)]
+pub fn op_node_create_hash(state: &mut OpState, algorithm: &str) -> u32 {
+ state
+ .resource_table
+ .add(match digest::Context::new(algorithm) {
+ Ok(context) => context,
+ Err(_) => return 0,
+ })
}
-#[op]
-pub fn op_node_hash_update(
- state: &mut OpState,
- rid: ResourceId,
- data: &[u8],
-) -> Result<(), AnyError> {
- let context = state.resource_table.get::<digest::Context>(rid)?;
+#[op(fast)]
+pub fn op_node_hash_update(state: &mut OpState, rid: u32, data: &[u8]) -> bool {
+ let context = match state.resource_table.get::<digest::Context>(rid) {
+ Ok(context) => context,
+ _ => return false,
+ };
context.update(data);
- Ok(())
+ true
+}
+
+#[op(fast)]
+pub fn op_node_hash_update_str(
+ state: &mut OpState,
+ rid: u32,
+ data: &str,
+) -> bool {
+ let context = match state.resource_table.get::<digest::Context>(rid) {
+ Ok(context) => context,
+ _ => return false,
+ };
+ context.update(data.as_bytes());
+ true
}
#[op]
@@ -48,6 +63,18 @@ pub fn op_node_hash_digest(
}
#[op]
+pub fn op_node_hash_digest_hex(
+ state: &mut OpState,
+ rid: ResourceId,
+) -> Result<String, AnyError> {
+ let context = state.resource_table.take::<digest::Context>(rid)?;
+ let context = Rc::try_unwrap(context)
+ .map_err(|_| type_error("Hash context is already in use"))?;
+ let digest = context.digest()?;
+ Ok(hex::encode(digest))
+}
+
+#[op]
pub fn op_node_hash_clone(
state: &mut OpState,
rid: ResourceId,
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 6df408ffd..725567cc3 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -328,7 +328,9 @@ pub fn init_polyfill() -> Extension {
.ops(vec![
crypto::op_node_create_hash::decl(),
crypto::op_node_hash_update::decl(),
+ crypto::op_node_hash_update_str::decl(),
crypto::op_node_hash_digest::decl(),
+ crypto::op_node_hash_digest_hex::decl(),
crypto::op_node_hash_clone::decl(),
crypto::op_node_private_encrypt::decl(),
crypto::op_node_private_decrypt::decl(),
diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts
index 7a7c0be8e..e2907632f 100644
--- a/ext/node/polyfills/internal/crypto/hash.ts
+++ b/ext/node/polyfills/internal/crypto/hash.ts
@@ -1,13 +1,9 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
-import {
- TextDecoder,
- TextEncoder,
-} from "internal:deno_web/08_text_encoding.js";
+import { TextEncoder } from "internal:deno_web/08_text_encoding.js";
import { Buffer } from "internal:deno_node/buffer.ts";
import { Transform } from "internal:deno_node/stream.ts";
-import { encode as encodeToHex } from "internal:deno_node/internal/crypto/_hex.ts";
import {
forgivingBase64Encode as encodeToBase64,
forgivingBase64UrlEncode as encodeToBase64Url,
@@ -26,6 +22,14 @@ import { notImplemented } from "internal:deno_node/_utils.ts";
const { ops } = globalThis.__bootstrap.core;
+// TODO(@littledivy): Use Result<T, E> instead of boolean when
+// https://bugs.chromium.org/p/v8/issues/detail?id=13600 is fixed.
+function unwrapErr(ok: boolean) {
+ if (!ok) {
+ throw new Error("Context is not initialized");
+ }
+}
+
const coerceToBytes = (data: string | BufferSource): Uint8Array => {
if (data instanceof Uint8Array) {
return data;
@@ -71,6 +75,9 @@ export class Hash extends Transform {
this.#context = ops.op_node_create_hash(
algorithm,
);
+ if (this.#context === 0) {
+ throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
+ }
} else {
this.#context = algorithm;
}
@@ -86,16 +93,12 @@ export class Hash extends Transform {
* Updates the hash content with the given data.
*/
update(data: string | ArrayBuffer, _encoding?: string): this {
- let bytes;
if (typeof data === "string") {
- data = new TextEncoder().encode(data);
- bytes = coerceToBytes(data);
+ unwrapErr(ops.op_node_hash_update_str(this.#context, data));
} else {
- bytes = coerceToBytes(data);
+ unwrapErr(ops.op_node_hash_update(this.#context, coerceToBytes(data)));
}
- ops.op_node_hash_update(this.#context, bytes);
-
return this;
}
@@ -107,14 +110,17 @@ export class Hash extends Transform {
* Supported encodings are currently 'hex', 'binary', 'base64', 'base64url'.
*/
digest(encoding?: string): Buffer | string {
+ if (encoding === "hex") {
+ return ops.op_node_hash_digest_hex(this.#context);
+ }
+
const digest = ops.op_node_hash_digest(this.#context);
if (encoding === undefined) {
return Buffer.from(digest);
}
+ // TODO(@littedivy): Fast paths for below encodings.
switch (encoding) {
- case "hex":
- return new TextDecoder().decode(encodeToHex(new Uint8Array(digest)));
case "binary":
return String.fromCharCode(...digest);
case "base64":