@suveren/gateway 0.4.1 → 0.6.0
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/bin/suveren-gateway.js +86 -5
- package/content/integrations/calendar.json +116 -22
- package/content/integrations/deploy-github.json +164 -0
- package/content/integrations/gmail.json +13 -4
- package/content/integrations/index.json +2 -1
- package/dist/control-plane/index.mjs +84 -7
- package/dist/mcp-server/http.mjs +147 -21
- package/dist/ui/assets/index-DecSrutK.js +105 -0
- package/dist/ui/index.html +1 -1
- package/node_modules/@hap/core/dist/index.d.mts +21 -0
- package/node_modules/@hap/core/dist/index.d.ts +21 -0
- package/node_modules/@hap/core/dist/index.js +17 -0
- package/node_modules/@hap/core/dist/index.mjs +17 -0
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/gatekeeper.ts +28 -0
- package/node_modules/@hap/core/src/types.ts +21 -0
- package/node_modules/fast-uri/index.js +37 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +136 -0
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/cjs/jsx/base.js +1 -9
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +14 -11
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/cjs/utils/cookie.js +2 -1
- package/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/jsx/base.js +1 -9
- package/node_modules/hono/dist/jsx/hooks/index.js +14 -11
- package/node_modules/hono/dist/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/utils/cookie.js +2 -1
- package/node_modules/hono/package.json +2 -3
- package/node_modules/ip-address/README.md +142 -128
- package/node_modules/ip-address/dist/common.d.ts +6 -0
- package/node_modules/ip-address/dist/common.js +17 -1
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.js +3 -12
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +9 -2
- package/node_modules/ip-address/dist/ipv6.js +35 -16
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/package.json +5 -3
- package/node_modules/jose/README.md +13 -13
- package/node_modules/jose/dist/types/index.d.ts +6 -5
- package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +7 -19
- package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +7 -19
- package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +18 -13
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +20 -21
- package/node_modules/jose/dist/types/jwk/embedded.d.ts +8 -12
- package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +0 -15
- package/node_modules/jose/dist/types/jwks/local.d.ts +12 -21
- package/node_modules/jose/dist/types/jwks/remote.d.ts +34 -165
- package/node_modules/jose/dist/types/jws/compact/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jws/compact/verify.d.ts +17 -13
- package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +17 -13
- package/node_modules/jose/dist/types/jws/general/sign.d.ts +16 -17
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +18 -15
- package/node_modules/jose/dist/types/jwt/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +10 -34
- package/node_modules/jose/dist/types/jwt/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +4 -13
- package/node_modules/jose/dist/types/jwt/verify.d.ts +14 -13
- package/node_modules/jose/dist/types/key/export.d.ts +0 -14
- package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +7 -14
- package/node_modules/jose/dist/types/key/generate_secret.d.ts +16 -14
- package/node_modules/jose/dist/types/key/import.d.ts +18 -28
- package/node_modules/jose/dist/types/types.d.ts +239 -222
- package/node_modules/jose/dist/types/util/base64url.d.ts +11 -4
- package/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -9
- package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +0 -8
- package/node_modules/jose/dist/types/util/errors.d.ts +128 -121
- package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +4 -22
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +5 -153
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +16 -111
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +15 -3
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +65 -81
- package/node_modules/jose/dist/webapi/jwk/embedded.js +5 -3
- package/node_modules/jose/dist/webapi/jwks/local.js +31 -72
- package/node_modules/jose/dist/webapi/jwks/remote.js +19 -28
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +5 -2
- package/node_modules/jose/dist/webapi/jws/compact/verify.js +4 -16
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +7 -65
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +3 -89
- package/node_modules/jose/dist/webapi/jws/general/sign.js +19 -15
- package/node_modules/jose/dist/webapi/jws/general/verify.js +29 -9
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +5 -5
- package/node_modules/jose/dist/webapi/jwt/sign.js +2 -3
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +4 -3
- package/node_modules/jose/dist/webapi/jwt/verify.js +6 -6
- package/node_modules/jose/dist/webapi/key/export.js +37 -4
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +33 -82
- package/node_modules/jose/dist/webapi/key/import.js +8 -8
- package/node_modules/jose/dist/webapi/lib/asn1.js +53 -122
- package/node_modules/jose/dist/webapi/lib/buffer_utils.js +1 -0
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +34 -109
- package/node_modules/jose/dist/webapi/lib/crypto_key.js +18 -126
- package/node_modules/jose/dist/webapi/lib/helpers.js +23 -0
- package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +0 -1
- package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +116 -0
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +186 -0
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +110 -0
- package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +8 -98
- package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +76 -0
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +74 -0
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +107 -0
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +68 -109
- package/node_modules/jose/dist/webapi/lib/key.js +132 -0
- package/node_modules/jose/dist/webapi/lib/key_algorithm.js +10 -0
- package/node_modules/jose/dist/webapi/lib/key_descriptor.js +7 -0
- package/node_modules/jose/dist/webapi/lib/key_management.js +162 -92
- package/node_modules/jose/dist/webapi/lib/options.js +48 -0
- package/node_modules/jose/dist/webapi/lib/signing.js +14 -56
- package/node_modules/jose/dist/webapi/lib/type_checks.js +13 -18
- package/node_modules/jose/dist/webapi/util/base64url.js +13 -4
- package/node_modules/jose/dist/webapi/util/decode_jwt.js +2 -2
- package/node_modules/jose/dist/webapi/util/decode_protected_header.js +5 -15
- package/node_modules/jose/dist/webapi/util/errors.js +1 -1
- package/node_modules/jose/package.json +2 -4
- package/package.json +2 -2
- package/profiles/deploy/0.6.profile.json +168 -0
- package/profiles/deploy/0.7.profile.json +168 -0
- package/profiles/email/0.4.profile.json +9 -2
- package/profiles/index.json +3 -1
- package/dist/ui/assets/index-Cog54HOo.js +0 -105
- package/node_modules/jose/dist/webapi/lib/aesgcmkw.js +0 -15
- package/node_modules/jose/dist/webapi/lib/aeskw.js +0 -25
- package/node_modules/jose/dist/webapi/lib/check_key_type.js +0 -122
- package/node_modules/jose/dist/webapi/lib/ecdhes.js +0 -52
- package/node_modules/jose/dist/webapi/lib/key_to_jwk.js +0 -34
- package/node_modules/jose/dist/webapi/lib/normalize_key.js +0 -166
- package/node_modules/jose/dist/webapi/lib/pbes2kw.js +0 -42
- package/node_modules/jose/dist/webapi/lib/rsaes.js +0 -24
- package/node_modules/jose/dist/webapi/lib/validate_algorithms.js +0 -10
- package/node_modules/jose/dist/webapi/lib/validate_crit.js +0 -33
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { withAlg as invalidKeyInput } from './invalid_key_input.js';
|
|
2
|
+
import { isKeyLike, isCryptoKey } from './is_key_like.js';
|
|
3
|
+
import * as jwk from './type_checks.js';
|
|
4
|
+
import { decode } from '../util/base64url.js';
|
|
5
|
+
import { jwkToKey } from './jwk_to_key.js';
|
|
6
|
+
const tag = (key) => key[Symbol.toStringTag];
|
|
7
|
+
const jwkMatchesOp = (entry, key, usage) => {
|
|
8
|
+
const { alg } = entry;
|
|
9
|
+
if (key.use !== undefined) {
|
|
10
|
+
const expected = usage === 'sign' || usage === 'verify' ? 'sig' : 'enc';
|
|
11
|
+
if (key.use !== expected) {
|
|
12
|
+
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (key.alg !== undefined && key.alg !== alg) {
|
|
16
|
+
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(key.key_ops)) {
|
|
19
|
+
const expectedKeyOp = usage === 'encrypt' || usage === 'decrypt' ? entry.ops?.[usage === 'encrypt' ? 0 : 1] : usage;
|
|
20
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) {
|
|
21
|
+
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export function checkKeyType(entry, key, usage) {
|
|
26
|
+
const { alg, secret } = entry;
|
|
27
|
+
const privateKey = usage === 'decrypt' || usage === 'sign';
|
|
28
|
+
if (secret && key instanceof Uint8Array)
|
|
29
|
+
return [BYTES, key];
|
|
30
|
+
if (jwk.isJWK(key)) {
|
|
31
|
+
if (secret ? !jwk.isSecretJWK(key) : !(privateKey ? jwk.isPrivateJWK(key) : jwk.isPublicJWK(key))) {
|
|
32
|
+
throw new TypeError(secret
|
|
33
|
+
? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`
|
|
34
|
+
: `JSON Web Key for this operation must be a ${privateKey ? 'private' : 'public'} JWK`);
|
|
35
|
+
}
|
|
36
|
+
jwkMatchesOp(entry, key, usage);
|
|
37
|
+
return [JWK, key];
|
|
38
|
+
}
|
|
39
|
+
if (!isKeyLike(key)) {
|
|
40
|
+
throw new TypeError(secret
|
|
41
|
+
? invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')
|
|
42
|
+
: invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
|
|
43
|
+
}
|
|
44
|
+
if (secret) {
|
|
45
|
+
if (key.type !== 'secret') {
|
|
46
|
+
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
if (key.type === 'secret') {
|
|
51
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
52
|
+
}
|
|
53
|
+
const expectedType = privateKey ? 'private' : 'public';
|
|
54
|
+
if ((key.type === 'public' || key.type === 'private') && key.type !== expectedType) {
|
|
55
|
+
const operation = usage === 'sign'
|
|
56
|
+
? 'signing'
|
|
57
|
+
: usage === 'verify'
|
|
58
|
+
? 'verifying'
|
|
59
|
+
: `${usage.slice(0, -1)}tion`;
|
|
60
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm ${operation} must be of type "${expectedType}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return isCryptoKey(key) ? [CRYPTO, key] : [KEYOBJECT, key];
|
|
64
|
+
}
|
|
65
|
+
const BYTES = 0;
|
|
66
|
+
const CRYPTO = 1;
|
|
67
|
+
const KEYOBJECT = 2;
|
|
68
|
+
const JWK = 3;
|
|
69
|
+
let cache;
|
|
70
|
+
const nist = {
|
|
71
|
+
__proto__: null,
|
|
72
|
+
prime256v1: 'P-256',
|
|
73
|
+
secp384r1: 'P-384',
|
|
74
|
+
secp521r1: 'P-521',
|
|
75
|
+
};
|
|
76
|
+
function cached(key, alg, value) {
|
|
77
|
+
cache ||= new WeakMap();
|
|
78
|
+
const entry = cache.get(key);
|
|
79
|
+
if (value) {
|
|
80
|
+
if (entry) {
|
|
81
|
+
entry[alg] = value;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
cache.set(key, { [alg]: value });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return value ?? entry?.[alg];
|
|
88
|
+
}
|
|
89
|
+
const handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ??
|
|
90
|
+
cached(key, entry.alg, await jwkToKey(entry, { ...jwk, alg: entry.alg }));
|
|
91
|
+
const handleKeyObject = (keyObject, entry) => {
|
|
92
|
+
const hit = cached(keyObject, entry.alg);
|
|
93
|
+
if (hit)
|
|
94
|
+
return hit;
|
|
95
|
+
const isPublic = keyObject.type === 'public';
|
|
96
|
+
const usages = entry.usages[isPublic ? 0 : 1];
|
|
97
|
+
const { asymmetricKeyType } = keyObject;
|
|
98
|
+
const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
|
|
99
|
+
const params = entry.resolve?.({ crv, asymmetricKeyType }) ?? entry.subtle;
|
|
100
|
+
return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
|
|
101
|
+
};
|
|
102
|
+
export async function prepareKey(entry, key, usage) {
|
|
103
|
+
const tagged = checkKeyType(entry, key, usage);
|
|
104
|
+
switch (tagged[0]) {
|
|
105
|
+
case BYTES:
|
|
106
|
+
case CRYPTO:
|
|
107
|
+
return tagged[1];
|
|
108
|
+
case JWK: {
|
|
109
|
+
const key = tagged[1];
|
|
110
|
+
if (key.k) {
|
|
111
|
+
return decode(key.k);
|
|
112
|
+
}
|
|
113
|
+
if (!Object.isFrozen(key)) {
|
|
114
|
+
const { key_ops } = key;
|
|
115
|
+
if (Array.isArray(key_ops))
|
|
116
|
+
Object.freeze(key_ops);
|
|
117
|
+
Object.freeze(key);
|
|
118
|
+
}
|
|
119
|
+
return handleJWK(key, key, entry);
|
|
120
|
+
}
|
|
121
|
+
case KEYOBJECT: {
|
|
122
|
+
const keyObject = tagged[1];
|
|
123
|
+
if (keyObject.type === 'secret') {
|
|
124
|
+
return keyObject.export();
|
|
125
|
+
}
|
|
126
|
+
if ('toCryptoKey' in keyObject && typeof keyObject.toCryptoKey === 'function') {
|
|
127
|
+
return handleKeyObject(keyObject, entry);
|
|
128
|
+
}
|
|
129
|
+
return handleJWK(keyObject, keyObject.export({ format: 'jwk' }), entry);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { JOSENotSupported } from '../util/errors.js';
|
|
2
|
+
import { maybeJWSAlgorithm } from './jws_algorithms.js';
|
|
3
|
+
import { maybeJWEAlgorithm } from './jwe_algorithms.js';
|
|
4
|
+
export function keyAlgorithm(alg) {
|
|
5
|
+
const entry = typeof alg === 'string' ? (maybeJWSAlgorithm(alg) ?? maybeJWEAlgorithm(alg)) : undefined;
|
|
6
|
+
if (!entry) {
|
|
7
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
8
|
+
}
|
|
9
|
+
return entry;
|
|
10
|
+
}
|
|
@@ -1,42 +1,129 @@
|
|
|
1
|
-
import * as aeskw from './aeskw.js';
|
|
2
|
-
import * as ecdhes from './ecdhes.js';
|
|
3
|
-
import * as pbes2kw from './pbes2kw.js';
|
|
4
|
-
import * as rsaes from './rsaes.js';
|
|
5
1
|
import { encode as b64u } from '../util/base64url.js';
|
|
6
|
-
import {
|
|
2
|
+
import { prepareKey } from './key.js';
|
|
3
|
+
import { jwkToKey } from './jwk_to_key.js';
|
|
4
|
+
import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js';
|
|
7
5
|
import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
8
|
-
import { decodeBase64url } from './helpers.js';
|
|
9
|
-
import { generateCek,
|
|
10
|
-
import { importJWK } from '../key/import.js';
|
|
11
|
-
import { exportJWK } from '../key/export.js';
|
|
6
|
+
import { decodeBase64url, digest } from './helpers.js';
|
|
7
|
+
import { generateCek, encrypt, decrypt } from './content_encryption.js';
|
|
12
8
|
import { isObject } from './type_checks.js';
|
|
13
|
-
import {
|
|
9
|
+
import { checkCryptoKey, checkModulusLength, checkUsage } from './crypto_key.js';
|
|
10
|
+
import { concat, encode, uint32be } from './buffer_utils.js';
|
|
14
11
|
import { assertCryptoKey } from './is_key_like.js';
|
|
15
|
-
|
|
12
|
+
function checkEcdhCryptoKey(key, usage) {
|
|
13
|
+
if (key.algorithm.name !== 'ECDH' && key.algorithm.name !== 'X25519') {
|
|
14
|
+
throw new TypeError('CryptoKey does not support this operation, its algorithm.name must be ECDH or X25519');
|
|
15
|
+
}
|
|
16
|
+
checkUsage(key, usage);
|
|
17
|
+
}
|
|
18
|
+
async function aeskwCryptoKey(key, alg, usage) {
|
|
19
|
+
const expected = jweAlgorithm(alg).subtle;
|
|
20
|
+
const cryptoKey = key instanceof Uint8Array
|
|
21
|
+
? await crypto.subtle.importKey('raw', key, 'AES-KW', true, [
|
|
22
|
+
usage,
|
|
23
|
+
])
|
|
24
|
+
: key;
|
|
25
|
+
checkCryptoKey(cryptoKey, expected, usage);
|
|
26
|
+
return cryptoKey;
|
|
27
|
+
}
|
|
28
|
+
async function aeskwWrap(alg, key, cek) {
|
|
29
|
+
const cryptoKey = await aeskwCryptoKey(key, alg, 'wrapKey');
|
|
30
|
+
const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
|
|
31
|
+
return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));
|
|
32
|
+
}
|
|
33
|
+
async function aeskwUnwrap(alg, key, encryptedKey) {
|
|
34
|
+
const cryptoKey = await aeskwCryptoKey(key, alg, 'unwrapKey');
|
|
35
|
+
const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
|
|
36
|
+
return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));
|
|
37
|
+
}
|
|
38
|
+
function checkRsaKey(alg, key, usage) {
|
|
39
|
+
checkCryptoKey(key, jweAlgorithm(alg).subtle, usage);
|
|
40
|
+
checkModulusLength(alg, key);
|
|
41
|
+
}
|
|
42
|
+
function pbes2CryptoKey(key, alg) {
|
|
43
|
+
if (key instanceof Uint8Array) {
|
|
44
|
+
return crypto.subtle.importKey('raw', key, 'PBKDF2', false, [
|
|
45
|
+
'deriveBits',
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
checkCryptoKey(key, jweAlgorithm(alg).subtle, 'deriveBits');
|
|
49
|
+
return key;
|
|
50
|
+
}
|
|
51
|
+
async function deriveKey(p2s, alg, p2c, key) {
|
|
52
|
+
if (!(p2s instanceof Uint8Array) || p2s.length < 8) {
|
|
53
|
+
throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets');
|
|
54
|
+
}
|
|
55
|
+
if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1) {
|
|
56
|
+
throw new JWEInvalid('PBES2 Count Input must be a positive integer');
|
|
57
|
+
}
|
|
58
|
+
const salt = concat(encode(alg), Uint8Array.of(0), p2s);
|
|
59
|
+
const keylen = parseInt(alg.slice(13, 16), 10);
|
|
60
|
+
const subtleAlg = {
|
|
61
|
+
hash: `SHA-${alg.slice(8, 11)}`,
|
|
62
|
+
iterations: p2c,
|
|
63
|
+
name: 'PBKDF2',
|
|
64
|
+
salt,
|
|
65
|
+
};
|
|
66
|
+
const cryptoKey = await pbes2CryptoKey(key, alg);
|
|
67
|
+
return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
|
|
68
|
+
}
|
|
69
|
+
function lengthAndInput(input) {
|
|
70
|
+
return concat(uint32be(input.length), input);
|
|
71
|
+
}
|
|
72
|
+
async function concatKdf(Z, L, OtherInfo) {
|
|
73
|
+
const dkLen = L >> 3;
|
|
74
|
+
const hashLen = 32;
|
|
75
|
+
const reps = Math.ceil(dkLen / hashLen);
|
|
76
|
+
const dk = new Uint8Array(reps * hashLen);
|
|
77
|
+
for (let i = 1; i <= reps; i++) {
|
|
78
|
+
const hashResult = await digest('sha256', concat(uint32be(i), Z, OtherInfo));
|
|
79
|
+
dk.set(hashResult, (i - 1) * hashLen);
|
|
80
|
+
}
|
|
81
|
+
return dk.slice(0, dkLen);
|
|
82
|
+
}
|
|
83
|
+
async function ecdhesDeriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) {
|
|
84
|
+
checkEcdhCryptoKey(publicKey);
|
|
85
|
+
checkEcdhCryptoKey(privateKey, 'deriveBits');
|
|
86
|
+
const otherInfo = concat(lengthAndInput(encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
|
|
87
|
+
const Z = new Uint8Array(await crypto.subtle.deriveBits({
|
|
88
|
+
name: publicKey.algorithm.name,
|
|
89
|
+
public: publicKey,
|
|
90
|
+
}, privateKey, publicKey.algorithm.name === 'X25519'
|
|
91
|
+
? 256
|
|
92
|
+
: Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3));
|
|
93
|
+
return concatKdf(Z, keyLength, otherInfo);
|
|
94
|
+
}
|
|
95
|
+
function assertEcdhKey(key) {
|
|
96
|
+
assertCryptoKey(key);
|
|
97
|
+
const curve = key.algorithm.namedCurve;
|
|
98
|
+
if (curve !== 'P-256' &&
|
|
99
|
+
curve !== 'P-384' &&
|
|
100
|
+
curve !== 'P-521' &&
|
|
101
|
+
key.algorithm.name !== 'X25519') {
|
|
102
|
+
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
16
105
|
function assertEncryptedKey(encryptedKey) {
|
|
17
106
|
if (encryptedKey === undefined)
|
|
18
107
|
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
19
108
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
case 'ECDH
|
|
32
|
-
|
|
109
|
+
function assertNoEncryptedKey(encryptedKey) {
|
|
110
|
+
if (encryptedKey !== undefined)
|
|
111
|
+
throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
|
|
112
|
+
}
|
|
113
|
+
export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHeader, options) {
|
|
114
|
+
const entry = jweAlgorithm(alg);
|
|
115
|
+
if (alg === 'dir') {
|
|
116
|
+
assertNoEncryptedKey(encryptedKey);
|
|
117
|
+
return key;
|
|
118
|
+
}
|
|
119
|
+
switch (entry.subtle.name) {
|
|
120
|
+
case 'ECDH': {
|
|
121
|
+
if (alg === 'ECDH-ES')
|
|
122
|
+
assertNoEncryptedKey(encryptedKey);
|
|
33
123
|
if (!isObject(joseHeader.epk))
|
|
34
124
|
throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
38
|
-
const epk = await importJWK(joseHeader.epk, alg);
|
|
39
|
-
assertCryptoKey(epk);
|
|
125
|
+
assertEcdhKey(key);
|
|
126
|
+
const epk = await jwkToKey(entry, joseHeader.epk);
|
|
40
127
|
let partyUInfo;
|
|
41
128
|
let partyVInfo;
|
|
42
129
|
if (joseHeader.apu !== undefined) {
|
|
@@ -49,23 +136,19 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
|
|
|
49
136
|
throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
|
|
50
137
|
partyVInfo = decodeBase64url(joseHeader.apv, 'apv', JWEInvalid);
|
|
51
138
|
}
|
|
52
|
-
const sharedSecret = await
|
|
139
|
+
const sharedSecret = await ecdhesDeriveKey(epk, key, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
|
|
53
140
|
if (alg === 'ECDH-ES')
|
|
54
141
|
return sharedSecret;
|
|
55
142
|
assertEncryptedKey(encryptedKey);
|
|
56
|
-
return
|
|
143
|
+
return aeskwUnwrap(alg.slice(-6), sharedSecret, encryptedKey);
|
|
57
144
|
}
|
|
58
|
-
case 'RSA-OAEP':
|
|
59
|
-
case 'RSA-OAEP-256':
|
|
60
|
-
case 'RSA-OAEP-384':
|
|
61
|
-
case 'RSA-OAEP-512': {
|
|
145
|
+
case 'RSA-OAEP': {
|
|
62
146
|
assertEncryptedKey(encryptedKey);
|
|
63
147
|
assertCryptoKey(key);
|
|
64
|
-
|
|
148
|
+
checkRsaKey(alg, key, 'decrypt');
|
|
149
|
+
return new Uint8Array(await crypto.subtle.decrypt('RSA-OAEP', key, encryptedKey));
|
|
65
150
|
}
|
|
66
|
-
case '
|
|
67
|
-
case 'PBES2-HS384+A192KW':
|
|
68
|
-
case 'PBES2-HS512+A256KW': {
|
|
151
|
+
case 'PBKDF2': {
|
|
69
152
|
assertEncryptedKey(encryptedKey);
|
|
70
153
|
if (typeof joseHeader.p2c !== 'number')
|
|
71
154
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
|
|
@@ -74,19 +157,15 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
|
|
|
74
157
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
|
|
75
158
|
if (typeof joseHeader.p2s !== 'string')
|
|
76
159
|
throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return
|
|
160
|
+
const p2s = decodeBase64url(joseHeader.p2s, 'p2s', JWEInvalid);
|
|
161
|
+
const derived = await deriveKey(p2s, alg, joseHeader.p2c, key);
|
|
162
|
+
return aeskwUnwrap(alg.slice(-6), derived, encryptedKey);
|
|
80
163
|
}
|
|
81
|
-
case '
|
|
82
|
-
case 'A192KW':
|
|
83
|
-
case 'A256KW': {
|
|
164
|
+
case 'AES-KW': {
|
|
84
165
|
assertEncryptedKey(encryptedKey);
|
|
85
|
-
return
|
|
166
|
+
return aeskwUnwrap(alg, key, encryptedKey);
|
|
86
167
|
}
|
|
87
|
-
case '
|
|
88
|
-
case 'A192GCMKW':
|
|
89
|
-
case 'A256GCMKW': {
|
|
168
|
+
case 'AES-GCM': {
|
|
90
169
|
assertEncryptedKey(encryptedKey);
|
|
91
170
|
if (typeof joseHeader.iv !== 'string')
|
|
92
171
|
throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
|
|
@@ -96,10 +175,7 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
|
|
|
96
175
|
iv = decodeBase64url(joseHeader.iv, 'iv', JWEInvalid);
|
|
97
176
|
let tag;
|
|
98
177
|
tag = decodeBase64url(joseHeader.tag, 'tag', JWEInvalid);
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
default: {
|
|
102
|
-
throw new JOSENotSupported(unsupportedAlgHeader);
|
|
178
|
+
return decrypt(jweEncryption(alg.slice(0, -2)), key, encryptedKey, iv, tag, new Uint8Array());
|
|
103
179
|
}
|
|
104
180
|
}
|
|
105
181
|
}
|
|
@@ -107,29 +183,30 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
|
|
|
107
183
|
let encryptedKey;
|
|
108
184
|
let parameters;
|
|
109
185
|
let cek;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
case 'ECDH-ES+A128KW':
|
|
117
|
-
case 'ECDH-ES+A192KW':
|
|
118
|
-
case 'ECDH-ES+A256KW': {
|
|
119
|
-
assertCryptoKey(key);
|
|
120
|
-
if (!ecdhes.allowed(key)) {
|
|
121
|
-
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
122
|
-
}
|
|
186
|
+
const entry = jweAlgorithm(alg);
|
|
187
|
+
if (alg === 'dir')
|
|
188
|
+
return [key, undefined, undefined];
|
|
189
|
+
switch (entry.subtle.name) {
|
|
190
|
+
case 'ECDH': {
|
|
191
|
+
assertEcdhKey(key);
|
|
123
192
|
const { apu, apv } = providedParameters;
|
|
124
193
|
let ephemeralKey;
|
|
125
194
|
if (providedParameters.epk) {
|
|
126
|
-
ephemeralKey = (await
|
|
195
|
+
ephemeralKey = (await prepareKey(entry, providedParameters.epk, 'decrypt'));
|
|
127
196
|
}
|
|
128
197
|
else {
|
|
129
198
|
ephemeralKey = (await crypto.subtle.generateKey(key.algorithm, true, ['deriveBits'])).privateKey;
|
|
130
199
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
200
|
+
const subtle = crypto.subtle;
|
|
201
|
+
let exportableEpk = ephemeralKey;
|
|
202
|
+
if (!exportableEpk.extractable) {
|
|
203
|
+
if (typeof subtle.getPublicKey !== 'function') {
|
|
204
|
+
throw new TypeError('CryptoKey for "epk" must be extractable');
|
|
205
|
+
}
|
|
206
|
+
exportableEpk = await subtle.getPublicKey(ephemeralKey, []);
|
|
207
|
+
}
|
|
208
|
+
const { x, y, crv, kty } = (await subtle.exportKey('jwk', exportableEpk));
|
|
209
|
+
const sharedSecret = await ecdhesDeriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), apu, apv);
|
|
133
210
|
parameters = { epk: { x, crv, kty } };
|
|
134
211
|
if (kty === 'EC')
|
|
135
212
|
parameters.epk.y = y;
|
|
@@ -143,44 +220,37 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
|
|
|
143
220
|
}
|
|
144
221
|
cek = providedCek || generateCek(enc);
|
|
145
222
|
const kwAlg = alg.slice(-6);
|
|
146
|
-
encryptedKey = await
|
|
223
|
+
encryptedKey = await aeskwWrap(kwAlg, sharedSecret, cek);
|
|
147
224
|
break;
|
|
148
225
|
}
|
|
149
|
-
case 'RSA-OAEP':
|
|
150
|
-
case 'RSA-OAEP-256':
|
|
151
|
-
case 'RSA-OAEP-384':
|
|
152
|
-
case 'RSA-OAEP-512': {
|
|
226
|
+
case 'RSA-OAEP': {
|
|
153
227
|
cek = providedCek || generateCek(enc);
|
|
154
228
|
assertCryptoKey(key);
|
|
155
|
-
|
|
229
|
+
checkRsaKey(alg, key, 'encrypt');
|
|
230
|
+
encryptedKey = new Uint8Array(await crypto.subtle.encrypt('RSA-OAEP', key, cek));
|
|
156
231
|
break;
|
|
157
232
|
}
|
|
158
|
-
case '
|
|
159
|
-
case 'PBES2-HS384+A192KW':
|
|
160
|
-
case 'PBES2-HS512+A256KW': {
|
|
233
|
+
case 'PBKDF2': {
|
|
161
234
|
cek = providedCek || generateCek(enc);
|
|
162
|
-
const { p2c, p2s } = providedParameters;
|
|
163
|
-
|
|
235
|
+
const { p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16)) } = providedParameters;
|
|
236
|
+
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
237
|
+
encryptedKey = await aeskwWrap(alg.slice(-6), derived, cek);
|
|
238
|
+
parameters = { p2c, p2s: b64u(p2s) };
|
|
164
239
|
break;
|
|
165
240
|
}
|
|
166
|
-
case '
|
|
167
|
-
case 'A192KW':
|
|
168
|
-
case 'A256KW': {
|
|
241
|
+
case 'AES-KW': {
|
|
169
242
|
cek = providedCek || generateCek(enc);
|
|
170
|
-
encryptedKey = await
|
|
243
|
+
encryptedKey = await aeskwWrap(alg, key, cek);
|
|
171
244
|
break;
|
|
172
245
|
}
|
|
173
|
-
case '
|
|
174
|
-
case 'A192GCMKW':
|
|
175
|
-
case 'A256GCMKW': {
|
|
246
|
+
case 'AES-GCM': {
|
|
176
247
|
cek = providedCek || generateCek(enc);
|
|
177
248
|
const { iv } = providedParameters;
|
|
178
|
-
|
|
249
|
+
const wrapped = await encrypt(jweEncryption(alg.slice(0, -2)), cek, key, iv, new Uint8Array());
|
|
250
|
+
encryptedKey = wrapped.ciphertext;
|
|
251
|
+
parameters = { iv: b64u(wrapped.iv), tag: b64u(wrapped.tag) };
|
|
179
252
|
break;
|
|
180
253
|
}
|
|
181
|
-
default: {
|
|
182
|
-
throw new JOSENotSupported(unsupportedAlgHeader);
|
|
183
|
-
}
|
|
184
254
|
}
|
|
185
|
-
return
|
|
255
|
+
return [cek, encryptedKey, parameters];
|
|
186
256
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js';
|
|
2
|
+
export const JWS_RECOGNIZED = { __proto__: null, b64: true };
|
|
3
|
+
export const JWE_RECOGNIZED = { __proto__: null };
|
|
4
|
+
export function validateAlgorithms(option, algorithms) {
|
|
5
|
+
if (algorithms !== undefined &&
|
|
6
|
+
(!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) {
|
|
7
|
+
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
8
|
+
}
|
|
9
|
+
if (!algorithms) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
return new Set(algorithms);
|
|
13
|
+
}
|
|
14
|
+
export function validateCritDuplicates(Err, protectedHeader) {
|
|
15
|
+
const { crit } = protectedHeader ?? {};
|
|
16
|
+
if (Array.isArray(crit) && new Set(crit).size !== crit.length) {
|
|
17
|
+
throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
21
|
+
if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
|
|
22
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
23
|
+
}
|
|
24
|
+
if (!protectedHeader || protectedHeader.crit === undefined) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
if (!Array.isArray(protectedHeader.crit) ||
|
|
28
|
+
protectedHeader.crit.length === 0 ||
|
|
29
|
+
protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {
|
|
30
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
31
|
+
}
|
|
32
|
+
const recognized = recognizedOption === undefined
|
|
33
|
+
? recognizedDefault
|
|
34
|
+
: { __proto__: null, ...recognizedOption, ...recognizedDefault };
|
|
35
|
+
for (const parameter of protectedHeader.crit) {
|
|
36
|
+
if (!(parameter in recognized)) {
|
|
37
|
+
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
38
|
+
}
|
|
39
|
+
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === undefined) {
|
|
40
|
+
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
41
|
+
}
|
|
42
|
+
if (recognized[parameter] &&
|
|
43
|
+
(!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === undefined)) {
|
|
44
|
+
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return protectedHeader.crit;
|
|
48
|
+
}
|
|
@@ -1,66 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { invalidKeyInput } from './invalid_key_input.js';
|
|
4
|
-
export function checkKeyLength(alg, key) {
|
|
5
|
-
if (alg.startsWith('RS') || alg.startsWith('PS')) {
|
|
6
|
-
const { modulusLength } = key.algorithm;
|
|
7
|
-
if (typeof modulusLength !== 'number' || modulusLength < 2048) {
|
|
8
|
-
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function subtleAlgorithm(alg, algorithm) {
|
|
13
|
-
const hash = `SHA-${alg.slice(-3)}`;
|
|
14
|
-
switch (alg) {
|
|
15
|
-
case 'HS256':
|
|
16
|
-
case 'HS384':
|
|
17
|
-
case 'HS512':
|
|
18
|
-
return { hash, name: 'HMAC' };
|
|
19
|
-
case 'PS256':
|
|
20
|
-
case 'PS384':
|
|
21
|
-
case 'PS512':
|
|
22
|
-
return { hash, name: 'RSA-PSS', saltLength: parseInt(alg.slice(-3), 10) >> 3 };
|
|
23
|
-
case 'RS256':
|
|
24
|
-
case 'RS384':
|
|
25
|
-
case 'RS512':
|
|
26
|
-
return { hash, name: 'RSASSA-PKCS1-v1_5' };
|
|
27
|
-
case 'ES256':
|
|
28
|
-
case 'ES384':
|
|
29
|
-
case 'ES512':
|
|
30
|
-
return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
|
|
31
|
-
case 'Ed25519':
|
|
32
|
-
case 'EdDSA':
|
|
33
|
-
return { name: 'Ed25519' };
|
|
34
|
-
case 'ML-DSA-44':
|
|
35
|
-
case 'ML-DSA-65':
|
|
36
|
-
case 'ML-DSA-87':
|
|
37
|
-
return { name: alg };
|
|
38
|
-
default:
|
|
39
|
-
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async function getSigKey(alg, key, usage) {
|
|
1
|
+
import { checkCryptoKey, checkModulusLength } from './crypto_key.js';
|
|
2
|
+
async function getSigKey(entry, key, usage) {
|
|
43
3
|
if (key instanceof Uint8Array) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);
|
|
4
|
+
return crypto.subtle.importKey('raw', key, entry.subtle, false, [
|
|
5
|
+
usage,
|
|
6
|
+
]);
|
|
48
7
|
}
|
|
49
|
-
|
|
8
|
+
checkCryptoKey(key, entry.subtle, usage);
|
|
9
|
+
if (entry.minRsaBits)
|
|
10
|
+
checkModulusLength(entry.alg, key);
|
|
50
11
|
return key;
|
|
51
12
|
}
|
|
52
|
-
export async function sign(
|
|
53
|
-
const cryptoKey = await getSigKey(
|
|
54
|
-
|
|
55
|
-
const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
|
|
13
|
+
export async function sign(entry, key, data) {
|
|
14
|
+
const cryptoKey = await getSigKey(entry, key, 'sign');
|
|
15
|
+
const signature = await crypto.subtle.sign(entry.signing, cryptoKey, data);
|
|
56
16
|
return new Uint8Array(signature);
|
|
57
17
|
}
|
|
58
|
-
export async function verify(
|
|
59
|
-
const cryptoKey = await getSigKey(
|
|
60
|
-
checkKeyLength(alg, cryptoKey);
|
|
61
|
-
const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
|
|
18
|
+
export async function verify(entry, key, signature, data) {
|
|
19
|
+
const cryptoKey = await getSigKey(entry, key, 'verify');
|
|
62
20
|
try {
|
|
63
|
-
return await crypto.subtle.verify(
|
|
21
|
+
return await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
|
|
64
22
|
}
|
|
65
23
|
catch {
|
|
66
24
|
return false;
|
|
@@ -1,34 +1,29 @@
|
|
|
1
|
-
const isObjectLike = (value) => typeof value === 'object' && value !== null;
|
|
2
1
|
export function isObject(input) {
|
|
3
|
-
if (
|
|
2
|
+
if (typeof input !== 'object' ||
|
|
3
|
+
input === null ||
|
|
4
|
+
Object.prototype.toString.call(input) !== '[object Object]') {
|
|
4
5
|
return false;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
+
const prototype = Object.getPrototypeOf(input);
|
|
8
|
+
if (prototype === null) {
|
|
7
9
|
return true;
|
|
8
10
|
}
|
|
9
|
-
let proto =
|
|
11
|
+
let proto = prototype;
|
|
10
12
|
while (Object.getPrototypeOf(proto) !== null) {
|
|
11
13
|
proto = Object.getPrototypeOf(proto);
|
|
12
14
|
}
|
|
13
|
-
return
|
|
15
|
+
return prototype === proto;
|
|
14
16
|
}
|
|
15
17
|
export function isDisjoint(...headers) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
let acc;
|
|
21
|
-
for (const header of sources) {
|
|
22
|
-
const parameters = Object.keys(header);
|
|
23
|
-
if (!acc || acc.size === 0) {
|
|
24
|
-
acc = new Set(parameters);
|
|
18
|
+
const parameters = new Set();
|
|
19
|
+
for (const header of headers) {
|
|
20
|
+
if (!header)
|
|
25
21
|
continue;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (acc.has(parameter)) {
|
|
22
|
+
for (const parameter of Object.keys(header)) {
|
|
23
|
+
if (parameters.has(parameter)) {
|
|
29
24
|
return false;
|
|
30
25
|
}
|
|
31
|
-
|
|
26
|
+
parameters.add(parameter);
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
return true;
|