jose 6.2.10 → 6.2.12
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/types/index.d.ts +1 -2
- package/dist/types/jwe/compact/decrypt.d.ts +12 -25
- package/dist/types/jwe/compact/encrypt.d.ts +18 -32
- package/dist/types/jwe/flattened/decrypt.d.ts +12 -25
- package/dist/types/jwe/flattened/encrypt.d.ts +24 -50
- package/dist/types/jwe/general/decrypt.d.ts +15 -30
- package/dist/types/jwe/general/encrypt.d.ts +29 -52
- package/dist/types/jwk/embedded.d.ts +5 -8
- package/dist/types/jwk/thumbprint.d.ts +7 -9
- package/dist/types/jwks/local.d.ts +10 -13
- package/dist/types/jwks/remote.d.ts +29 -41
- package/dist/types/jws/compact/sign.d.ts +8 -13
- package/dist/types/jws/compact/verify.d.ts +14 -26
- package/dist/types/jws/flattened/sign.d.ts +10 -19
- package/dist/types/jws/flattened/verify.d.ts +14 -26
- package/dist/types/jws/general/sign.d.ts +19 -33
- package/dist/types/jws/general/verify.d.ts +17 -32
- package/dist/types/jwt/decrypt.d.ts +20 -27
- package/dist/types/jwt/encrypt.d.ts +30 -35
- package/dist/types/jwt/sign.d.ts +8 -13
- package/dist/types/jwt/unsecured.d.ts +10 -19
- package/dist/types/jwt/verify.d.ts +19 -22
- package/dist/types/key/export.d.ts +10 -10
- package/dist/types/key/generate_key_pair.d.ts +15 -22
- package/dist/types/key/generate_secret.d.ts +12 -19
- package/dist/types/key/import.d.ts +25 -31
- package/dist/types/types.d.ts +184 -319
- package/dist/types/util/base64url.d.ts +7 -7
- package/dist/types/util/decode_jwt.d.ts +5 -7
- package/dist/types/util/decode_protected_header.d.ts +6 -5
- package/dist/types/util/errors.d.ts +50 -88
- package/dist/webapi/index.js +70 -32
- package/dist/webapi/jwe/compact/decrypt.js +6 -8
- package/dist/webapi/jwe/compact/encrypt.js +25 -48
- package/dist/webapi/jwe/flattened/decrypt.js +14 -14
- package/dist/webapi/jwe/flattened/encrypt.js +34 -64
- package/dist/webapi/jwe/general/decrypt.js +38 -49
- package/dist/webapi/jwe/general/encrypt.js +100 -172
- package/dist/webapi/jwk/embedded.js +29 -32
- package/dist/webapi/jwk/thumbprint.js +51 -70
- package/dist/webapi/jwks/local.js +53 -64
- package/dist/webapi/jwks/remote.js +88 -136
- package/dist/webapi/jws/compact/sign.js +19 -21
- package/dist/webapi/jws/compact/verify.js +7 -8
- package/dist/webapi/jws/flattened/sign.js +22 -31
- package/dist/webapi/jws/flattened/verify.js +11 -24
- package/dist/webapi/jws/general/sign.js +55 -73
- package/dist/webapi/jws/general/verify.js +43 -69
- package/dist/webapi/jwt/decrypt.js +12 -20
- package/dist/webapi/jwt/encrypt.js +43 -70
- package/dist/webapi/jwt/sign.js +17 -16
- package/dist/webapi/jwt/unsecured.js +31 -40
- package/dist/webapi/jwt/verify.js +12 -14
- package/dist/webapi/key/export.js +32 -41
- package/dist/webapi/key/generate_key_pair.js +32 -49
- package/dist/webapi/key/generate_secret.js +35 -40
- package/dist/webapi/key/import.js +48 -56
- package/dist/webapi/lib/asn1.js +128 -169
- package/dist/webapi/lib/buffer_utils.js +72 -41
- package/dist/webapi/lib/content_encryption.js +75 -119
- package/dist/webapi/lib/deflate.js +35 -47
- package/dist/webapi/lib/jwe_algorithms.js +102 -93
- package/dist/webapi/lib/jwe_decrypt.js +178 -234
- package/dist/webapi/lib/jwe_encrypt.js +71 -138
- package/dist/webapi/lib/jws_algorithms.js +62 -61
- package/dist/webapi/lib/jws_sign.js +43 -82
- package/dist/webapi/lib/jws_verify.js +78 -131
- package/dist/webapi/lib/jwt_claims_set.js +123 -209
- package/dist/webapi/lib/key.js +147 -139
- package/dist/webapi/lib/key_algorithm.js +13 -8
- package/dist/webapi/lib/key_descriptor.js +8 -6
- package/dist/webapi/lib/key_management.js +169 -235
- package/dist/webapi/lib/validate.js +122 -0
- package/dist/webapi/util/base64url.js +14 -37
- package/dist/webapi/util/decode_jwt.js +32 -31
- package/dist/webapi/util/decode_protected_header.js +18 -23
- package/dist/webapi/util/errors.js +94 -84
- package/package.json +17 -81
- package/dist/webapi/lib/base64.js +0 -22
- package/dist/webapi/lib/crypto_key.js +0 -28
- package/dist/webapi/lib/helpers.js +0 -42
- package/dist/webapi/lib/invalid_key_input.js +0 -26
- package/dist/webapi/lib/is_key_like.js +0 -17
- package/dist/webapi/lib/jwk_metadata.js +0 -20
- package/dist/webapi/lib/jwk_to_key.js +0 -17
- package/dist/webapi/lib/key_options.js +0 -6
- package/dist/webapi/lib/options.js +0 -74
- package/dist/webapi/lib/signing.js +0 -26
- package/dist/webapi/lib/type_checks.js +0 -33
package/dist/webapi/lib/key.js
CHANGED
|
@@ -1,147 +1,155 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
if (Array.isArray(key.key_ops)) {
|
|
20
|
-
const expectedKeyOp = usage === 'encrypt' || usage === 'decrypt' ? entry.ops?.[usage === 'encrypt' ? 0 : 1] : usage;
|
|
21
|
-
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) {
|
|
22
|
-
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
1
|
+
import { isObject } from "./validate.js";
|
|
2
|
+
import { decode } from "../util/base64url.js";
|
|
3
|
+
import { JOSENotSupported } from "../util/errors.js";
|
|
4
|
+
const tag = (key) => key[Symbol.toStringTag], jwkMatchesOp = (entry, key, usage) => {
|
|
5
|
+
const { alg } = entry;
|
|
6
|
+
if (key.use !== void 0) {
|
|
7
|
+
const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
|
|
8
|
+
if (key.use !== expected)
|
|
9
|
+
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
10
|
+
}
|
|
11
|
+
if (key.alg !== void 0 && key.alg !== alg)
|
|
12
|
+
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
13
|
+
if (Array.isArray(key.key_ops)) {
|
|
14
|
+
const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
|
|
15
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))
|
|
16
|
+
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
17
|
+
}
|
|
25
18
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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) {
|
|
46
|
-
throw new TypeError(secret
|
|
47
|
-
? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`
|
|
48
|
-
: `JSON Web Key for this operation must be a ${privateKey ? 'private' : 'public'} JWK`);
|
|
49
|
-
}
|
|
50
|
-
jwkMatchesOp(entry, normalized, usage);
|
|
51
|
-
return [JWK, key, normalized];
|
|
52
|
-
}
|
|
53
|
-
if (!isKeyLike(key)) {
|
|
54
|
-
throw new TypeError(secret
|
|
55
|
-
? invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')
|
|
56
|
-
: invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
|
|
57
|
-
}
|
|
58
|
-
if (secret) {
|
|
59
|
-
if (key.type !== 'secret') {
|
|
60
|
-
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
61
|
-
}
|
|
19
|
+
async function prepareKey(entry, key, usage) {
|
|
20
|
+
const { alg, secret } = entry, privateKey = usage === "decrypt" || usage === "sign";
|
|
21
|
+
if (secret && key instanceof Uint8Array)
|
|
22
|
+
return key;
|
|
23
|
+
let normalized, keyObject;
|
|
24
|
+
if (isObject(key)) {
|
|
25
|
+
if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
|
|
26
|
+
throw invalidKeyType(alg, key, secret);
|
|
27
|
+
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === void 0 && normalized.priv === void 0)))
|
|
28
|
+
throw new TypeError(secret ? 'JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present' : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
|
|
29
|
+
if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
|
|
30
|
+
return decode(normalized.k);
|
|
31
|
+
if (!Object.isFrozen(key)) {
|
|
32
|
+
const { key_ops } = key;
|
|
33
|
+
Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);
|
|
62
34
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
35
|
+
} else {
|
|
36
|
+
if (!isKeyLike(key))
|
|
37
|
+
throw invalidKeyType(alg, key, secret);
|
|
38
|
+
const expectedType = secret ? "secret" : privateKey ? "private" : "public";
|
|
39
|
+
if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
|
|
40
|
+
throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
|
|
41
|
+
if (isCryptoKey(key))
|
|
42
|
+
return key;
|
|
43
|
+
if (keyObject = key, keyObject.type === "secret")
|
|
44
|
+
return keyObject.export();
|
|
45
|
+
}
|
|
46
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
47
|
+
const cacheKey = key;
|
|
48
|
+
let cached = cache.get(cacheKey);
|
|
49
|
+
if (cached?.[alg])
|
|
50
|
+
return cached[alg];
|
|
51
|
+
if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == "function") {
|
|
52
|
+
const isPublic = keyObject.type === "public", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;
|
|
53
|
+
return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);
|
|
54
|
+
}
|
|
55
|
+
return normalized ??= keyObject.export({ format: "jwk" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);
|
|
78
56
|
}
|
|
79
|
-
const BYTES = 0;
|
|
80
|
-
const CRYPTO = 1;
|
|
81
|
-
const KEYOBJECT = 2;
|
|
82
|
-
const JWK = 3;
|
|
83
57
|
let cache;
|
|
84
58
|
const nist = {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
59
|
+
__proto__: null,
|
|
60
|
+
prime256v1: "P-256",
|
|
61
|
+
secp384r1: "P-384",
|
|
62
|
+
secp521r1: "P-521"
|
|
89
63
|
};
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (value) {
|
|
94
|
-
if (entry) {
|
|
95
|
-
entry[alg] = value;
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
cache.set(key, { [alg]: value });
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return value ?? entry?.[alg];
|
|
64
|
+
function assertCryptoKey(key) {
|
|
65
|
+
if (!isCryptoKey(key))
|
|
66
|
+
throw new Error("CryptoKey instance expected");
|
|
102
67
|
}
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const key = tagged[1];
|
|
124
|
-
const normalized = tagged[2];
|
|
125
|
-
if (normalized.kty === 'oct') {
|
|
126
|
-
return decode(normalized.k);
|
|
127
|
-
}
|
|
128
|
-
if (!Object.isFrozen(key)) {
|
|
129
|
-
const { key_ops } = key;
|
|
130
|
-
if (Array.isArray(key_ops))
|
|
131
|
-
Object.freeze(key_ops);
|
|
132
|
-
Object.freeze(key);
|
|
133
|
-
}
|
|
134
|
-
return handleJWK(key, normalized, entry);
|
|
135
|
-
}
|
|
136
|
-
case KEYOBJECT: {
|
|
137
|
-
const keyObject = tagged[1];
|
|
138
|
-
if (keyObject.type === 'secret') {
|
|
139
|
-
return keyObject.export();
|
|
140
|
-
}
|
|
141
|
-
if ('toCryptoKey' in keyObject && typeof keyObject.toCryptoKey === 'function') {
|
|
142
|
-
return handleKeyObject(keyObject, entry);
|
|
143
|
-
}
|
|
144
|
-
return handleJWK(keyObject, keyObject.export({ format: 'jwk' }), entry);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
68
|
+
const isCryptoKey = (key) => {
|
|
69
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey")
|
|
70
|
+
return !0;
|
|
71
|
+
try {
|
|
72
|
+
return key instanceof CryptoKey;
|
|
73
|
+
} catch {
|
|
74
|
+
return !1;
|
|
75
|
+
}
|
|
76
|
+
}, isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject", isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
77
|
+
function message(msg, actual, ...types) {
|
|
78
|
+
if (types.length > 2) {
|
|
79
|
+
const last = types.pop();
|
|
80
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
81
|
+
} else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
|
|
82
|
+
return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
|
|
83
|
+
}
|
|
84
|
+
const invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
|
|
85
|
+
function invalidKeyType(alg, actual, secret) {
|
|
86
|
+
const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
|
|
87
|
+
return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
|
|
147
88
|
}
|
|
89
|
+
const unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
90
|
+
function checkUsage(key, usage) {
|
|
91
|
+
if (usage && !key.usages.includes(usage))
|
|
92
|
+
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
93
|
+
}
|
|
94
|
+
function checkModulusLength(alg, key) {
|
|
95
|
+
const { modulusLength } = key.algorithm;
|
|
96
|
+
if (typeof modulusLength != "number" || modulusLength < 2048)
|
|
97
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
98
|
+
}
|
|
99
|
+
function checkCryptoKey(key, expected, usage) {
|
|
100
|
+
const algorithm = key.algorithm;
|
|
101
|
+
if (algorithm.name !== expected.name)
|
|
102
|
+
throw unusable(expected.name);
|
|
103
|
+
if (expected.hash && algorithm.hash?.name !== expected.hash)
|
|
104
|
+
throw unusable(expected.hash, "algorithm.hash");
|
|
105
|
+
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)
|
|
106
|
+
throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
107
|
+
if (expected.length !== void 0 && algorithm.length !== expected.length)
|
|
108
|
+
throw unusable(expected.length, "algorithm.length");
|
|
109
|
+
checkUsage(key, usage);
|
|
110
|
+
}
|
|
111
|
+
function snapshotJwk(jwk) {
|
|
112
|
+
return { __proto__: null, ...jwk };
|
|
113
|
+
}
|
|
114
|
+
function normalizeJwk(jwk) {
|
|
115
|
+
const normalized = snapshotJwk(jwk);
|
|
116
|
+
if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
|
|
117
|
+
throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
|
|
118
|
+
if (normalized.key_ops !== void 0) {
|
|
119
|
+
const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
|
|
120
|
+
if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
|
|
121
|
+
throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
|
|
122
|
+
normalized.key_ops = keyOps;
|
|
123
|
+
}
|
|
124
|
+
return normalized;
|
|
125
|
+
}
|
|
126
|
+
function validateExtractableOption(extractable) {
|
|
127
|
+
if (extractable !== void 0 && typeof extractable != "boolean")
|
|
128
|
+
throw new TypeError('"extractable" option must be a boolean');
|
|
129
|
+
return extractable;
|
|
130
|
+
}
|
|
131
|
+
async function jwkToKey(entry, jwk, extractable) {
|
|
132
|
+
if (!entry.kty.includes(jwk.kty))
|
|
133
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
134
|
+
const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };
|
|
135
|
+
return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
|
|
136
|
+
}
|
|
137
|
+
async function rawKey(key, expected, usage, extractable = !1) {
|
|
138
|
+
return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
assertCryptoKey,
|
|
142
|
+
checkCryptoKey,
|
|
143
|
+
checkModulusLength,
|
|
144
|
+
checkUsage,
|
|
145
|
+
invalidKeyInput,
|
|
146
|
+
isCryptoKey,
|
|
147
|
+
isKeyLike,
|
|
148
|
+
isKeyObject,
|
|
149
|
+
jwkToKey,
|
|
150
|
+
normalizeJwk,
|
|
151
|
+
prepareKey,
|
|
152
|
+
rawKey,
|
|
153
|
+
snapshotJwk,
|
|
154
|
+
validateExtractableOption
|
|
155
|
+
};
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { JOSENotSupported } from
|
|
2
|
-
import { JWS } from
|
|
3
|
-
import { JWE } from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { JOSENotSupported } from "../util/errors.js";
|
|
2
|
+
import { JWS } from "./jws_algorithms.js";
|
|
3
|
+
import { JWE } from "./jwe_algorithms.js";
|
|
4
|
+
const algArgument = '"alg" (Algorithm)';
|
|
5
|
+
function unsupportedAlg(source = 'JWK "alg" (Algorithm) Parameter') {
|
|
6
|
+
throw new JOSENotSupported(`Invalid or unsupported ${source} value`);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
function keyAlgorithm(alg, source) {
|
|
9
|
+
return (typeof alg == "string" ? JWS[alg] ?? JWE[alg] : void 0) ?? unsupportedAlg(source);
|
|
10
10
|
}
|
|
11
|
+
export {
|
|
12
|
+
algArgument,
|
|
13
|
+
keyAlgorithm,
|
|
14
|
+
unsupportedAlg
|
|
15
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return out;
|
|
1
|
+
function table(entries) {
|
|
2
|
+
const out = { __proto__: null };
|
|
3
|
+
for (const alg in entries)
|
|
4
|
+
out[alg] = { ...entries[alg], alg };
|
|
5
|
+
return out;
|
|
7
6
|
}
|
|
7
|
+
export {
|
|
8
|
+
table
|
|
9
|
+
};
|