Skip to content

Commit

Permalink
Fix path Esbuild config to run all browser tests (#441)
Browse files Browse the repository at this point in the history
* Fix path in esbuild-tests.cjs
* Fix failing tests in dids package
* Fix failing tests under Chrome

---------

Signed-off-by: Frank Hinek <[email protected]>
  • Loading branch information
frankhinek authored Mar 12, 2024
1 parent a4fc1cf commit 7442465
Show file tree
Hide file tree
Showing 19 changed files with 117 additions and 68 deletions.
2 changes: 1 addition & 1 deletion packages/agent/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
2 changes: 1 addition & 1 deletion packages/api/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
2 changes: 1 addition & 1 deletion packages/common/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
2 changes: 1 addition & 1 deletion packages/credentials/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
2 changes: 1 addition & 1 deletion packages/crypto/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
24 changes: 16 additions & 8 deletions packages/crypto/src/primitives/aes-gcm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,14 @@ export class AesGcm {
// Import the JWK into the Web Crypto API to use for the decrypt operation.
const webCryptoKey = await webCrypto.importKey('jwk', key, { name: 'AES-GCM' }, true, ['decrypt']);

// Browser implementations of the Web Crypto API throw an error if additionalData is undefined.
const algorithm = (additionalData === undefined)
? { name: 'AES-GCM', iv, tagLength }
: { name: 'AES-GCM', additionalData, iv, tagLength };
// Note: Some browser implementations of the Web Crypto API throw an error if additionalData or
// tagLength are undefined, so only include them in the algorithm object if they are defined.
const algorithm = {
name: 'AES-GCM',
iv,
...(tagLength && { tagLength }),
...(additionalData && { additionalData})
};

// Decrypt the data.
const plaintextBuffer = await webCrypto.decrypt(algorithm, webCryptoKey, data);
Expand Down Expand Up @@ -269,10 +273,14 @@ export class AesGcm {
// Import the JWK into the Web Crypto API to use for the encrypt operation.
const webCryptoKey = await webCrypto.importKey('jwk', key, { name: 'AES-GCM' }, true, ['encrypt']);

// Browser implementations of the Web Crypto API throw an error if additionalData is undefined.
const algorithm = (additionalData === undefined)
? { name: 'AES-GCM', iv, tagLength }
: { name: 'AES-GCM', additionalData, iv, tagLength };
// Note: Some browser implementations of the Web Crypto API throw an error if additionalData or
// tagLength are undefined, so only include them in the algorithm object if they are defined.
const algorithm = {
name: 'AES-GCM',
iv,
...(tagLength && { tagLength }),
...(additionalData && { additionalData})
};

// Encrypt the data.
const ciphertextBuffer = await webCrypto.encrypt(algorithm, webCryptoKey, data);
Expand Down
15 changes: 11 additions & 4 deletions packages/crypto/tests/algorithms/aes-ctr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Convert } from '@web5/common';

import type { Jwk } from '../../src/jose/jwk.js';

import { isChrome } from '../utils/runtimes.js';
import { randomBytes } from '../../src/utils.js';
import { AesCtrAlgorithm } from '../../src/algorithms/aes-ctr.js';

Expand Down Expand Up @@ -67,18 +68,24 @@ describe('AesCtrAlgorithm', () => {
expect(privateKey).to.have.property('kty', 'oct');
});

it(`supports 'A128CTR', 'A192CTR', and 'A256CTR' algorithms`, async () => {
const algorithms = ['A128CTR', 'A192CTR', 'A256CTR'] as const;
it(`supports 'A128CTR' and 'A256CTR' algorithms in all supported runtimes`, async () => {
const algorithms = ['A128CTR', 'A256CTR'] as const;
for (const algorithm of algorithms) {
const privateKey = await aesCtr.generateKey({ algorithm });
expect(privateKey).to.have.property('alg', algorithm);
if (!privateKey.k) throw new Error('Expected privateKey to have a `k` property'); // TypeScript type guard.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength * 8).to.equal(parseInt(algorithm.slice(1, 4)));
}
});

it(`returns keys with the correct bit length`, async () => {
const algorithms = ['A128CTR', 'A192CTR', 'A256CTR'] as const;
it(`supports 'A192CTR' algorithm in all supported runtimes except Chrome browser`, async function () {
if (isChrome) this.skip();

const algorithms = ['A192CTR'] as const;
for (const algorithm of algorithms) {
const privateKey = await aesCtr.generateKey({ algorithm });
expect(privateKey).to.have.property('alg', algorithm);
if (!privateKey.k) throw new Error('Expected privateKey to have a `k` property'); // TypeScript type guard.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength * 8).to.equal(parseInt(algorithm.slice(1, 4)));
Expand Down
15 changes: 11 additions & 4 deletions packages/crypto/tests/algorithms/aes-gcm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Convert } from '@web5/common';

import type { Jwk } from '../../src/jose/jwk.js';

import { isChrome } from '../utils/runtimes.js';
import { randomBytes } from '../../src/utils.js';
import { AesGcmAlgorithm } from '../../src/algorithms/aes-gcm.js';

Expand Down Expand Up @@ -68,18 +69,24 @@ describe('AesGcmAlgorithm', () => {
expect(privateKey).to.have.property('kty', 'oct');
});

it(`supports 'A128GCM', 'A192GCM', and 'A256GCM' algorithms`, async () => {
const algorithms = ['A128GCM', 'A192GCM', 'A256GCM'] as const;
it(`supports 'A128GCM' and 'A256GCM' algorithms in all supported runtimes`, async () => {
const algorithms = ['A128GCM', 'A256GCM'] as const;
for (const algorithm of algorithms) {
const privateKey = await aesGcm.generateKey({ algorithm });
expect(privateKey).to.have.property('alg', algorithm);
if (!privateKey.k) throw new Error('Expected privateKey to have a `k` property'); // TypeScript type guard.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength * 8).to.equal(parseInt(algorithm.slice(1, 4)));
}
});

it(`returns keys with the correct bit length`, async () => {
const algorithms = ['A128GCM', 'A192GCM', 'A256GCM'] as const;
it(`supports 'A192GCM' algorithm in all supported runtimes except Chrome browser`, async function () {
if (isChrome) this.skip();

const algorithms = ['A192GCM'] as const;
for (const algorithm of algorithms) {
const privateKey = await aesGcm.generateKey({ algorithm });
expect(privateKey).to.have.property('alg', algorithm);
if (!privateKey.k) throw new Error('Expected privateKey to have a `k` property'); // TypeScript type guard.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength * 8).to.equal(parseInt(algorithm.slice(1, 4)));
Expand Down
30 changes: 22 additions & 8 deletions packages/crypto/tests/primitives/aes-ctr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import chaiAsPromised from 'chai-as-promised';

import type { Jwk, JwkParamsOctPrivate } from '../../src/jose/jwk.js';

import { isChrome } from '../utils/runtimes.js';
import { AesCtr } from '../../src/primitives/aes-ctr.js';
import AesCtrDecryptTestVector from '../fixtures/test-vectors/aes-ctr/decrypt.json' assert { type: 'json' };
import AesCtrEncryptTestVector from '../fixtures/test-vectors/aes-ctr/encrypt.json' assert { type: 'json' };
Expand Down Expand Up @@ -45,10 +46,13 @@ describe('AesCtr', () => {
});

for (const vector of AesCtrDecryptTestVector.vectors) {
it(vector.description, async () => {
it(vector.description, async function () {
const privateKeyBytes = Convert.hex(vector.input.key).toUint8Array();
const privateKey = await AesCtr.bytesToPrivateKey({ privateKeyBytes });

// Skip the test if the key length is 192 bits and the runtime is Chrome browser.
if (isChrome && privateKeyBytes.length === 24) this.skip();

const ciphertext = await AesCtr.decrypt({
key : privateKey,
data : Convert.hex(vector.input.data).toUint8Array(),
Expand Down Expand Up @@ -112,10 +116,13 @@ describe('AesCtr', () => {
});

for (const vector of AesCtrEncryptTestVector.vectors) {
it(vector.description, async () => {
it(vector.description, async function () {
const privateKeyBytes = Convert.hex(vector.input.key).toUint8Array();
const privateKey = await AesCtr.bytesToPrivateKey({ privateKeyBytes });

// Skip the test if the key length is 192 bits and the runtime is Chrome browser.
if (isChrome && privateKeyBytes.length === 24) this.skip();

const ciphertext = await AesCtr.encrypt({
key : privateKey,
data : Convert.hex(vector.input.data).toUint8Array(),
Expand Down Expand Up @@ -176,7 +183,7 @@ describe('AesCtr', () => {
expect(privateKey).to.have.property('kty', 'oct');
});

it('supports key lengths of 128, 192, or 256 bits', async () => {
it('supports key lengths of 128 and 256 bits in all supported runtimes', async () => {
let privateKey: Jwk;
let privateKeyBytes: Uint8Array;

Expand All @@ -185,17 +192,24 @@ describe('AesCtr', () => {
privateKeyBytes = Convert.base64Url(privateKey.k!).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(16);

// 192 bits
privateKey = await AesCtr.generateKey({ length: 192 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k!).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(24);

// 256 bits
privateKey = await AesCtr.generateKey({ length: 256 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k!).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(32);
});

it('supports key lengths of 192 bits in all supported runtimes except Chrome browser', async function () {
if (isChrome) this.skip();

let privateKey: Jwk;
let privateKeyBytes: Uint8Array;

// 192 bits
privateKey = await AesCtr.generateKey({ length: 192 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k!).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(24);
});

it('throws an error if the key length is invalid', async () => {
for (const length of [32, 64, 100, 512]) {
try {
Expand Down
20 changes: 14 additions & 6 deletions packages/crypto/tests/primitives/aes-gcm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import chaiAsPromised from 'chai-as-promised';

import type { Jwk, JwkParamsOctPrivate } from '../../src/jose/jwk.js';

import { isChrome } from '../utils/runtimes.js';
import { AesGcm, AES_GCM_TAG_LENGTHS } from '../../src/primitives/aes-gcm.js';
import AesGcmDecryptTestVector from '../fixtures/test-vectors/aes-gcm/decrypt.json' assert { type: 'json' };
import AesGcmEncryptTestVector from '../fixtures/test-vectors/aes-gcm/encrypt.json' assert { type: 'json' };
Expand Down Expand Up @@ -229,7 +230,7 @@ describe('AesGcm', () => {
expect(privateKey).to.have.property('kty', 'oct');
});

it('supports key lengths of 128, 192, or 256 bits', async () => {
it('supports key lengths of 128 and 256 bits in all supported runtimes', async () => {
let privateKey: JwkParamsOctPrivate;
let privateKeyBytes: Uint8Array;

Expand All @@ -238,17 +239,24 @@ describe('AesGcm', () => {
privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(16);

// 192 bits
privateKey = await AesGcm.generateKey({ length: 192 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(24);

// 256 bits
privateKey = await AesGcm.generateKey({ length: 256 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(32);
});

it('supports key lengths of 192 bits in all supported runtimes except Chrome browser', async function () {
if (isChrome) this.skip();

let privateKey: JwkParamsOctPrivate;
let privateKeyBytes: Uint8Array;

// 192 bits
privateKey = await AesGcm.generateKey({ length: 192 }) as JwkParamsOctPrivate;
privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
expect(privateKeyBytes.byteLength).to.equal(24);
});

it('throws an error if the key length is invalid', async () => {
for (const length of [32, 64, 100, 512]) {
try {
Expand Down
1 change: 1 addition & 0 deletions packages/crypto/tests/utils/runtimes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isChrome = typeof navigator !== 'undefined' && /Chrome/.test(navigator.userAgent);
2 changes: 1 addition & 1 deletion packages/dids/build/esbuild-tests.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const browserConfig = require('./esbuild-browser-config.cjs');
esbuild.build({
...browserConfig,
format : 'esm',
entryPoints : ['./tests/*.spec.*'],
entryPoints : ['./tests/**/*.spec.*'],
bundle : true,
minify : false,
outdir : 'tests/compiled',
Expand Down
2 changes: 0 additions & 2 deletions packages/dids/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
"@playwright/test": "1.40.1",
"@types/bencode": "2.0.4",
"@types/chai": "4.3.6",
"@types/chai-as-promised": "7.1.5",
"@types/eslint": "8.44.2",
"@types/mocha": "10.0.1",
"@types/ms": "0.7.31",
Expand All @@ -101,7 +100,6 @@
"@web/test-runner-playwright": "0.11.0",
"c8": "9.0.0",
"chai": "4.3.10",
"chai-as-promised": "7.1.1",
"esbuild": "0.19.8",
"eslint": "8.47.0",
"eslint-plugin-mocha": "10.1.0",
Expand Down
31 changes: 20 additions & 11 deletions packages/dids/tests/methods/did-key.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,13 @@ describe('DidKey', () => {
});

it('throws an error if unsupported JOSE has been passed', async () => {
await expect(
try {
// @ts-expect-error because parameters are intentionally omitted to trigger an error.
DidKeyUtils.jwkToMulticodec({ jwk: { crv: '123' } })
).to.eventually.be.rejectedWith(Error, `Unsupported JWK to Multicodec conversion: '123:public'`);
await DidKeyUtils.jwkToMulticodec({ jwk: { crv: '123' } });
expect.fail('Expected an error to be thrown.');
} catch (error: any) {
expect(error.message).to.include(`Unsupported JWK to Multicodec conversion: '123:public'`);
}
});
});

Expand Down Expand Up @@ -658,28 +661,34 @@ describe('DidKey', () => {
});

it('throws an error for an unsupported public key type', async () => {
await expect(
DidKeyUtils.publicKeyToMultibaseId({
try {
await DidKeyUtils.publicKeyToMultibaseId({
publicKey: {
kty : 'RSA',
n : 'r0YDzIV4GPJ1wFb1Gftdd3C3VE6YeknVq1C7jGypq5WTTmX0yRDBqzL6mBR3_c-mKRuE5Z5VMGniA1lFnFmv8m0A2engKfALXHPJqoL6WzqN1SyjSM2aI6v8JVTj4H0RdYV9R4jxIB-zK5X-ZyL6CwHx-3dKZkCvZSEp8b-5I8c2Fz8E8Hl7qKkD_qEz6ZOmKVhJLGiEag1qUQYJv2TcRdiyZfwwVsV3nI3IcVfMCTjDZTw2jI0YHJgLi7-MkP4DO7OJ4D4AFtL-7CkZ7V2xG0piBz4b02_-ZGnBZ5zHJxGoUZnTY6HX4V9bPQI_ME8qCjFXf-TcwCfDFcwMm70L2Q',
e : 'AQAB',
alg : 'RS256'
}
})
).to.eventually.be.rejectedWith(Error, `unsupported key type`);
});
expect.fail('Expected an error to be thrown.');
} catch (error: any) {
expect(error.message).to.include('unsupported key type');
}
});

it('throws an error for an unsupported public key curve', async () => {
await expect(
DidKeyUtils.publicKeyToMultibaseId({
try {
await DidKeyUtils.publicKeyToMultibaseId({
publicKey: {
kty : 'EC',
crv : 'BLS12381_G1',
x : 'mIT3NuXBB_VeJUaV15hwBbMtBrMaTWcN4gnDfkzX-VuUZg3vnpB9RxxaC6vkTgJ2'
}
})
).to.eventually.be.rejectedWith(Error, `unsupported key type`);
});
expect.fail('Expected an error to be thrown.');
} catch (error: any) {
expect(error.message).to.include('unsupported key type');
}
});
});
});
Expand Down
Loading

0 comments on commit 7442465

Please sign in to comment.