Skip to content

Commit 7f4fb3a

Browse files
committed
2 parents 7ca917c + 505e15b commit 7f4fb3a

File tree

13 files changed

+88
-69
lines changed

13 files changed

+88
-69
lines changed

.editorconfig

+5
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ charset = utf-8
77
insert_final_newline = true
88
end_of_line = lf
99
trim_trailing_whitespace = true
10+
11+
[*.{yml,yaml}]
12+
indent_style = space
13+
indent_size = 2
14+
trim_trailing_whitespace = false

.github/workflows/test.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88

99
strategy:
1010
matrix:
11-
node-version: [20.10.0]
11+
node-version: [18.x, 20.x, 21.x]
1212

1313
steps:
1414
- uses: actions/checkout@v4
@@ -32,3 +32,6 @@ jobs:
3232
- name: Test
3333
run: |
3434
pnpm test
35+
- name: Performance
36+
run: |
37+
pnpm performance

dist/draft/sign.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// <reference types="node" />
2-
import type { webcrypto as crypto } from 'node:crypto';
2+
import type { webcrypto } from 'node:crypto';
33
import type { PrivateKey, RequestLike, SignInfo, SignatureHashAlgorithmUpperSnake } from '../types.js';
44
export declare function getDraftAlgoString(algorithm: SignInfo): string;
55
export declare function genDraftSigningString(request: RequestLike, includeHeaders: string[], additional?: {
@@ -9,7 +9,7 @@ export declare function genDraftSigningString(request: RequestLike, includeHeade
99
expires?: string;
1010
opaque?: string;
1111
}): string;
12-
export declare function genDraftSignature(privateKey: crypto.CryptoKey, signingString: string): Promise<string>;
12+
export declare function genDraftSignature(privateKey: webcrypto.CryptoKey, signingString: string): Promise<string>;
1313
export declare function genDraftSignatureHeader(includeHeaders: string[], keyId: string, signature: string, algorithm: string): string;
1414
export declare function signAsDraftToRequest(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
1515
hashAlgorithm?: SignatureHashAlgorithmUpperSnake;

dist/index.cjs

+16-13
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ __export(src_exports, {
6767
getDraftAlgoString: () => getDraftAlgoString,
6868
getNistCurveFromOid: () => getNistCurveFromOid,
6969
getPublicKeyAlgorithmNameFromOid: () => getPublicKeyAlgorithmNameFromOid,
70+
getWebcrypto: () => getWebcrypto,
7071
keyHashAlgosForDraftDecoding: () => keyHashAlgosForDraftDecoding,
7172
keyHashAlgosForDraftEncofing: () => keyHashAlgosForDraftEncofing,
7273
lcObjectGet: () => lcObjectGet,
@@ -263,6 +264,9 @@ function parsePublicKey(input) {
263264
}
264265

265266
// src/utils.ts
267+
async function getWebcrypto() {
268+
return globalThis.crypto ?? (await import("node:crypto")).webcrypto;
269+
}
266270
function lcObjectKey(src) {
267271
return Object.entries(src).reduce((dst, [key, value]) => {
268272
if (key === "__proto__")
@@ -455,7 +459,7 @@ function genDraftSigningString(request, includeHeaders, additional) {
455459
return results.join("\n");
456460
}
457461
async function genDraftSignature(privateKey, signingString) {
458-
const signatureAB = await globalThis.crypto.subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
462+
const signatureAB = await (await getWebcrypto()).subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
459463
return encodeArrayBufferToBase64(signatureAB);
460464
}
461465
function genDraftSignatureHeader(includeHeaders, keyId, signature, algorithm) {
@@ -465,7 +469,7 @@ async function signAsDraftToRequest(request, key, includeHeaders, opts = {}) {
465469
const hash = opts?.hashAlgorithm || "SHA-256";
466470
const parsedPrivateKey = parsePkcs8(key.privateKeyPem);
467471
const importParams = genSignInfo(parsedPrivateKey, { hash, ec: "DSA" });
468-
const privateKey = await globalThis.crypto.subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
472+
const privateKey = await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
469473
const algoString = getDraftAlgoString(importParams);
470474
const signingString = genDraftSigningString(request, includeHeaders, { keyId: key.keyId, algorithm: algoString });
471475
const signature = await genDraftSignature(privateKey, signingString);
@@ -722,15 +726,15 @@ function parseRequestSignature(request, options) {
722726

723727
// src/keypair.ts
724728
async function exportPublicKeyPem(key) {
725-
const ab = await globalThis.crypto.subtle.exportKey("spki", key);
729+
const ab = await (await getWebcrypto()).subtle.exportKey("spki", key);
726730
return "-----BEGIN PUBLIC KEY-----\n" + splitPer64Chars(encodeArrayBufferToBase64(ab)).join("\n") + "\n-----END PUBLIC KEY-----\n";
727731
}
728732
async function exportPrivateKeyPem(key) {
729-
const ab = await globalThis.crypto.subtle.exportKey("pkcs8", key);
733+
const ab = await (await getWebcrypto()).subtle.exportKey("pkcs8", key);
730734
return "-----BEGIN PRIVATE KEY-----\n" + splitPer64Chars(encodeArrayBufferToBase64(ab)).join("\n") + "\n-----END PRIVATE KEY-----\n";
731735
}
732736
async function genRsaKeyPair(modulusLength = 4096, keyUsage = ["sign", "verify"]) {
733-
const keyPair = await globalThis.crypto.subtle.generateKey(
737+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
734738
{
735739
name: "RSASSA-PKCS1-v1_5",
736740
modulusLength,
@@ -746,7 +750,7 @@ async function genRsaKeyPair(modulusLength = 4096, keyUsage = ["sign", "verify"]
746750
};
747751
}
748752
async function genEcKeyPair(namedCurve = "P-256", keyUsage = ["sign", "verify"]) {
749-
const keyPair = await globalThis.crypto.subtle.generateKey(
753+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
750754
{
751755
name: "ECDSA",
752756
namedCurve
@@ -760,7 +764,7 @@ async function genEcKeyPair(namedCurve = "P-256", keyUsage = ["sign", "verify"])
760764
};
761765
}
762766
async function genEd25519KeyPair(keyUsage = ["sign", "verify"]) {
763-
const keyPair = await globalThis.crypto.subtle.generateKey(
767+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
764768
{
765769
name: "Ed25519"
766770
},
@@ -773,7 +777,7 @@ async function genEd25519KeyPair(keyUsage = ["sign", "verify"]) {
773777
};
774778
}
775779
async function genEd448KeyPair(keyUsage) {
776-
const keyPair = await globalThis.crypto.subtle.generateKey(
780+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
777781
{
778782
name: "Ed448"
779783
},
@@ -787,7 +791,6 @@ async function genEd448KeyPair(keyUsage) {
787791
}
788792

789793
// src/digest/utils.ts
790-
var import_node_crypto = require("node:crypto");
791794
async function createBase64Digest(body, hash = "SHA-256") {
792795
if (Array.isArray(hash)) {
793796
return new Map(await Promise.all(hash.map((h) => {
@@ -800,7 +803,7 @@ async function createBase64Digest(body, hash = "SHA-256") {
800803
if (typeof body === "string") {
801804
body = new TextEncoder().encode(body);
802805
}
803-
const hashAb = await import_node_crypto.webcrypto.subtle.digest(hash, body);
806+
const hashAb = await (await getWebcrypto()).subtle.digest(hash, body);
804807
return encodeArrayBufferToBase64(hashAb);
805808
}
806809

@@ -851,7 +854,6 @@ async function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true
851854
}
852855
throw e;
853856
}
854-
;
855857
if (hash !== value) {
856858
if (errorLogger)
857859
errorLogger(`Digest header hash mismatch`);
@@ -959,8 +961,8 @@ var genSignInfoDraft = parseSignInfo;
959961
async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
960962
try {
961963
const parsedSpki = parsePublicKey(publicKeyPem);
962-
const publicKey = await globalThis.crypto.subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
963-
const verify = await globalThis.crypto.subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
964+
const publicKey = await (await getWebcrypto()).subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
965+
const verify = await (await getWebcrypto()).subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
964966
return verify;
965967
} catch (e) {
966968
if (errorLogger)
@@ -1007,6 +1009,7 @@ async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
10071009
getDraftAlgoString,
10081010
getNistCurveFromOid,
10091011
getPublicKeyAlgorithmNameFromOid,
1012+
getWebcrypto,
10101013
keyHashAlgosForDraftDecoding,
10111014
keyHashAlgosForDraftEncofing,
10121015
lcObjectGet,

dist/index.mjs

+15-13
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ function parsePublicKey(input) {
167167
}
168168

169169
// src/utils.ts
170+
async function getWebcrypto() {
171+
return globalThis.crypto ?? (await import("node:crypto")).webcrypto;
172+
}
170173
function lcObjectKey(src) {
171174
return Object.entries(src).reduce((dst, [key, value]) => {
172175
if (key === "__proto__")
@@ -359,7 +362,7 @@ function genDraftSigningString(request, includeHeaders, additional) {
359362
return results.join("\n");
360363
}
361364
async function genDraftSignature(privateKey, signingString) {
362-
const signatureAB = await globalThis.crypto.subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
365+
const signatureAB = await (await getWebcrypto()).subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
363366
return encodeArrayBufferToBase64(signatureAB);
364367
}
365368
function genDraftSignatureHeader(includeHeaders, keyId, signature, algorithm) {
@@ -369,7 +372,7 @@ async function signAsDraftToRequest(request, key, includeHeaders, opts = {}) {
369372
const hash = opts?.hashAlgorithm || "SHA-256";
370373
const parsedPrivateKey = parsePkcs8(key.privateKeyPem);
371374
const importParams = genSignInfo(parsedPrivateKey, { hash, ec: "DSA" });
372-
const privateKey = await globalThis.crypto.subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
375+
const privateKey = await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
373376
const algoString = getDraftAlgoString(importParams);
374377
const signingString = genDraftSigningString(request, includeHeaders, { keyId: key.keyId, algorithm: algoString });
375378
const signature = await genDraftSignature(privateKey, signingString);
@@ -626,15 +629,15 @@ function parseRequestSignature(request, options) {
626629

627630
// src/keypair.ts
628631
async function exportPublicKeyPem(key) {
629-
const ab = await globalThis.crypto.subtle.exportKey("spki", key);
632+
const ab = await (await getWebcrypto()).subtle.exportKey("spki", key);
630633
return "-----BEGIN PUBLIC KEY-----\n" + splitPer64Chars(encodeArrayBufferToBase64(ab)).join("\n") + "\n-----END PUBLIC KEY-----\n";
631634
}
632635
async function exportPrivateKeyPem(key) {
633-
const ab = await globalThis.crypto.subtle.exportKey("pkcs8", key);
636+
const ab = await (await getWebcrypto()).subtle.exportKey("pkcs8", key);
634637
return "-----BEGIN PRIVATE KEY-----\n" + splitPer64Chars(encodeArrayBufferToBase64(ab)).join("\n") + "\n-----END PRIVATE KEY-----\n";
635638
}
636639
async function genRsaKeyPair(modulusLength = 4096, keyUsage = ["sign", "verify"]) {
637-
const keyPair = await globalThis.crypto.subtle.generateKey(
640+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
638641
{
639642
name: "RSASSA-PKCS1-v1_5",
640643
modulusLength,
@@ -650,7 +653,7 @@ async function genRsaKeyPair(modulusLength = 4096, keyUsage = ["sign", "verify"]
650653
};
651654
}
652655
async function genEcKeyPair(namedCurve = "P-256", keyUsage = ["sign", "verify"]) {
653-
const keyPair = await globalThis.crypto.subtle.generateKey(
656+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
654657
{
655658
name: "ECDSA",
656659
namedCurve
@@ -664,7 +667,7 @@ async function genEcKeyPair(namedCurve = "P-256", keyUsage = ["sign", "verify"])
664667
};
665668
}
666669
async function genEd25519KeyPair(keyUsage = ["sign", "verify"]) {
667-
const keyPair = await globalThis.crypto.subtle.generateKey(
670+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
668671
{
669672
name: "Ed25519"
670673
},
@@ -677,7 +680,7 @@ async function genEd25519KeyPair(keyUsage = ["sign", "verify"]) {
677680
};
678681
}
679682
async function genEd448KeyPair(keyUsage) {
680-
const keyPair = await globalThis.crypto.subtle.generateKey(
683+
const keyPair = await (await getWebcrypto()).subtle.generateKey(
681684
{
682685
name: "Ed448"
683686
},
@@ -691,7 +694,6 @@ async function genEd448KeyPair(keyUsage) {
691694
}
692695

693696
// src/digest/utils.ts
694-
import { webcrypto as crypto } from "node:crypto";
695697
async function createBase64Digest(body, hash = "SHA-256") {
696698
if (Array.isArray(hash)) {
697699
return new Map(await Promise.all(hash.map((h) => {
@@ -704,7 +706,7 @@ async function createBase64Digest(body, hash = "SHA-256") {
704706
if (typeof body === "string") {
705707
body = new TextEncoder().encode(body);
706708
}
707-
const hashAb = await crypto.subtle.digest(hash, body);
709+
const hashAb = await (await getWebcrypto()).subtle.digest(hash, body);
708710
return encodeArrayBufferToBase64(hashAb);
709711
}
710712

@@ -755,7 +757,6 @@ async function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true
755757
}
756758
throw e;
757759
}
758-
;
759760
if (hash !== value) {
760761
if (errorLogger)
761762
errorLogger(`Digest header hash mismatch`);
@@ -863,8 +864,8 @@ var genSignInfoDraft = parseSignInfo;
863864
async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
864865
try {
865866
const parsedSpki = parsePublicKey(publicKeyPem);
866-
const publicKey = await globalThis.crypto.subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
867-
const verify = await globalThis.crypto.subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
867+
const publicKey = await (await getWebcrypto()).subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
868+
const verify = await (await getWebcrypto()).subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
868869
return verify;
869870
} catch (e) {
870871
if (errorLogger)
@@ -910,6 +911,7 @@ export {
910911
getDraftAlgoString,
911912
getNistCurveFromOid,
912913
getPublicKeyAlgorithmNameFromOid,
914+
getWebcrypto,
913915
keyHashAlgosForDraftDecoding,
914916
keyHashAlgosForDraftEncofing,
915917
lcObjectGet,

dist/keypair.d.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
/// <reference types="node" />
2-
import type { webcrypto as crypto } from 'node:crypto';
2+
import { webcrypto } from 'node:crypto';
33
import { ECNamedCurve } from './types';
4-
export declare function exportPublicKeyPem(key: crypto.CryptoKey): Promise<string>;
5-
export declare function exportPrivateKeyPem(key: crypto.CryptoKey): Promise<string>;
6-
export declare function genRsaKeyPair(modulusLength?: number, keyUsage?: crypto.KeyUsage[]): Promise<{
4+
export declare function exportPublicKeyPem(key: webcrypto.CryptoKey): Promise<string>;
5+
export declare function exportPrivateKeyPem(key: webcrypto.CryptoKey): Promise<string>;
6+
export declare function genRsaKeyPair(modulusLength?: number, keyUsage?: webcrypto.KeyUsage[]): Promise<{
77
publicKey: string;
88
privateKey: string;
99
}>;
10-
export declare function genEcKeyPair(namedCurve?: ECNamedCurve, keyUsage?: crypto.KeyUsage[]): Promise<{
10+
export declare function genEcKeyPair(namedCurve?: ECNamedCurve, keyUsage?: webcrypto.KeyUsage[]): Promise<{
1111
publicKey: string;
1212
privateKey: string;
1313
}>;
14-
export declare function genEd25519KeyPair(keyUsage?: crypto.KeyUsage[]): Promise<{
14+
export declare function genEd25519KeyPair(keyUsage?: webcrypto.KeyUsage[]): Promise<{
1515
publicKey: string;
1616
privateKey: string;
1717
}>;

dist/utils.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
/// <reference types="node" />
12
import type { SignInfo, SignatureHashAlgorithmUpperSnake } from './types.js';
23
import { ParsedAlgorithmIdentifier } from './pem/spki.js';
4+
export declare function getWebcrypto(): Promise<import("crypto").webcrypto.Crypto>;
35
/**
46
* Convert object keys to lowercase
57
*/

src/digest/utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { webcrypto as crypto } from 'node:crypto';
22
import { DigestHashAlgorithm } from '../types';
3-
import { encodeArrayBufferToBase64 } from '../utils';
3+
import { encodeArrayBufferToBase64, getWebcrypto } from '../utils';
44

55
export type DigestSource = crypto.BufferSource | string;
66

@@ -23,6 +23,6 @@ export async function createBase64Digest(
2323
if (typeof body === 'string') {
2424
body = (new TextEncoder()).encode(body);
2525
}
26-
const hashAb = await crypto.subtle.digest(hash, body);
26+
const hashAb = await (await getWebcrypto()).subtle.digest(hash, body);
2727
return encodeArrayBufferToBase64(hashAb);
2828
}

src/draft/sign.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { webcrypto as crypto } from 'node:crypto';
1+
import type { webcrypto } from 'node:crypto';
22
import type { PrivateKey, RequestLike, SignInfo, SignatureHashAlgorithmUpperSnake } from '../types.js';
3-
import { encodeArrayBufferToBase64, genSignInfo, lcObjectKey } from '../utils.js';
3+
import { encodeArrayBufferToBase64, genSignInfo, getWebcrypto, lcObjectKey } from '../utils.js';
44
import { parsePkcs8 } from '../pem/pkcs8.js';
55
import { keyHashAlgosForDraftEncofing } from './const.js';
66

@@ -72,8 +72,8 @@ export function genDraftSigningString(
7272
return results.join('\n');
7373
}
7474

75-
export async function genDraftSignature(privateKey: crypto.CryptoKey, signingString: string) {
76-
const signatureAB = await globalThis.crypto.subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
75+
export async function genDraftSignature(privateKey: webcrypto.CryptoKey, signingString: string) {
76+
const signatureAB = await (await getWebcrypto()).subtle.sign(privateKey.algorithm, privateKey, new TextEncoder().encode(signingString));
7777
return encodeArrayBufferToBase64(signatureAB);
7878
}
7979

@@ -86,7 +86,7 @@ export async function signAsDraftToRequest(request: RequestLike, key: PrivateKey
8686

8787
const parsedPrivateKey = parsePkcs8(key.privateKeyPem);
8888
const importParams = genSignInfo(parsedPrivateKey, { hash, ec: 'DSA' });
89-
const privateKey = await globalThis.crypto.subtle.importKey('pkcs8', parsedPrivateKey.der, importParams, false, ['sign']);
89+
const privateKey = await (await getWebcrypto()).subtle.importKey('pkcs8', parsedPrivateKey.der, importParams, false, ['sign']);
9090
const algoString = getDraftAlgoString(importParams);
9191

9292
const signingString = genDraftSigningString(request, includeHeaders, { keyId: key.keyId, algorithm: algoString });

src/draft/verify.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ParsedDraftSignature } from "../types";
22
import { parsePublicKey } from "../pem/spki";
33
import { parseSignInfo } from "../shared/verify";
4-
import { decodeBase64ToUint8Array, genSignInfo } from "../utils";
4+
import { decodeBase64ToUint8Array, genSignInfo, getWebcrypto } from "../utils";
55

66
/**
77
* @deprecated Use `parseSignInfo`
@@ -14,9 +14,9 @@ export const genSignInfoDraft = parseSignInfo;
1414
export async function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)) {
1515
try {
1616
const parsedSpki = parsePublicKey(publicKeyPem);
17-
const publicKey = await globalThis.crypto.subtle.importKey('spki', parsedSpki.der, genSignInfo(parsedSpki), false, ['verify']);
17+
const publicKey = await (await getWebcrypto()).subtle.importKey('spki', parsedSpki.der, genSignInfo(parsedSpki), false, ['verify']);
1818

19-
const verify = await globalThis.crypto.subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), (new TextEncoder()).encode(parsed.signingString));
19+
const verify = await (await getWebcrypto()).subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), (new TextEncoder()).encode(parsed.signingString));
2020
return verify;
2121
} catch (e) {
2222
if (errorLogger) errorLogger(e);

0 commit comments

Comments
 (0)