forked from cloudflare/blindrsa-ts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvitest.setup-file.ts
94 lines (89 loc) · 3.45 KB
/
vitest.setup-file.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (c) 2023 Cloudflare, Inc.
// Licensed under the Apache-2.0 license found in the LICENSE file or at https://opensource.org/licenses/Apache-2.0
// Mocking crypto with NodeJS WebCrypto module only for tests.
import { webcrypto } from 'node:crypto';
import { RSABSSA } from '../src';
if (typeof crypto === 'undefined') {
Object.assign(global, { crypto: webcrypto });
}
// RSA-RAW is not supported by WebCrypto, so we need to mock it.
// blindSign operation is similar for deterministic and randomized variants, and salt length is not used during this operation.
// It matches cloudflare/workerd implementation https://github.com/cloudflare/workerd/blob/6b63c701e263a311c2a3ce64e2aeada69afc32a1/src/workerd/api/crypto-impl-asymmetric.c%2B%2B#L827-L868
// eslint-disable-next-line @typescript-eslint/unbound-method
const parentSign = crypto.subtle.sign;
async function mockSign(
algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams,
key: CryptoKey,
data: Uint8Array,
): Promise<ArrayBuffer> {
if (
algorithm === 'RSA-RAW' ||
(typeof algorithm !== 'string' && algorithm.name === 'RSA-RAW')
) {
const algorithmName = key.algorithm.name;
if (algorithmName !== 'RSA-RAW') {
throw new Error(`Invalid key algorithm: ${algorithmName}`);
}
key.algorithm.name = 'RSA-PSS';
try {
// await is needed here because if the promised is returned, the algorithmName could be restored before the key is used, causing an error
return await RSABSSA.SHA384.PSSZero.Deterministic().blindSign(key, data);
} finally {
key.algorithm.name = algorithmName;
}
}
// webcrypto calls crypto, which is mocked. We need to restore the original implementation.
crypto.subtle.sign = parentSign;
const res = crypto.subtle.sign(algorithm, key, data);
await res.finally(() => {
crypto.subtle.sign = mockSign;
});
return res;
}
crypto.subtle.sign = mockSign;
// eslint-disable-next-line @typescript-eslint/unbound-method
const parentImportKey = crypto.subtle.importKey;
async function mockImportKey(
format: KeyFormat,
keyData: JsonWebKey | BufferSource,
algorithm: AlgorithmIdentifier,
extractable: boolean,
keyUsages: KeyUsage[],
): Promise<CryptoKey> {
crypto.subtle.importKey = parentImportKey;
try {
if (format === 'jwk') {
return await crypto.subtle.importKey(
format,
keyData as JsonWebKey,
algorithm,
extractable,
keyUsages,
);
}
const data: BufferSource = keyData as BufferSource;
if (
algorithm === 'RSA-RAW' ||
(!(typeof algorithm === 'string') && algorithm.name === 'RSA-RAW')
) {
if (typeof algorithm === 'string') {
algorithm = { name: 'RSA-PSS' };
} else {
algorithm = { ...algorithm, name: 'RSA-PSS' };
}
const key = await crypto.subtle.importKey(
format,
data,
algorithm,
extractable,
keyUsages,
);
key.algorithm.name = 'RSA-RAW';
return key;
}
return await crypto.subtle.importKey(format, data, algorithm, extractable, keyUsages);
} finally {
crypto.subtle.importKey = mockImportKey;
}
}
crypto.subtle.importKey = mockImportKey;