summaryrefslogtreecommitdiff
path: root/std/node/_crypto
diff options
context:
space:
mode:
authorLiam Murphy <43807659+Liamolucko@users.noreply.github.com>2021-01-26 23:34:40 +1100
committerGitHub <noreply@github.com>2021-01-26 13:34:40 +0100
commit06bd692e5c4a8f66960d3919e7087530b60c20dd (patch)
tree54da22655c71341c0e1e750d5197623e4fa0e286 /std/node/_crypto
parentf9949a31707dcaa5a8786bfe4f84ed202be91607 (diff)
fix(std/node): Stop callbacks being called twice when callback throws error (#8867)
Diffstat (limited to 'std/node/_crypto')
-rw-r--r--std/node/_crypto/pbkdf2.ts34
-rw-r--r--std/node/_crypto/pbkdf2_test.ts15
-rw-r--r--std/node/_crypto/randomBytes.ts12
-rw-r--r--std/node/_crypto/randomBytes_test.ts31
4 files changed, 70 insertions, 22 deletions
diff --git a/std/node/_crypto/pbkdf2.ts b/std/node/_crypto/pbkdf2.ts
index 80aacdaf2..2a63802e6 100644
--- a/std/node/_crypto/pbkdf2.ts
+++ b/std/node/_crypto/pbkdf2.ts
@@ -162,19 +162,25 @@ export function pbkdf2(
iterations: number,
keylen: number,
digest: Algorithms = "sha1",
- callback: ((err?: Error, derivedKey?: Buffer) => void),
+ callback: ((err: Error | null, derivedKey?: Buffer) => void),
): void {
- try {
- const res = pbkdf2Sync(
- password,
- salt,
- iterations,
- keylen,
- digest,
- );
-
- callback(undefined, res);
- } catch (e) {
- callback(e);
- }
+ setTimeout(() => {
+ let err = null, res;
+ try {
+ res = pbkdf2Sync(
+ password,
+ salt,
+ iterations,
+ keylen,
+ digest,
+ );
+ } catch (e) {
+ err = e;
+ }
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res);
+ }
+ }, 0);
}
diff --git a/std/node/_crypto/pbkdf2_test.ts b/std/node/_crypto/pbkdf2_test.ts
index 798805ce4..29f149cbe 100644
--- a/std/node/_crypto/pbkdf2_test.ts
+++ b/std/node/_crypto/pbkdf2_test.ts
@@ -3,7 +3,12 @@ import {
pbkdf2,
pbkdf2Sync,
} from "./pbkdf2.ts";
-import { assert, assertEquals } from "../../testing/asserts.ts";
+import {
+ assert,
+ assertEquals,
+ assertStringIncludes,
+} from "../../testing/asserts.ts";
+import { assertCallbackErrorUncaught } from "../_utils.ts";
type Pbkdf2Fixture = {
key: string | Float64Array | Int32Array | Uint8Array;
@@ -412,3 +417,11 @@ Deno.test("pbkdf2Sync hashes data correctly", () => {
}
});
});
+
+Deno.test("[std/node/crypto] pbkdf2 callback isn't called twice if error is thrown", async () => {
+ const importUrl = new URL("./pbkdf2.ts", import.meta.url);
+ await assertCallbackErrorUncaught({
+ prelude: `import { pbkdf2 } from ${JSON.stringify(importUrl)}`,
+ invocation: 'pbkdf2("password", "salt", 1, 32, "sha1", ',
+ });
+});
diff --git a/std/node/_crypto/randomBytes.ts b/std/node/_crypto/randomBytes.ts
index 28c7e454e..335c92d68 100644
--- a/std/node/_crypto/randomBytes.ts
+++ b/std/node/_crypto/randomBytes.ts
@@ -39,8 +39,9 @@ export default function randomBytes(
cb?: (err: Error | null, buf?: Buffer) => void,
): Buffer | void {
if (typeof cb === "function") {
+ let err: Error | null = null, bytes: Buffer;
try {
- cb(null, generateRandomBytes(size));
+ bytes = generateRandomBytes(size);
} catch (e) {
//NodeJS nonsense
//If the size is out of range it will throw sync, otherwise throw async
@@ -50,9 +51,16 @@ export default function randomBytes(
) {
throw e;
} else {
- cb(e);
+ err = e;
}
}
+ setTimeout(() => {
+ if (err) {
+ cb(err);
+ } else {
+ cb(null, bytes);
+ }
+ }, 0);
} else {
return generateRandomBytes(size);
}
diff --git a/std/node/_crypto/randomBytes_test.ts b/std/node/_crypto/randomBytes_test.ts
index 701127dce..6dd2091e1 100644
--- a/std/node/_crypto/randomBytes_test.ts
+++ b/std/node/_crypto/randomBytes_test.ts
@@ -1,4 +1,11 @@
-import { assert, assertEquals, assertThrows } from "../../testing/asserts.ts";
+import {
+ assert,
+ assertEquals,
+ assertStringIncludes,
+ assertThrows,
+ assertThrowsAsync,
+} from "../../testing/asserts.ts";
+import { assertCallbackErrorUncaught } from "../_utils.ts";
import randomBytes, { MAX_RANDOM_VALUES, MAX_SIZE } from "./randomBytes.ts";
Deno.test("randomBytes sync works correctly", function () {
@@ -59,10 +66,24 @@ Deno.test("randomBytes async works correctly", function () {
assert(!err);
})
);
- assertThrows(() =>
- randomBytes(-1, function (err) {
- //Shouldn't throw async
- assert(!err);
+ assertThrowsAsync(() =>
+ new Promise((resolve, reject) => {
+ randomBytes(-1, function (err, res) {
+ //Shouldn't throw async
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res);
+ }
+ });
})
);
});
+
+Deno.test("[std/node/crypto] randomBytes callback isn't called twice if error is thrown", async () => {
+ const importUrl = new URL("./randomBytes.ts", import.meta.url);
+ await assertCallbackErrorUncaught({
+ prelude: `import randomBytes from ${JSON.stringify(importUrl)}`,
+ invocation: "randomBytes(0, ",
+ });
+});