jose 4.7.0 → 4.8.3
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/README.md +3 -7
- package/dist/browser/jwks/remote.js +1 -1
- package/dist/browser/lib/crypto_key.js +1 -6
- package/dist/browser/runtime/asn1.js +3 -5
- package/dist/browser/runtime/env.js +0 -8
- package/dist/browser/runtime/fetch_jwks.js +2 -1
- package/dist/browser/runtime/generate.js +3 -7
- package/dist/browser/runtime/jwk_to_key.js +2 -6
- package/dist/browser/runtime/subtle_dsa.js +2 -2
- package/dist/browser/runtime/webcrypto.js +1 -11
- package/dist/node/cjs/jwks/remote.js +1 -1
- package/dist/node/cjs/lib/crypto_key.js +0 -5
- package/dist/node/cjs/runtime/env.js +1 -5
- package/dist/node/cjs/runtime/fetch_jwks.js +2 -1
- package/dist/node/cjs/runtime/webcrypto.js +2 -2
- package/dist/node/esm/jwks/remote.js +1 -1
- package/dist/node/esm/lib/crypto_key.js +1 -6
- package/dist/node/esm/runtime/env.js +0 -3
- package/dist/node/esm/runtime/fetch_jwks.js +2 -1
- package/dist/node/esm/runtime/webcrypto.js +2 -2
- package/dist/types/jwks/remote.d.ts +4 -0
- package/dist/types/key/export.d.ts +4 -4
- package/dist/types/key/import.d.ts +2 -2
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -19,9 +19,7 @@ The following specifications are implemented by `jose`
|
|
|
19
19
|
The test suite utilizes examples defined in [RFC7520][spec-cookbook] to confirm its JOSE
|
|
20
20
|
implementation is correct.
|
|
21
21
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
If you or your business use `jose`, please consider becoming a [sponsor][support-sponsor] so I can continue maintaining it and adding new features carefree.
|
|
22
|
+
## [💗 Help the project](https://github.com/sponsors/panva)
|
|
25
23
|
|
|
26
24
|
## Documentation
|
|
27
25
|
|
|
@@ -91,10 +89,8 @@ import * as jose from 'https://deno.land/x/jose/index.ts'
|
|
|
91
89
|
|
|
92
90
|
| Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
|
|
93
91
|
| ------- | --------- | -------- | -------- |
|
|
94
|
-
| [
|
|
95
|
-
| [
|
|
96
|
-
| [2.x.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ✅ until 2022-04-30 | ❌ |
|
|
97
|
-
| [1.x.x](https://github.com/panva/jose/tree/v1.x) | ✅ | ❌ | ❌ |
|
|
92
|
+
| [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ✅ | ✅ |
|
|
93
|
+
| [v3.x](https://github.com/panva/jose/tree/v3.x), [v2.x](https://github.com/panva/jose/tree/v2.x), [v1.x](https://github.com/panva/jose/tree/v1.x) | ✅ | ❌ | ❌ |
|
|
98
94
|
|
|
99
95
|
#### Semver?
|
|
100
96
|
|
|
@@ -10,7 +10,7 @@ class RemoteJWKSet extends LocalJWKSet {
|
|
|
10
10
|
throw new TypeError('url must be an instance of URL');
|
|
11
11
|
}
|
|
12
12
|
this._url = new URL(url.href);
|
|
13
|
-
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent };
|
|
13
|
+
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent, headers: options === null || options === void 0 ? void 0 : options.headers };
|
|
14
14
|
this._timeoutDuration =
|
|
15
15
|
typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000;
|
|
16
16
|
this._cooldownDuration =
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from '../runtime/env.js';
|
|
2
2
|
function unusable(name, prop = 'algorithm.name') {
|
|
3
3
|
return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
4
4
|
}
|
|
@@ -71,11 +71,6 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
71
71
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
72
72
|
break;
|
|
73
73
|
}
|
|
74
|
-
case isNodeJs() && 'EdDSA': {
|
|
75
|
-
if (key.algorithm.name !== 'NODE-ED25519' && key.algorithm.name !== 'NODE-ED448')
|
|
76
|
-
throw unusable('NODE-ED25519 or NODE-ED448');
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
74
|
case isCloudflareWorkers() && 'EdDSA': {
|
|
80
75
|
if (!isAlgorithm(key.algorithm, 'NODE-ED25519'))
|
|
81
76
|
throw unusable('NODE-ED25519');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from './env.js';
|
|
2
2
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
3
3
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
4
4
|
import { encodeBase64 } from './base64url.js';
|
|
@@ -44,10 +44,8 @@ const getNamedCurve = (keyData) => {
|
|
|
44
44
|
return 'P-384';
|
|
45
45
|
case findOid(keyData, [0x2b, 0x81, 0x04, 0x00, 0x23]):
|
|
46
46
|
return 'P-521';
|
|
47
|
-
case
|
|
47
|
+
case isCloudflareWorkers() && findOid(keyData, [0x2b, 0x65, 0x70]):
|
|
48
48
|
return 'Ed25519';
|
|
49
|
-
case isNodeJs() && findOid(keyData, [0x2b, 0x65, 0x71]):
|
|
50
|
-
return 'Ed448';
|
|
51
49
|
default:
|
|
52
50
|
throw new JOSENotSupported('Invalid or unsupported EC Key Curve or OKP Key Sub Type');
|
|
53
51
|
}
|
|
@@ -102,7 +100,7 @@ const genericImport = async (replace, keyFormat, pem, alg, options) => {
|
|
|
102
100
|
algorithm = { name: 'ECDH', namedCurve: getNamedCurve(keyData) };
|
|
103
101
|
keyUsages = isPublic ? [] : ['deriveBits'];
|
|
104
102
|
break;
|
|
105
|
-
case
|
|
103
|
+
case isCloudflareWorkers() && 'EdDSA':
|
|
106
104
|
const namedCurve = getNamedCurve(keyData).toUpperCase();
|
|
107
105
|
algorithm = { name: `NODE-${namedCurve}`, namedCurve: `NODE-${namedCurve}` };
|
|
108
106
|
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JOSEError, JWKSTimeout } from '../util/errors.js';
|
|
2
|
-
const fetchJwks = async (url, timeout) => {
|
|
2
|
+
const fetchJwks = async (url, timeout, options) => {
|
|
3
3
|
let controller;
|
|
4
4
|
let id;
|
|
5
5
|
let timedOut = false;
|
|
@@ -13,6 +13,7 @@ const fetchJwks = async (url, timeout) => {
|
|
|
13
13
|
const response = await fetch(url.href, {
|
|
14
14
|
signal: controller ? controller.signal : undefined,
|
|
15
15
|
redirect: 'manual',
|
|
16
|
+
headers: options.headers,
|
|
16
17
|
}).catch((err) => {
|
|
17
18
|
if (timedOut)
|
|
18
19
|
throw new JWKSTimeout();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from './env.js';
|
|
2
2
|
import crypto from './webcrypto.js';
|
|
3
3
|
import { JOSENotSupported } from '../util/errors.js';
|
|
4
4
|
import random from './random.js';
|
|
@@ -101,19 +101,15 @@ export async function generateKeyPair(alg, options) {
|
|
|
101
101
|
algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
|
|
102
102
|
keyUsages = ['sign', 'verify'];
|
|
103
103
|
break;
|
|
104
|
-
case
|
|
104
|
+
case isCloudflareWorkers() && 'EdDSA':
|
|
105
105
|
switch (options === null || options === void 0 ? void 0 : options.crv) {
|
|
106
106
|
case undefined:
|
|
107
107
|
case 'Ed25519':
|
|
108
108
|
algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
|
|
109
109
|
keyUsages = ['sign', 'verify'];
|
|
110
110
|
break;
|
|
111
|
-
case isNodeJs() && 'Ed448':
|
|
112
|
-
algorithm = { name: 'NODE-ED448', namedCurve: 'NODE-ED448' };
|
|
113
|
-
keyUsages = ['sign', 'verify'];
|
|
114
|
-
break;
|
|
115
111
|
default:
|
|
116
|
-
throw new JOSENotSupported('Invalid or unsupported crv option provided
|
|
112
|
+
throw new JOSENotSupported('Invalid or unsupported crv option provided');
|
|
117
113
|
}
|
|
118
114
|
break;
|
|
119
115
|
case 'ECDH-ES':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from './env.js';
|
|
2
2
|
import crypto from './webcrypto.js';
|
|
3
3
|
import { JOSENotSupported } from '../util/errors.js';
|
|
4
4
|
import { decode as base64url } from './base64url.js';
|
|
@@ -99,7 +99,7 @@ function subtleMapping(jwk) {
|
|
|
99
99
|
}
|
|
100
100
|
break;
|
|
101
101
|
}
|
|
102
|
-
case
|
|
102
|
+
case isCloudflareWorkers() && 'OKP':
|
|
103
103
|
if (jwk.alg !== 'EdDSA') {
|
|
104
104
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
105
105
|
}
|
|
@@ -108,10 +108,6 @@ function subtleMapping(jwk) {
|
|
|
108
108
|
algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
|
|
109
109
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
110
110
|
break;
|
|
111
|
-
case isNodeJs() && 'Ed448':
|
|
112
|
-
algorithm = { name: 'NODE-ED448', namedCurve: 'NODE-ED448' };
|
|
113
|
-
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
114
|
-
break;
|
|
115
111
|
default:
|
|
116
112
|
throw new JOSENotSupported('Invalid or unsupported JWK "crv" (Subtype of Key Pair) Parameter value');
|
|
117
113
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from './env.js';
|
|
2
2
|
import { JOSENotSupported } from '../util/errors.js';
|
|
3
3
|
export default function subtleDsa(alg, algorithm) {
|
|
4
4
|
const hash = `SHA-${alg.slice(-3)}`;
|
|
@@ -19,7 +19,7 @@ export default function subtleDsa(alg, algorithm) {
|
|
|
19
19
|
case 'ES384':
|
|
20
20
|
case 'ES512':
|
|
21
21
|
return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
|
|
22
|
-
case
|
|
22
|
+
case isCloudflareWorkers() && 'EdDSA':
|
|
23
23
|
const { namedCurve } = algorithm;
|
|
24
24
|
return { name: namedCurve, namedCurve };
|
|
25
25
|
default:
|
|
@@ -1,12 +1,2 @@
|
|
|
1
1
|
export default crypto;
|
|
2
|
-
export
|
|
3
|
-
try {
|
|
4
|
-
return (key != null &&
|
|
5
|
-
typeof key.extractable === 'boolean' &&
|
|
6
|
-
typeof key.algorithm.name === 'string' &&
|
|
7
|
-
typeof key.type === 'string');
|
|
8
|
-
}
|
|
9
|
-
catch (_a) {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
2
|
+
export const isCryptoKey = (key) => key instanceof CryptoKey;
|
|
@@ -13,7 +13,7 @@ class RemoteJWKSet extends local_js_1.LocalJWKSet {
|
|
|
13
13
|
throw new TypeError('url must be an instance of URL');
|
|
14
14
|
}
|
|
15
15
|
this._url = new URL(url.href);
|
|
16
|
-
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent };
|
|
16
|
+
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent, headers: options === null || options === void 0 ? void 0 : options.headers };
|
|
17
17
|
this._timeoutDuration =
|
|
18
18
|
typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000;
|
|
19
19
|
this._cooldownDuration =
|
|
@@ -74,11 +74,6 @@ function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
74
74
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
75
75
|
break;
|
|
76
76
|
}
|
|
77
|
-
case (0, env_js_1.isNodeJs)() && 'EdDSA': {
|
|
78
|
-
if (key.algorithm.name !== 'NODE-ED25519' && key.algorithm.name !== 'NODE-ED448')
|
|
79
|
-
throw unusable('NODE-ED25519 or NODE-ED448');
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
77
|
case (0, env_js_1.isCloudflareWorkers)() && 'EdDSA': {
|
|
83
78
|
if (!isAlgorithm(key.algorithm, 'NODE-ED25519'))
|
|
84
79
|
throw unusable('NODE-ED25519');
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isCloudflareWorkers = void 0;
|
|
4
4
|
function isCloudflareWorkers() {
|
|
5
5
|
return false;
|
|
6
6
|
}
|
|
7
7
|
exports.isCloudflareWorkers = isCloudflareWorkers;
|
|
8
|
-
function isNodeJs() {
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
exports.isNodeJs = isNodeJs;
|
|
@@ -17,10 +17,11 @@ const fetchJwks = async (url, timeout, options) => {
|
|
|
17
17
|
default:
|
|
18
18
|
throw new TypeError('Unsupported URL protocol.');
|
|
19
19
|
}
|
|
20
|
-
const { agent } = options;
|
|
20
|
+
const { agent, headers } = options;
|
|
21
21
|
const req = get(url.href, {
|
|
22
22
|
agent,
|
|
23
23
|
timeout,
|
|
24
|
+
headers,
|
|
24
25
|
});
|
|
25
26
|
const [response] = (await Promise.race([(0, events_1.once)(req, 'response'), (0, events_1.once)(req, 'timeout')]));
|
|
26
27
|
if (!response) {
|
|
@@ -6,6 +6,6 @@ const util = require("util");
|
|
|
6
6
|
const webcrypto = crypto.webcrypto;
|
|
7
7
|
exports.default = webcrypto;
|
|
8
8
|
exports.isCryptoKey = util.types.isCryptoKey
|
|
9
|
-
? (
|
|
9
|
+
? (key) => util.types.isCryptoKey(key)
|
|
10
10
|
:
|
|
11
|
-
(
|
|
11
|
+
(key) => false;
|
|
@@ -10,7 +10,7 @@ class RemoteJWKSet extends LocalJWKSet {
|
|
|
10
10
|
throw new TypeError('url must be an instance of URL');
|
|
11
11
|
}
|
|
12
12
|
this._url = new URL(url.href);
|
|
13
|
-
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent };
|
|
13
|
+
this._options = { agent: options === null || options === void 0 ? void 0 : options.agent, headers: options === null || options === void 0 ? void 0 : options.headers };
|
|
14
14
|
this._timeoutDuration =
|
|
15
15
|
typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000;
|
|
16
16
|
this._cooldownDuration =
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCloudflareWorkers
|
|
1
|
+
import { isCloudflareWorkers } from '../runtime/env.js';
|
|
2
2
|
function unusable(name, prop = 'algorithm.name') {
|
|
3
3
|
return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
4
4
|
}
|
|
@@ -71,11 +71,6 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
71
71
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
72
72
|
break;
|
|
73
73
|
}
|
|
74
|
-
case isNodeJs() && 'EdDSA': {
|
|
75
|
-
if (key.algorithm.name !== 'NODE-ED25519' && key.algorithm.name !== 'NODE-ED448')
|
|
76
|
-
throw unusable('NODE-ED25519 or NODE-ED448');
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
74
|
case isCloudflareWorkers() && 'EdDSA': {
|
|
80
75
|
if (!isAlgorithm(key.algorithm, 'NODE-ED25519'))
|
|
81
76
|
throw unusable('NODE-ED25519');
|
|
@@ -15,10 +15,11 @@ const fetchJwks = async (url, timeout, options) => {
|
|
|
15
15
|
default:
|
|
16
16
|
throw new TypeError('Unsupported URL protocol.');
|
|
17
17
|
}
|
|
18
|
-
const { agent } = options;
|
|
18
|
+
const { agent, headers } = options;
|
|
19
19
|
const req = get(url.href, {
|
|
20
20
|
agent,
|
|
21
21
|
timeout,
|
|
22
|
+
headers,
|
|
22
23
|
});
|
|
23
24
|
const [response] = (await Promise.race([once(req, 'response'), once(req, 'timeout')]));
|
|
24
25
|
if (!response) {
|
|
@@ -3,6 +3,6 @@ import * as util from 'util';
|
|
|
3
3
|
const webcrypto = crypto.webcrypto;
|
|
4
4
|
export default webcrypto;
|
|
5
5
|
export const isCryptoKey = util.types.isCryptoKey
|
|
6
|
-
? (
|
|
6
|
+
? (key) => util.types.isCryptoKey(key)
|
|
7
7
|
:
|
|
8
|
-
(
|
|
8
|
+
(key) => false;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { JWK, KeyLike } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Exports a runtime-specific public key representation (KeyObject or CryptoKey) to
|
|
3
|
+
* Exports a runtime-specific public key representation (KeyObject or CryptoKey) to a PEM-encoded SPKI string format.
|
|
4
4
|
*
|
|
5
|
-
* @param key Key representation to transform to
|
|
5
|
+
* @param key Key representation to transform to a PEM-encoded SPKI string format.
|
|
6
6
|
*
|
|
7
7
|
* @example Usage
|
|
8
8
|
* ```js
|
|
@@ -13,9 +13,9 @@ import type { JWK, KeyLike } from '../types';
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function exportSPKI(key: KeyLike): Promise<string>;
|
|
15
15
|
/**
|
|
16
|
-
* Exports a runtime-specific private key representation (KeyObject or CryptoKey) to
|
|
16
|
+
* Exports a runtime-specific private key representation (KeyObject or CryptoKey) to a PEM-encoded PKCS8 string format.
|
|
17
17
|
*
|
|
18
|
-
* @param key Key representation to transform to
|
|
18
|
+
* @param key Key representation to transform to a PEM-encoded PKCS8 string format.
|
|
19
19
|
*
|
|
20
20
|
* @example Usage
|
|
21
21
|
* ```js
|
|
@@ -8,7 +8,7 @@ export interface PEMImportOptions {
|
|
|
8
8
|
extractable?: boolean;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Imports
|
|
11
|
+
* Imports a PEM-encoded SPKI string as a runtime-specific public key representation (KeyObject or CryptoKey).
|
|
12
12
|
* See [Algorithm Key Requirements](https://github.com/panva/jose/issues/210) to learn about key to algorithm
|
|
13
13
|
* requirements and mapping.
|
|
14
14
|
*
|
|
@@ -52,7 +52,7 @@ export declare function importSPKI(spki: string, alg: string, options?: PEMImpor
|
|
|
52
52
|
*/
|
|
53
53
|
export declare function importX509(x509: string, alg: string, options?: PEMImportOptions): Promise<KeyLike>;
|
|
54
54
|
/**
|
|
55
|
-
* Imports
|
|
55
|
+
* Imports a PEM-encoded PKCS8 string as a runtime-specific private key representation (KeyObject or CryptoKey).
|
|
56
56
|
* See [Algorithm Key Requirements](https://github.com/panva/jose/issues/210) to learn about key to algorithm
|
|
57
57
|
* requirements and mapping. Encrypted keys are not supported.
|
|
58
58
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jose",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.3",
|
|
4
4
|
"description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS with no dependencies using runtime's native crypto",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"browser",
|
|
@@ -55,7 +55,9 @@
|
|
|
55
55
|
"sideEffects": false,
|
|
56
56
|
"exports": {
|
|
57
57
|
".": {
|
|
58
|
+
"types": "./dist/types/index.d.ts",
|
|
58
59
|
"browser": "./dist/browser/index.js",
|
|
60
|
+
"worker": "./dist/browser/index.js",
|
|
59
61
|
"import": "./dist/node/esm/index.js",
|
|
60
62
|
"require": "./dist/node/cjs/index.js"
|
|
61
63
|
},
|