summaryrefslogtreecommitdiff
path: root/tests/node_compat
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-06-24 11:47:12 +0200
committerGitHub <noreply@github.com>2024-06-24 11:47:12 +0200
commit1e8a6b94b1dcf98a2ae4de97b3e98e7b3e4e8f7f (patch)
tree89ae2bc343dea6bf17ca9d512ea80b51540347ca /tests/node_compat
parentff535061077d2b67e20154a7dfefe8ca92502c5a (diff)
fix(ext/node): rewrite crypto.Hash (#24302)
Changes in this PR: - Added new fixed size hash algorithms (blake2b512, blake2s256, sha512-224, sha512-256, sha3-224, sha3-256, sha3-384, sha3-512, sm3) - Added variable size hash algorithms (the concept), with the algorithms shake128 and shake256 - Use cppgc instead of resources for the hasher - Enable Node's crypto.Hash tests and fix found bugs
Diffstat (limited to 'tests/node_compat')
-rw-r--r--tests/node_compat/config.jsonc8
-rw-r--r--tests/node_compat/runner/TODO.md1
-rw-r--r--tests/node_compat/test.ts16
-rw-r--r--tests/node_compat/test/fixtures/sample.pngbin0 -> 9416 bytes
-rw-r--r--tests/node_compat/test/parallel/test-crypto-hash.js285
5 files changed, 299 insertions, 11 deletions
diff --git a/tests/node_compat/config.jsonc b/tests/node_compat/config.jsonc
index 0a661c0a9..83d91eac1 100644
--- a/tests/node_compat/config.jsonc
+++ b/tests/node_compat/config.jsonc
@@ -132,16 +132,17 @@
"tmpdir.js"
],
"fixtures": [
- "GH-1899-output.js",
"a.js",
- "child-process-spawn-node.js",
"child_process_should_emit_error.js",
+ "child-process-spawn-node.js",
"echo.js",
"elipses.txt",
"empty.txt",
"exit.js",
+ "GH-1899-output.js",
"loop.js",
"print-chars.js",
+ "sample.png",
"x.txt"
],
"fixtures/keys": ["agent1-cert.pem", "agent1-key.pem", "ca1-cert.pem"],
@@ -253,6 +254,7 @@
"test-console-tty-colors.js",
"test-crypto-dh-shared.js",
"test-crypto-dh.js",
+ "test-crypto-hash.js",
"test-crypto-hkdf.js",
"test-crypto-hmac.js",
"test-crypto-prime.js",
@@ -701,8 +703,8 @@
"test-zlib-zero-windowBits.js"
],
"pseudo-tty": [
- "console-dumb-tty.js",
"console_colors.js",
+ "console-dumb-tty.js",
"no_dropped_stdio.js",
"no_interleaved_stdio.js",
"test-tty-color-support-warning-2.js",
diff --git a/tests/node_compat/runner/TODO.md b/tests/node_compat/runner/TODO.md
index d5dd2fc7b..24618dc88 100644
--- a/tests/node_compat/runner/TODO.md
+++ b/tests/node_compat/runner/TODO.md
@@ -464,7 +464,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
- [parallel/test-crypto-from-binary.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-from-binary.js)
- [parallel/test-crypto-getcipherinfo.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-getcipherinfo.js)
- [parallel/test-crypto-hash-stream-pipe.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-hash-stream-pipe.js)
-- [parallel/test-crypto-hash.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-hash.js)
- [parallel/test-crypto-key-objects-messageport.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-key-objects-messageport.js)
- [parallel/test-crypto-key-objects.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-key-objects.js)
- [parallel/test-crypto-keygen-async-dsa-key-object.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-keygen-async-dsa-key-object.js)
diff --git a/tests/node_compat/test.ts b/tests/node_compat/test.ts
index 6f15f2d0b..939fdf52a 100644
--- a/tests/node_compat/test.ts
+++ b/tests/node_compat/test.ts
@@ -16,7 +16,7 @@
import { magenta } from "@std/fmt/colors.ts";
import { pooledMap } from "@std/async/pool.ts";
import { dirname, fromFileUrl, join } from "@std/path/mod.ts";
-import { fail } from "@std/assert/mod.ts";
+import { assertEquals, fail } from "@std/assert/mod.ts";
import {
config,
getPathsFromTestSuites,
@@ -169,12 +169,14 @@ Deno.test("Node.js compatibility", async (t) => {
function checkConfigTestFilesOrder(testFileLists: Array<string[]>) {
for (const testFileList of testFileLists) {
const sortedTestList = JSON.parse(JSON.stringify(testFileList));
- sortedTestList.sort();
- if (JSON.stringify(testFileList) !== JSON.stringify(sortedTestList)) {
- throw new Error(
- `File names in \`config.json\` are not correct order.`,
- );
- }
+ sortedTestList.sort((a: string, b: string) =>
+ a.toLowerCase().localeCompare(b.toLowerCase())
+ );
+ assertEquals(
+ testFileList,
+ sortedTestList,
+ "File names in `config.json` are not correct order.",
+ );
}
}
diff --git a/tests/node_compat/test/fixtures/sample.png b/tests/node_compat/test/fixtures/sample.png
new file mode 100644
index 000000000..258622019
--- /dev/null
+++ b/tests/node_compat/test/fixtures/sample.png
Binary files differ
diff --git a/tests/node_compat/test/parallel/test-crypto-hash.js b/tests/node_compat/test/parallel/test-crypto-hash.js
new file mode 100644
index 000000000..18c57dab7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-hash.js
@@ -0,0 +1,285 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+const fs = require('fs');
+
+const fixtures = require('../common/fixtures');
+
+let cryptoType;
+let digest;
+
+// Test hashing
+const a1 = crypto.createHash('sha1').update('Test123').digest('hex');
+const a2 = crypto.createHash('sha256').update('Test123').digest('base64');
+const a3 = crypto.createHash('sha512').update('Test123').digest(); // buffer
+const a4 = crypto.createHash('sha1').update('Test123').digest('buffer');
+
+// stream interface
+let a5 = crypto.createHash('sha512');
+a5.end('Test123');
+a5 = a5.read();
+
+let a6 = crypto.createHash('sha512');
+a6.write('Te');
+a6.write('st');
+a6.write('123');
+a6.end();
+a6 = a6.read();
+
+let a7 = crypto.createHash('sha512');
+a7.end();
+a7 = a7.read();
+
+let a8 = crypto.createHash('sha512');
+a8.write('');
+a8.end();
+a8 = a8.read();
+
+if (!common.hasFipsCrypto) {
+ cryptoType = 'md5';
+ digest = 'latin1';
+ const a0 = crypto.createHash(cryptoType).update('Test123').digest(digest);
+ assert.strictEqual(
+ a0,
+ 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca\u00bd\u008c',
+ `${cryptoType} with ${digest} digest failed to evaluate to expected hash`
+ );
+}
+cryptoType = 'md5';
+digest = 'hex';
+assert.strictEqual(
+ a1,
+ '8308651804facb7b9af8ffc53a33a22d6a1c8ac2',
+ `${cryptoType} with ${digest} digest failed to evaluate to expected hash`);
+cryptoType = 'sha256';
+digest = 'base64';
+assert.strictEqual(
+ a2,
+ '2bX1jws4GYKTlxhloUB09Z66PoJZW+y+hq5R8dnx9l4=',
+ `${cryptoType} with ${digest} digest failed to evaluate to expected hash`);
+cryptoType = 'sha512';
+digest = 'latin1';
+assert.deepStrictEqual(
+ a3,
+ Buffer.from(
+ '\u00c1(4\u00f1\u0003\u001fd\u0097!O\'\u00d4C/&Qz\u00d4' +
+ '\u0094\u0015l\u00b8\u008dQ+\u00db\u001d\u00c4\u00b5}\u00b2' +
+ '\u00d6\u0092\u00a3\u00df\u00a2i\u00a1\u009b\n\n*\u000f' +
+ '\u00d7\u00d6\u00a2\u00a8\u0085\u00e3<\u0083\u009c\u0093' +
+ '\u00c2\u0006\u00da0\u00a1\u00879(G\u00ed\'',
+ 'latin1'),
+ `${cryptoType} with ${digest} digest failed to evaluate to expected hash`);
+cryptoType = 'sha1';
+digest = 'hex';
+assert.deepStrictEqual(
+ a4,
+ Buffer.from('8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'hex'),
+ `${cryptoType} with ${digest} digest failed to evaluate to expected hash`
+);
+
+// Stream interface should produce the same result.
+assert.deepStrictEqual(a5, a3);
+assert.deepStrictEqual(a6, a3);
+assert.notStrictEqual(a7, undefined);
+assert.notStrictEqual(a8, undefined);
+
+// Test multiple updates to same hash
+const h1 = crypto.createHash('sha1').update('Test123').digest('hex');
+const h2 = crypto.createHash('sha1').update('Test').update('123').digest('hex');
+assert.strictEqual(h1, h2);
+
+// Test hashing for binary files
+const fn = fixtures.path('sample.png');
+const sha1Hash = crypto.createHash('sha1');
+const fileStream = fs.createReadStream(fn);
+fileStream.on('data', function(data) {
+ sha1Hash.update(data);
+});
+fileStream.on('close', common.mustCall(function() {
+ // Test SHA1 of sample.png
+ assert.strictEqual(sha1Hash.digest('hex'),
+ '22723e553129a336ad96e10f6aecdf0f45e4149e');
+}));
+
+// Issue https://github.com/nodejs/node-v0.x-archive/issues/2227: unknown digest
+// method should throw an error.
+assert.throws(function() {
+ crypto.createHash('xyzzy');
+}, /Digest method not supported/);
+
+// Issue https://github.com/nodejs/node/issues/9819: throwing encoding used to
+// segfault.
+assert.throws(
+ () => crypto.createHash('sha256').digest({
+ toString: () => { throw new Error('boom'); },
+ }),
+ {
+ name: 'Error',
+ message: 'boom'
+ });
+
+// Issue https://github.com/nodejs/node/issues/25487: error message for invalid
+// arg type to update method should include all possible types
+assert.throws(
+ () => crypto.createHash('sha256').update(),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ });
+
+// Default UTF-8 encoding
+const hutf8 = crypto.createHash('sha512').update('УТФ-8 text').digest('hex');
+assert.strictEqual(
+ hutf8,
+ '4b21bbd1a68e690a730ddcb5a8bc94ead9879ffe82580767ad7ec6fa8ba2dea6' +
+ '43a821af66afa9a45b6a78c712fecf0e56dc7f43aef4bcfc8eb5b4d8dca6ea5b');
+
+assert.notStrictEqual(
+ hutf8,
+ crypto.createHash('sha512').update('УТФ-8 text', 'latin1').digest('hex'));
+
+const h3 = crypto.createHash('sha256');
+h3.digest();
+
+assert.throws(
+ () => h3.digest(),
+ {
+ code: 'ERR_CRYPTO_HASH_FINALIZED',
+ name: 'Error'
+ });
+
+assert.throws(
+ () => h3.update('foo'),
+ {
+ code: 'ERR_CRYPTO_HASH_FINALIZED',
+ name: 'Error'
+ });
+
+assert.strictEqual(
+ crypto.createHash('sha256').update('test').digest('ucs2'),
+ crypto.createHash('sha256').update('test').digest().toString('ucs2'));
+
+assert.throws(
+ () => crypto.createHash(),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "algorithm" argument must be of type string. ' +
+ 'Received undefined'
+ }
+);
+
+{
+ const Hash = crypto.Hash;
+ const instance = crypto.Hash('sha256');
+ assert(instance instanceof Hash, 'Hash is expected to return a new instance' +
+ ' when called without `new`');
+}
+
+// Test XOF hash functions and the outputLength option.
+{
+ // Default outputLengths.
+ assert.strictEqual(crypto.createHash('shake128').digest('hex'),
+ '7f9c2ba4e88f827d616045507605853e');
+ assert.strictEqual(crypto.createHash('shake128', null).digest('hex'),
+ '7f9c2ba4e88f827d616045507605853e');
+ assert.strictEqual(crypto.createHash('shake256').digest('hex'),
+ '46b9dd2b0ba88d13233b3feb743eeb24' +
+ '3fcd52ea62b81b82b50c27646ed5762f');
+ assert.strictEqual(crypto.createHash('shake256', { outputLength: 0 })
+ .copy() // Default outputLength.
+ .digest('hex'),
+ '46b9dd2b0ba88d13233b3feb743eeb24' +
+ '3fcd52ea62b81b82b50c27646ed5762f');
+
+ // Short outputLengths.
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 })
+ .digest('hex'),
+ '');
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 })
+ .copy({ outputLength: 0 })
+ .digest('hex'),
+ '');
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 })
+ .digest('hex'),
+ '7f9c2ba4e8');
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 })
+ .copy({ outputLength: 5 })
+ .digest('hex'),
+ '7f9c2ba4e8');
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 15 })
+ .digest('hex'),
+ '7f9c2ba4e88f827d61604550760585');
+ assert.strictEqual(crypto.createHash('shake256', { outputLength: 16 })
+ .digest('hex'),
+ '46b9dd2b0ba88d13233b3feb743eeb24');
+
+ // Large outputLengths.
+ assert.strictEqual(crypto.createHash('shake128', { outputLength: 128 })
+ .digest('hex'),
+ '7f9c2ba4e88f827d616045507605853e' +
+ 'd73b8093f6efbc88eb1a6eacfa66ef26' +
+ '3cb1eea988004b93103cfb0aeefd2a68' +
+ '6e01fa4a58e8a3639ca8a1e3f9ae57e2' +
+ '35b8cc873c23dc62b8d260169afa2f75' +
+ 'ab916a58d974918835d25e6a435085b2' +
+ 'badfd6dfaac359a5efbb7bcc4b59d538' +
+ 'df9a04302e10c8bc1cbf1a0b3a5120ea');
+ const superLongHash = crypto.createHash('shake256', {
+ outputLength: 1024 * 1024
+ }).update('The message is shorter than the hash!')
+ .digest('hex');
+ assert.strictEqual(superLongHash.length, 2 * 1024 * 1024);
+ assert.ok(superLongHash.endsWith('193414035ddba77bf7bba97981e656ec'));
+ assert.ok(superLongHash.startsWith('a2a28dbc49cfd6e5d6ceea3d03e77748'));
+
+ // Non-XOF hash functions should accept valid outputLength options as well.
+ assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 })
+ .digest('hex'),
+ 'd14a028c2a3a2bc9476102bb288234c4' +
+ '15a2b01f828ea62ac5b3e42f');
+
+ // Passing invalid sizes should throw during creation.
+ assert.throws(() => {
+ crypto.createHash('sha256', { outputLength: 28 });
+ }, {
+ code: 'ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH'
+ });
+
+ for (const outputLength of [null, {}, 'foo', false]) {
+ assert.throws(() => crypto.createHash('sha256', { outputLength }),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ }
+
+ for (const outputLength of [-1, .5, Infinity, 2 ** 90]) {
+ assert.throws(() => crypto.createHash('sha256', { outputLength }),
+ { code: 'ERR_OUT_OF_RANGE' });
+ }
+}
+
+{
+ const h = crypto.createHash('sha512');
+ h.digest();
+ assert.throws(() => h.copy(), { code: 'ERR_CRYPTO_HASH_FINALIZED' });
+ assert.throws(() => h.digest(), { code: 'ERR_CRYPTO_HASH_FINALIZED' });
+}
+
+{
+ const a = crypto.createHash('sha512').update('abc');
+ const b = a.copy();
+ const c = b.copy().update('def');
+ const d = crypto.createHash('sha512').update('abcdef');
+ assert.strictEqual(a.digest('hex'), b.digest('hex'));
+ assert.strictEqual(c.digest('hex'), d.digest('hex'));
+}