@suveren/gateway 0.7.4 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/control-plane/index.mjs +248 -58
- package/dist/mcp-server/http.mjs +408 -65
- package/dist/ui/assets/{index-CkWaRck1.css → index-BYVb_0oG.css} +1 -1
- package/dist/ui/assets/index-CsrM6RQr.js +110 -0
- package/dist/ui/index.html +2 -2
- package/node_modules/@hap/core/dist/index.d.mts +258 -9
- package/node_modules/@hap/core/dist/index.d.ts +258 -9
- package/node_modules/@hap/core/dist/index.js +227 -5
- package/node_modules/@hap/core/dist/index.mjs +213 -4
- package/node_modules/@hap/core/package.json +3 -2
- package/node_modules/@hap/core/src/did-key.ts +126 -0
- package/node_modules/@hap/core/src/identity.ts +21 -5
- package/node_modules/@hap/core/src/index.ts +3 -0
- package/node_modules/@hap/core/src/mandate.ts +207 -0
- package/node_modules/@hap/core/src/receipt.ts +74 -0
- package/node_modules/@hap/core/src/types.ts +81 -5
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/package.json +16 -10
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/buffer.buffer.d.ts +5 -5
- package/node_modules/@types/node/crypto.d.ts +2 -2
- package/node_modules/@types/node/http.d.ts +16 -0
- package/node_modules/@types/node/http2.d.ts +10 -2
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/process.d.ts +52 -0
- package/node_modules/@types/node/quic.d.ts +210 -28
- package/node_modules/@types/node/sqlite.d.ts +6 -2
- package/node_modules/@types/node/test.d.ts +36 -0
- package/node_modules/fast-uri/index.js +201 -48
- package/node_modules/fast-uri/lib/schemes.js +9 -4
- package/node_modules/fast-uri/lib/utils.js +388 -91
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +105 -0
- package/node_modules/fast-uri/test/equal.test.js +31 -3
- package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
- package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +90 -0
- package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
- package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
- package/node_modules/fast-uri/test/parse.test.js +7 -3
- package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
- package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
- package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
- package/node_modules/fast-uri/test/security-normalization.test.js +101 -0
- package/node_modules/fast-uri/test/security.test.js +75 -3
- package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
- package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
- package/node_modules/hono/dist/cjs/client/client.js +25 -11
- package/node_modules/hono/dist/cjs/client/utils.js +4 -1
- package/node_modules/hono/dist/cjs/context.js +4 -0
- package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +36 -2
- package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +1 -1
- package/node_modules/hono/dist/cjs/helper/ssg/utils.js +30 -10
- package/node_modules/hono/dist/cjs/jsx/dom/render.js +2 -0
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/csrf/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/etag/digest.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -3
- package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +3 -1
- package/node_modules/hono/dist/cjs/request.js +8 -4
- package/node_modules/hono/dist/cjs/router/linear-router/router.js +7 -2
- package/node_modules/hono/dist/cjs/router/pattern-router/router.js +3 -9
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +10 -3
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +47 -83
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +2 -1
- package/node_modules/hono/dist/cjs/router/trie-router/node.js +46 -69
- package/node_modules/hono/dist/cjs/router/trie-router/router.js +3 -11
- package/node_modules/hono/dist/cjs/router/utils.js +27 -0
- package/node_modules/hono/dist/cjs/utils/body.js +15 -3
- package/node_modules/hono/dist/cjs/utils/cookie.js +1 -1
- package/node_modules/hono/dist/cjs/utils/ipaddr.js +5 -3
- package/node_modules/hono/dist/cjs/utils/stream.js +7 -1
- package/node_modules/hono/dist/cjs/utils/url.js +9 -1
- package/node_modules/hono/dist/client/client.js +25 -11
- package/node_modules/hono/dist/client/utils.js +4 -1
- package/node_modules/hono/dist/context.js +4 -0
- package/node_modules/hono/dist/helper/accepts/accepts.js +36 -2
- package/node_modules/hono/dist/helper/ssg/ssg.js +1 -1
- package/node_modules/hono/dist/helper/ssg/utils.js +30 -10
- package/node_modules/hono/dist/jsx/dom/render.js +2 -0
- package/node_modules/hono/dist/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/middleware/csrf/index.js +1 -1
- package/node_modules/hono/dist/middleware/etag/digest.js +1 -1
- package/node_modules/hono/dist/middleware/etag/index.js +3 -3
- package/node_modules/hono/dist/middleware/pretty-json/index.js +3 -1
- package/node_modules/hono/dist/request.js +8 -4
- package/node_modules/hono/dist/router/linear-router/router.js +7 -2
- package/node_modules/hono/dist/router/pattern-router/router.js +3 -9
- package/node_modules/hono/dist/router/reg-exp-router/node.js +6 -2
- package/node_modules/hono/dist/router/reg-exp-router/router.js +53 -84
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +2 -1
- package/node_modules/hono/dist/router/trie-router/node.js +46 -69
- package/node_modules/hono/dist/router/trie-router/router.js +3 -11
- package/node_modules/hono/dist/router/utils.js +5 -0
- package/node_modules/hono/dist/types/context.d.ts +4 -0
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +3 -0
- package/node_modules/hono/dist/types/router/trie-router/node.d.ts +1 -2
- package/node_modules/hono/dist/types/router/trie-router/router.d.ts +0 -1
- package/node_modules/hono/dist/types/router/utils.d.ts +1 -0
- package/node_modules/hono/dist/types/utils/url.d.ts +4 -0
- package/node_modules/hono/dist/utils/body.js +15 -3
- package/node_modules/hono/dist/utils/cookie.js +1 -1
- package/node_modules/hono/dist/utils/ipaddr.js +5 -3
- package/node_modules/hono/dist/utils/stream.js +7 -1
- package/node_modules/hono/dist/utils/url.js +9 -1
- package/node_modules/hono/package.json +1 -1
- package/node_modules/is-plain-object/README.md +39 -95
- package/node_modules/is-plain-object/dist/is-plain-object.js +0 -2
- package/node_modules/is-plain-object/is-plain-object.d.ts +6 -1
- package/node_modules/is-plain-object/package.json +8 -34
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +12 -17
- package/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
- package/node_modules/jose/dist/types/types.d.ts +4 -2
- package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +32 -21
- package/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
- package/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
- package/node_modules/jose/dist/webapi/jwks/local.js +45 -53
- package/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
- package/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
- package/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
- package/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
- package/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
- package/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
- package/node_modules/jose/dist/webapi/key/import.js +16 -12
- package/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
- package/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
- package/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +45 -13
- package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
- package/node_modules/jose/dist/webapi/lib/key.js +24 -9
- package/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
- package/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
- package/node_modules/jose/dist/webapi/lib/options.js +26 -0
- package/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
- package/node_modules/jose/package.json +1 -1
- package/package.json +2 -2
- package/dist/ui/assets/index-0Q2eNytX.js +0 -110
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/HISTORY.md +0 -114
|
@@ -1,30 +1,54 @@
|
|
|
1
1
|
import { encode as b64u } from '../util/base64url.js';
|
|
2
2
|
import { encrypt } from './content_encryption.js';
|
|
3
3
|
import { encryptKeyManagement } from './key_management.js';
|
|
4
|
-
import {
|
|
5
|
-
import { isDisjoint } from './type_checks.js';
|
|
4
|
+
import { JWEInvalid } from '../util/errors.js';
|
|
5
|
+
import { assertUint8Array, isDisjoint, isObject } from './type_checks.js';
|
|
6
6
|
import { concat, encode } from './buffer_utils.js';
|
|
7
|
-
import { validateCrit, JWE_RECOGNIZED } from './options.js';
|
|
7
|
+
import { serializeJoseHeader, validateCrit, validateCritDuplicates, JWE_RECOGNIZED, } from './options.js';
|
|
8
8
|
import { prepareKey } from './key.js';
|
|
9
9
|
import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js';
|
|
10
|
-
import { compress } from './deflate.js';
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import { compress, validateZip } from './deflate.js';
|
|
11
|
+
import { unprotected } from './helpers.js';
|
|
12
|
+
export function checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader) {
|
|
13
13
|
if (!isDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader)) {
|
|
14
14
|
throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
|
|
15
15
|
}
|
|
16
|
+
}
|
|
17
|
+
export function checkEncryptHeaders(input) {
|
|
18
|
+
let [, protectedHeader, unprotectedHeader, sharedUnprotectedHeader, aad, cek, iv, keyManagementParameters, crit,] = input;
|
|
19
|
+
if (aad !== undefined) {
|
|
20
|
+
assertUint8Array(aad, 'JWE Additional Authenticated Data');
|
|
21
|
+
}
|
|
22
|
+
if (cek !== undefined) {
|
|
23
|
+
assertUint8Array(cek, 'JWE Content Encryption Key');
|
|
24
|
+
}
|
|
25
|
+
if (iv !== undefined) {
|
|
26
|
+
assertUint8Array(iv, 'JWE Initialization Vector');
|
|
27
|
+
}
|
|
28
|
+
if (protectedHeader !== undefined) {
|
|
29
|
+
protectedHeader = serializeJoseHeader(JWEInvalid, protectedHeader)[0];
|
|
30
|
+
input[1] = protectedHeader;
|
|
31
|
+
}
|
|
32
|
+
if (unprotectedHeader !== undefined) {
|
|
33
|
+
unprotectedHeader = serializeJoseHeader(JWEInvalid, unprotectedHeader)[0];
|
|
34
|
+
input[2] = unprotectedHeader;
|
|
35
|
+
}
|
|
36
|
+
if (sharedUnprotectedHeader !== undefined) {
|
|
37
|
+
sharedUnprotectedHeader = serializeJoseHeader(JWEInvalid, sharedUnprotectedHeader)[0];
|
|
38
|
+
input[3] = sharedUnprotectedHeader;
|
|
39
|
+
}
|
|
40
|
+
if (keyManagementParameters !== undefined && !isObject(keyManagementParameters)) {
|
|
41
|
+
throw new TypeError('JWE Key Management Parameters must be an object');
|
|
42
|
+
}
|
|
43
|
+
checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader);
|
|
16
44
|
const joseHeader = {
|
|
17
45
|
...protectedHeader,
|
|
18
46
|
...unprotectedHeader,
|
|
19
47
|
...sharedUnprotectedHeader,
|
|
20
48
|
};
|
|
49
|
+
validateCritDuplicates(JWEInvalid, protectedHeader);
|
|
21
50
|
validateCrit(JWEInvalid, JWE_RECOGNIZED, crit, protectedHeader, joseHeader);
|
|
22
|
-
|
|
23
|
-
throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.');
|
|
24
|
-
}
|
|
25
|
-
if (joseHeader.zip !== undefined && !protectedHeader?.zip) {
|
|
26
|
-
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.');
|
|
27
|
-
}
|
|
51
|
+
validateZip(joseHeader, protectedHeader);
|
|
28
52
|
const { alg, enc } = joseHeader;
|
|
29
53
|
if (typeof alg !== 'string' || !alg) {
|
|
30
54
|
throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
|
|
@@ -52,6 +76,7 @@ export async function encryptJWE(input, checked, key) {
|
|
|
52
76
|
else {
|
|
53
77
|
protectedHeader = protectedHeader ? { ...protectedHeader, ...parameters } : parameters;
|
|
54
78
|
}
|
|
79
|
+
checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader);
|
|
55
80
|
}
|
|
56
81
|
let protectedHeaderS;
|
|
57
82
|
let protectedHeaderB;
|
|
@@ -105,6 +130,13 @@ export async function encryptJWE(input, checked, key) {
|
|
|
105
130
|
}
|
|
106
131
|
return jwe;
|
|
107
132
|
}
|
|
108
|
-
export async function createJWE(input, key) {
|
|
133
|
+
export async function createJWE(input, key, options) {
|
|
134
|
+
if (!input[1] && !input[2] && !input[3]) {
|
|
135
|
+
throw new JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()');
|
|
136
|
+
}
|
|
137
|
+
if (options !== undefined) {
|
|
138
|
+
input[8] = options?.crit;
|
|
139
|
+
input[9] = options ? unprotected in options : false;
|
|
140
|
+
}
|
|
109
141
|
return encryptJWE(input, checkEncryptHeaders(input), key);
|
|
110
142
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function snapshotJwk(jwk) {
|
|
2
|
+
return { __proto__: null, ...jwk };
|
|
3
|
+
}
|
|
4
|
+
export function normalizeJwk(jwk) {
|
|
5
|
+
const normalized = snapshotJwk(jwk);
|
|
6
|
+
if (normalized.ext !== undefined && typeof normalized.ext !== 'boolean') {
|
|
7
|
+
throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
|
|
8
|
+
}
|
|
9
|
+
if (normalized.key_ops !== undefined) {
|
|
10
|
+
const value = normalized.key_ops;
|
|
11
|
+
const keyOps = Array.isArray(value) ? [...value] : undefined;
|
|
12
|
+
if (!keyOps ||
|
|
13
|
+
keyOps.some((operation) => typeof operation !== 'string') ||
|
|
14
|
+
new Set(keyOps).size !== keyOps.length) {
|
|
15
|
+
throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
|
|
16
|
+
}
|
|
17
|
+
normalized.key_ops = keyOps;
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
@@ -4,15 +4,37 @@ import { jwsAlgorithm } from './jws_algorithms.js';
|
|
|
4
4
|
import { isDisjoint } from './type_checks.js';
|
|
5
5
|
import { JWSInvalid } from '../util/errors.js';
|
|
6
6
|
import { concat, encode } from './buffer_utils.js';
|
|
7
|
-
import { validateCrit, validateCritDuplicates, JWS_RECOGNIZED } from './options.js';
|
|
7
|
+
import { serializeJoseHeader, validateB64, validateCrit, validateCritDuplicates, JWS_RECOGNIZED, } from './options.js';
|
|
8
8
|
import { prepareKey } from './key.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
function serializeProtectedHeader(protectedHeader) {
|
|
10
|
+
if (protectedHeader === undefined)
|
|
11
|
+
return [undefined, ''];
|
|
12
|
+
const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);
|
|
13
|
+
return [normalized[0], b64u(normalized[1])];
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
function validateSignatureHeader(protectedHeader, joseHeader, crit) {
|
|
16
|
+
validateCritDuplicates(JWSInvalid, protectedHeader);
|
|
17
|
+
return validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));
|
|
18
|
+
}
|
|
19
|
+
function signatureAlgorithm(joseHeader) {
|
|
20
|
+
const alg = joseHeader.alg;
|
|
21
|
+
if (typeof alg !== 'string' || !alg) {
|
|
22
|
+
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
23
|
+
}
|
|
24
|
+
return jwsAlgorithm(alg);
|
|
25
|
+
}
|
|
26
|
+
async function signSignature(protectedHeader, payload, entry, key) {
|
|
27
|
+
const data = concat(encode(protectedHeader), encode('.'), payload);
|
|
28
|
+
const k = await prepareKey(entry, key, 'sign');
|
|
29
|
+
return b64u(await sign(entry, k, data));
|
|
30
|
+
}
|
|
31
|
+
export async function createSignature(input, key, assertB64) {
|
|
32
|
+
let { protectedHeader, unprotectedHeader } = input;
|
|
33
|
+
let protectedHeaderString;
|
|
34
|
+
[protectedHeader, protectedHeaderString] = serializeProtectedHeader(protectedHeader);
|
|
35
|
+
if (unprotectedHeader !== undefined) {
|
|
36
|
+
unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0];
|
|
37
|
+
}
|
|
16
38
|
if (!protectedHeader && !unprotectedHeader) {
|
|
17
39
|
throw new JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()');
|
|
18
40
|
}
|
|
@@ -20,20 +42,9 @@ export async function createSignature(input, key) {
|
|
|
20
42
|
throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');
|
|
21
43
|
}
|
|
22
44
|
const joseHeader = { ...protectedHeader, ...unprotectedHeader };
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (extensions.includes('b64')) {
|
|
27
|
-
b64 = protectedHeader.b64;
|
|
28
|
-
if (typeof b64 !== 'boolean') {
|
|
29
|
-
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const { alg } = joseHeader;
|
|
33
|
-
if (typeof alg !== 'string' || !alg) {
|
|
34
|
-
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
35
|
-
}
|
|
36
|
-
const entry = jwsAlgorithm(alg);
|
|
45
|
+
const b64 = validateSignatureHeader(protectedHeader, joseHeader, input.crit);
|
|
46
|
+
assertB64?.(b64);
|
|
47
|
+
const entry = signatureAlgorithm(joseHeader);
|
|
37
48
|
let payloadS;
|
|
38
49
|
let payloadB;
|
|
39
50
|
if (b64) {
|
|
@@ -47,21 +58,8 @@ export async function createSignature(input, key) {
|
|
|
47
58
|
payloadB = input.payload;
|
|
48
59
|
payloadS = '';
|
|
49
60
|
}
|
|
50
|
-
let protectedHeaderString;
|
|
51
|
-
let protectedHeaderBytes;
|
|
52
|
-
if (protectedHeader) {
|
|
53
|
-
protectedHeaderString = b64u(JSON.stringify(protectedHeader));
|
|
54
|
-
protectedHeaderBytes = encode(protectedHeaderString);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
protectedHeaderString = '';
|
|
58
|
-
protectedHeaderBytes = new Uint8Array();
|
|
59
|
-
}
|
|
60
|
-
const data = concat(protectedHeaderBytes, encode('.'), payloadB);
|
|
61
|
-
const k = await prepareKey(entry, key, 'sign');
|
|
62
|
-
const signature = await sign(entry, k, data);
|
|
63
61
|
const jws = {
|
|
64
|
-
signature:
|
|
62
|
+
signature: await signSignature(protectedHeaderString, payloadB, entry, key),
|
|
65
63
|
payload: payloadS,
|
|
66
64
|
};
|
|
67
65
|
if (protectedHeader) {
|
|
@@ -70,5 +68,18 @@ export async function createSignature(input, key) {
|
|
|
70
68
|
if (unprotectedHeader) {
|
|
71
69
|
jws.header = unprotectedHeader;
|
|
72
70
|
}
|
|
73
|
-
return jws;
|
|
71
|
+
return [jws, b64];
|
|
72
|
+
}
|
|
73
|
+
export async function createCompactSignature(payload, inputProtectedHeader, inputCrit, key, rejectUnencoded) {
|
|
74
|
+
const [protectedHeader, protectedHeaderString] = serializeProtectedHeader(inputProtectedHeader);
|
|
75
|
+
if (!protectedHeader) {
|
|
76
|
+
throw new JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()');
|
|
77
|
+
}
|
|
78
|
+
const b64 = validateSignatureHeader(protectedHeader, protectedHeader, inputCrit);
|
|
79
|
+
if (!b64)
|
|
80
|
+
rejectUnencoded();
|
|
81
|
+
const entry = signatureAlgorithm(protectedHeader);
|
|
82
|
+
const encodedPayload = b64u(payload);
|
|
83
|
+
const signature = await signSignature(protectedHeaderString, encode(encodedPayload), entry, key);
|
|
84
|
+
return `${protectedHeaderString}.${encodedPayload}.${signature}`;
|
|
74
85
|
}
|
|
@@ -3,9 +3,25 @@ import { jwsAlgorithm } from './jws_algorithms.js';
|
|
|
3
3
|
import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../util/errors.js';
|
|
4
4
|
import { concat, decoder, encoder, encode } from './buffer_utils.js';
|
|
5
5
|
import { decodeBase64url, encodeBase64url, parseJoseHeader } from './helpers.js';
|
|
6
|
-
import { isDisjoint } from './type_checks.js';
|
|
7
|
-
import { validateCrit, validateAlgorithms, JWS_RECOGNIZED } from './options.js';
|
|
6
|
+
import { isDisjoint, isObject } from './type_checks.js';
|
|
7
|
+
import { validateB64, validateCrit, validateAlgorithms, JWS_RECOGNIZED } from './options.js';
|
|
8
8
|
import { prepareKey } from './key.js';
|
|
9
|
+
export function snapshotJws(jws, sharedPayload) {
|
|
10
|
+
const encodedProtected = jws.protected;
|
|
11
|
+
const inputHeader = jws.header;
|
|
12
|
+
const header = isObject(inputHeader) ? { ...inputHeader } : inputHeader;
|
|
13
|
+
let payload = sharedPayload ? sharedPayload[0] : jws.payload;
|
|
14
|
+
if (!sharedPayload && payload instanceof Uint8Array) {
|
|
15
|
+
payload = new Uint8Array(payload);
|
|
16
|
+
}
|
|
17
|
+
const signature = jws.signature;
|
|
18
|
+
const snapshot = { payload, signature };
|
|
19
|
+
if (encodedProtected !== undefined)
|
|
20
|
+
snapshot.protected = encodedProtected;
|
|
21
|
+
if (inputHeader !== undefined)
|
|
22
|
+
snapshot.header = header;
|
|
23
|
+
return snapshot;
|
|
24
|
+
}
|
|
9
25
|
export function verifyResult(jws, verified) {
|
|
10
26
|
const [payload, parsedProt, , key, resolvedKey] = verified;
|
|
11
27
|
const result = { payload };
|
|
@@ -23,12 +39,24 @@ export function verifyResult(jws, verified) {
|
|
|
23
39
|
export function prepareVerify(options) {
|
|
24
40
|
return [options && validateAlgorithms('algorithms', options.algorithms), options?.crit];
|
|
25
41
|
}
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
export function parseProtectedHeader(encodedProtected, parsedProtected = encodedProtected === undefined
|
|
43
|
+
? {}
|
|
44
|
+
: parseJoseHeader(encodedProtected, JWSInvalid, 'JWS Protected Header is invalid')) {
|
|
45
|
+
return parsedProtected;
|
|
46
|
+
}
|
|
47
|
+
function validateJwsHeaders(parsedProt, joseHeader, shared) {
|
|
48
|
+
const b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader));
|
|
49
|
+
const alg = joseHeader.alg;
|
|
50
|
+
if (typeof alg !== 'string' || !alg) {
|
|
51
|
+
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
31
52
|
}
|
|
53
|
+
if (shared[0] && !shared[0].has(alg)) {
|
|
54
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
55
|
+
}
|
|
56
|
+
return [b64, alg];
|
|
57
|
+
}
|
|
58
|
+
export function parseJwsHeaders(encodedProtected, header, shared, parsedProtected) {
|
|
59
|
+
const parsedProt = parseProtectedHeader(encodedProtected, parsedProtected);
|
|
32
60
|
let joseHeader;
|
|
33
61
|
if (header !== undefined) {
|
|
34
62
|
if (!isDisjoint(parsedProt, header)) {
|
|
@@ -39,58 +67,58 @@ export async function verifySignature(jws, shared, key) {
|
|
|
39
67
|
else {
|
|
40
68
|
joseHeader = parsedProt;
|
|
41
69
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
if (b64) {
|
|
58
|
-
if (typeof inputPayload !== 'string') {
|
|
59
|
-
throw new JWSInvalid('JWS Payload must be a string');
|
|
60
|
-
}
|
|
70
|
+
return [parsedProt, joseHeader, ...validateJwsHeaders(parsedProt, joseHeader, shared)];
|
|
71
|
+
}
|
|
72
|
+
export function encodeJsonUnencodedPayload(payload) {
|
|
73
|
+
const invalid = /[\p{Cs}\p{Cn}]/u.exec(payload)?.[0];
|
|
74
|
+
if (invalid !== undefined) {
|
|
75
|
+
throw new JWSInvalid(/\p{Cs}/u.test(invalid)
|
|
76
|
+
? 'JWS Payload must be a well-formed Unicode string'
|
|
77
|
+
: 'JWS Payload must not contain unassigned Unicode code points');
|
|
78
|
+
}
|
|
79
|
+
return encoder.encode(payload);
|
|
80
|
+
}
|
|
81
|
+
function encodeCompactUnencodedPayload(payload) {
|
|
82
|
+
try {
|
|
83
|
+
return encode(payload);
|
|
61
84
|
}
|
|
62
|
-
|
|
63
|
-
throw new JWSInvalid('JWS
|
|
85
|
+
catch {
|
|
86
|
+
throw new JWSInvalid('JWS Compact Serialization payload must use only ASCII characters');
|
|
64
87
|
}
|
|
88
|
+
}
|
|
89
|
+
async function verifyPrepared(jws, shared, key, encodedProtected, parsedProt, alg, signingPayload) {
|
|
65
90
|
let resolvedKey = false;
|
|
66
91
|
if (typeof key === 'function') {
|
|
67
92
|
key = await key(parsedProt, jws);
|
|
68
93
|
resolvedKey = true;
|
|
69
94
|
}
|
|
95
|
+
const b64 = typeof signingPayload === 'string';
|
|
70
96
|
const entry = jwsAlgorithm(alg);
|
|
71
|
-
const data = concat(encodedProtected !== undefined ? encode(encodedProtected) : new Uint8Array(), encode('.'),
|
|
72
|
-
?
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
: encoder.encode(inputPayload)
|
|
76
|
-
: inputPayload);
|
|
97
|
+
const data = concat(encodedProtected !== undefined ? encode(encodedProtected) : new Uint8Array(), encode('.'), b64
|
|
98
|
+
?
|
|
99
|
+
(shared[2] ??= encodeBase64url(signingPayload, 'payload', JWSInvalid))
|
|
100
|
+
: signingPayload);
|
|
77
101
|
const signature = decodeBase64url(jws.signature, 'signature', JWSInvalid);
|
|
78
102
|
const k = await prepareKey(entry, key, 'verify');
|
|
79
|
-
|
|
80
|
-
if (!verified) {
|
|
103
|
+
if (!(await verify(entry, k, signature, data))) {
|
|
81
104
|
throw new JWSSignatureVerificationFailed();
|
|
82
105
|
}
|
|
83
|
-
|
|
106
|
+
const payload = b64 ? decodeBase64url(signingPayload, 'payload', JWSInvalid) : signingPayload;
|
|
107
|
+
return [payload, parsedProt, b64, k, resolvedKey];
|
|
108
|
+
}
|
|
109
|
+
export async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
110
|
+
const { protected: encodedProtected, header, payload: inputPayload } = jws;
|
|
111
|
+
const [parsedProt, , b64, alg] = parseJwsHeaders(encodedProtected, header, shared, parsedProtected);
|
|
84
112
|
if (b64) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
payload = encoder.encode(inputPayload);
|
|
113
|
+
if (typeof inputPayload !== 'string') {
|
|
114
|
+
throw new JWSInvalid('JWS Payload must be a string');
|
|
115
|
+
}
|
|
89
116
|
}
|
|
90
|
-
else {
|
|
91
|
-
|
|
117
|
+
else if (typeof inputPayload !== 'string' && !(inputPayload instanceof Uint8Array)) {
|
|
118
|
+
throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance');
|
|
92
119
|
}
|
|
93
|
-
|
|
120
|
+
const signingPayload = b64 || typeof inputPayload !== 'string' ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
121
|
+
return verifyPrepared(jws, shared, key, encodedProtected, parsedProt, alg, signingPayload);
|
|
94
122
|
}
|
|
95
123
|
export async function verifyCompact(jws, shared, key) {
|
|
96
124
|
if (jws instanceof Uint8Array) {
|
|
@@ -103,5 +131,9 @@ export async function verifyCompact(jws, shared, key) {
|
|
|
103
131
|
if (length !== 3) {
|
|
104
132
|
throw new JWSInvalid('Invalid Compact JWS');
|
|
105
133
|
}
|
|
106
|
-
|
|
134
|
+
const compactJws = { payload, protected: protectedHeader, signature };
|
|
135
|
+
const parsedProt = parseProtectedHeader(protectedHeader);
|
|
136
|
+
const [b64, alg] = validateJwsHeaders(parsedProt, parsedProt, shared);
|
|
137
|
+
const signingPayload = b64 ? payload : encodeCompactUnencodedPayload(payload);
|
|
138
|
+
return verifyPrepared(compactJws, shared, key, protectedHeader, parsedProt, alg, signingPayload);
|
|
107
139
|
}
|
|
@@ -12,13 +12,22 @@ const multipliers = {
|
|
|
12
12
|
};
|
|
13
13
|
const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
14
14
|
const checkFailed = 'check_failed';
|
|
15
|
+
function invalidDuration() {
|
|
16
|
+
throw new TypeError('Invalid time period format');
|
|
17
|
+
}
|
|
15
18
|
export function secs(str) {
|
|
19
|
+
if (typeof str !== 'string') {
|
|
20
|
+
invalidDuration();
|
|
21
|
+
}
|
|
16
22
|
const matched = REGEX.exec(str);
|
|
17
23
|
if (!matched || (matched[4] && matched[1])) {
|
|
18
|
-
|
|
24
|
+
invalidDuration();
|
|
19
25
|
}
|
|
20
26
|
const value = parseFloat(matched[2]);
|
|
21
27
|
const numericDate = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
28
|
+
if (!Number.isFinite(numericDate)) {
|
|
29
|
+
invalidDuration();
|
|
30
|
+
}
|
|
22
31
|
if (matched[1] === '-' || matched[4] === 'ago') {
|
|
23
32
|
return -numericDate;
|
|
24
33
|
}
|
|
@@ -30,6 +39,17 @@ function validateInput(label, input) {
|
|
|
30
39
|
}
|
|
31
40
|
return input;
|
|
32
41
|
}
|
|
42
|
+
function validateStringClaim(claim, value) {
|
|
43
|
+
if (typeof value !== 'string') {
|
|
44
|
+
throw new TypeError(`"${claim}" claim must be a string`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function validateAudienceClaim(value) {
|
|
48
|
+
if (typeof value !== 'string' &&
|
|
49
|
+
(!Array.isArray(value) || Array.from(value).some((member) => typeof member !== 'string'))) {
|
|
50
|
+
throw new TypeError('"aud" claim must be a string or an array of strings');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
33
53
|
function numericDate(value, label) {
|
|
34
54
|
if (typeof value === 'number')
|
|
35
55
|
return validateInput(label, value);
|
|
@@ -38,10 +58,8 @@ function numericDate(value, label) {
|
|
|
38
58
|
return epoch(new Date()) + secs(value);
|
|
39
59
|
}
|
|
40
60
|
const normalizeTyp = (value) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
return `application/${value.toLowerCase()}`;
|
|
61
|
+
const normalized = value.toLowerCase();
|
|
62
|
+
return value.includes('/') ? normalized : `application/${normalized}`;
|
|
45
63
|
};
|
|
46
64
|
const checkAudiencePresence = (audPayload, audOption) => {
|
|
47
65
|
if (typeof audPayload === 'string') {
|
|
@@ -75,7 +93,7 @@ export function validateClaimsSet(protectedHeader, encodedPayload, options = {})
|
|
|
75
93
|
throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
|
|
76
94
|
}
|
|
77
95
|
const { typ } = options;
|
|
78
|
-
if (typ &&
|
|
96
|
+
if (typ !== undefined &&
|
|
79
97
|
(typeof protectedHeader.typ !== 'string' ||
|
|
80
98
|
normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
|
|
81
99
|
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, 'typ', checkFailed);
|
|
@@ -119,7 +137,7 @@ export function validateClaimsSet(protectedHeader, encodedPayload, options = {})
|
|
|
119
137
|
}
|
|
120
138
|
validateInput('clockTolerance option', tolerance);
|
|
121
139
|
const { currentDate } = options;
|
|
122
|
-
const now = validateInput('currentDate option', epoch(currentDate
|
|
140
|
+
const now = validateInput('currentDate option', epoch(currentDate === undefined ? new Date() : currentDate));
|
|
123
141
|
const iat = validateNumericDate(payload, 'iat', maxTokenAge !== undefined);
|
|
124
142
|
const nbf = validateNumericDate(payload, 'nbf');
|
|
125
143
|
if (nbf !== undefined) {
|
|
@@ -135,63 +153,80 @@ export function validateClaimsSet(protectedHeader, encodedPayload, options = {})
|
|
|
135
153
|
}
|
|
136
154
|
if (maxTokenAge !== undefined) {
|
|
137
155
|
const age = now - iat;
|
|
138
|
-
const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
|
|
156
|
+
const max = validateInput('maxTokenAge option', typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge));
|
|
139
157
|
if (age - tolerance > max) {
|
|
140
158
|
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, 'iat', checkFailed);
|
|
141
159
|
}
|
|
142
|
-
if (age <
|
|
160
|
+
if (age < -tolerance) {
|
|
143
161
|
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, 'iat', checkFailed);
|
|
144
162
|
}
|
|
145
163
|
}
|
|
146
164
|
return payload;
|
|
147
165
|
}
|
|
166
|
+
let producerPayloads;
|
|
167
|
+
function producerPayload(producer) {
|
|
168
|
+
return producerPayloads.get(producer);
|
|
169
|
+
}
|
|
170
|
+
export function jwtData(producer) {
|
|
171
|
+
const payload = producerPayload(producer);
|
|
172
|
+
for (const claim of ['iat', 'nbf', 'exp']) {
|
|
173
|
+
const value = payload[claim];
|
|
174
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
175
|
+
throw new TypeError(`"${claim}" claim must be a finite number`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return encoder.encode(JSON.stringify(payload));
|
|
179
|
+
}
|
|
180
|
+
export function jwtClaim(producer, claim) {
|
|
181
|
+
return producerPayload(producer)[claim];
|
|
182
|
+
}
|
|
148
183
|
export class JWTClaimsBuilder {
|
|
149
|
-
|
|
150
|
-
constructor(payload) {
|
|
184
|
+
constructor(payload = {}) {
|
|
151
185
|
if (!isObject(payload)) {
|
|
152
186
|
throw new TypeError('JWT Claims Set MUST be an object');
|
|
153
187
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return this
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
this
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
;
|
|
189
|
+
(producerPayloads ||= new WeakMap()).set(this, structuredClone(payload));
|
|
190
|
+
}
|
|
191
|
+
setIssuer(value) {
|
|
192
|
+
validateStringClaim('iss', value);
|
|
193
|
+
producerPayload(this).iss = value;
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
setSubject(value) {
|
|
197
|
+
validateStringClaim('sub', value);
|
|
198
|
+
producerPayload(this).sub = value;
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
setAudience(value) {
|
|
202
|
+
validateAudienceClaim(value);
|
|
203
|
+
producerPayload(this).aud = value;
|
|
204
|
+
return this;
|
|
205
|
+
}
|
|
206
|
+
setJti(value) {
|
|
207
|
+
validateStringClaim('jti', value);
|
|
208
|
+
producerPayload(this).jti = value;
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
setNotBefore(value) {
|
|
212
|
+
producerPayload(this).nbf = numericDate(value, 'setNotBefore');
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
setExpirationTime(value) {
|
|
216
|
+
producerPayload(this).exp = numericDate(value, 'setExpirationTime');
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
setIssuedAt(value) {
|
|
220
|
+
const payload = producerPayload(this);
|
|
187
221
|
if (value === undefined) {
|
|
188
|
-
|
|
222
|
+
payload.iat = epoch(new Date());
|
|
189
223
|
}
|
|
190
224
|
else if (typeof value === 'string') {
|
|
191
|
-
|
|
225
|
+
payload.iat = validateInput('setIssuedAt', epoch(new Date()) + secs(value));
|
|
192
226
|
}
|
|
193
227
|
else {
|
|
194
|
-
|
|
228
|
+
payload.iat = numericDate(value, 'setIssuedAt');
|
|
195
229
|
}
|
|
230
|
+
return this;
|
|
196
231
|
}
|
|
197
232
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { withAlg as invalidKeyInput } from './invalid_key_input.js';
|
|
2
2
|
import { isKeyLike, isCryptoKey } from './is_key_like.js';
|
|
3
|
-
import
|
|
3
|
+
import { isObject } from './type_checks.js';
|
|
4
4
|
import { decode } from '../util/base64url.js';
|
|
5
5
|
import { jwkToKey } from './jwk_to_key.js';
|
|
6
|
+
import { normalizeJwk } from './jwk_metadata.js';
|
|
6
7
|
const tag = (key) => key[Symbol.toStringTag];
|
|
7
8
|
const jwkMatchesOp = (entry, key, usage) => {
|
|
8
9
|
const { alg } = entry;
|
|
@@ -27,14 +28,27 @@ export function checkKeyType(entry, key, usage) {
|
|
|
27
28
|
const privateKey = usage === 'decrypt' || usage === 'sign';
|
|
28
29
|
if (secret && key instanceof Uint8Array)
|
|
29
30
|
return [BYTES, key];
|
|
30
|
-
if (
|
|
31
|
-
|
|
31
|
+
if (isObject(key)) {
|
|
32
|
+
const normalized = normalizeJwk(key);
|
|
33
|
+
if (typeof normalized.kty !== 'string') {
|
|
34
|
+
throw new TypeError(secret
|
|
35
|
+
? invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')
|
|
36
|
+
: invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
|
|
37
|
+
}
|
|
38
|
+
const valid = secret
|
|
39
|
+
? normalized.kty === 'oct' && typeof normalized.k === 'string'
|
|
40
|
+
: normalized.kty !== 'oct' &&
|
|
41
|
+
(privateKey
|
|
42
|
+
? (normalized.kty === 'AKP' && typeof normalized.priv === 'string') ||
|
|
43
|
+
typeof normalized.d === 'string'
|
|
44
|
+
: normalized.d === undefined && normalized.priv === undefined);
|
|
45
|
+
if (!valid) {
|
|
32
46
|
throw new TypeError(secret
|
|
33
47
|
? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`
|
|
34
48
|
: `JSON Web Key for this operation must be a ${privateKey ? 'private' : 'public'} JWK`);
|
|
35
49
|
}
|
|
36
|
-
jwkMatchesOp(entry,
|
|
37
|
-
return [JWK, key];
|
|
50
|
+
jwkMatchesOp(entry, normalized, usage);
|
|
51
|
+
return [JWK, key, normalized];
|
|
38
52
|
}
|
|
39
53
|
if (!isKeyLike(key)) {
|
|
40
54
|
throw new TypeError(secret
|
|
@@ -81,7 +95,7 @@ function cached(key, alg, value) {
|
|
|
81
95
|
entry[alg] = value;
|
|
82
96
|
}
|
|
83
97
|
else {
|
|
84
|
-
cache.set(key, {
|
|
98
|
+
cache.set(key, { [alg]: value });
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
return value ?? entry?.[alg];
|
|
@@ -107,8 +121,9 @@ export async function prepareKey(entry, key, usage) {
|
|
|
107
121
|
return tagged[1];
|
|
108
122
|
case JWK: {
|
|
109
123
|
const key = tagged[1];
|
|
110
|
-
|
|
111
|
-
|
|
124
|
+
const normalized = tagged[2];
|
|
125
|
+
if (normalized.kty === 'oct') {
|
|
126
|
+
return decode(normalized.k);
|
|
112
127
|
}
|
|
113
128
|
if (!Object.isFrozen(key)) {
|
|
114
129
|
const { key_ops } = key;
|
|
@@ -116,7 +131,7 @@ export async function prepareKey(entry, key, usage) {
|
|
|
116
131
|
Object.freeze(key_ops);
|
|
117
132
|
Object.freeze(key);
|
|
118
133
|
}
|
|
119
|
-
return handleJWK(key,
|
|
134
|
+
return handleJWK(key, normalized, entry);
|
|
120
135
|
}
|
|
121
136
|
case KEYOBJECT: {
|
|
122
137
|
const keyObject = tagged[1];
|