jose 5.1.3 → 5.2.1

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.
Files changed (38) hide show
  1. package/README.md +6 -6
  2. package/dist/browser/jwe/flattened/decrypt.js +1 -1
  3. package/dist/browser/jwe/general/encrypt.js +2 -2
  4. package/dist/browser/jwks/local.js +3 -7
  5. package/dist/browser/jwks/remote.js +2 -4
  6. package/dist/browser/jwt/produce.js +6 -0
  7. package/dist/browser/lib/buffer_utils.js +2 -2
  8. package/dist/browser/lib/invalid_key_input.js +1 -1
  9. package/dist/browser/lib/secs.js +21 -10
  10. package/dist/browser/lib/validate_crit.js +1 -1
  11. package/dist/browser/runtime/asn1.js +4 -4
  12. package/dist/browser/runtime/generate.js +2 -1
  13. package/dist/node/cjs/jwe/flattened/decrypt.js +1 -1
  14. package/dist/node/cjs/jwe/general/encrypt.js +2 -2
  15. package/dist/node/cjs/jwks/local.js +3 -7
  16. package/dist/node/cjs/jwks/remote.js +2 -4
  17. package/dist/node/cjs/jwt/produce.js +6 -0
  18. package/dist/node/cjs/lib/buffer_utils.js +2 -2
  19. package/dist/node/cjs/lib/invalid_key_input.js +1 -1
  20. package/dist/node/cjs/lib/secs.js +21 -10
  21. package/dist/node/cjs/lib/validate_crit.js +1 -1
  22. package/dist/node/cjs/runtime/generate.js +2 -1
  23. package/dist/node/cjs/runtime/get_named_curve.js +1 -1
  24. package/dist/node/esm/jwe/flattened/decrypt.js +1 -1
  25. package/dist/node/esm/jwe/general/encrypt.js +2 -2
  26. package/dist/node/esm/jwks/local.js +3 -7
  27. package/dist/node/esm/jwks/remote.js +2 -4
  28. package/dist/node/esm/jwt/produce.js +6 -0
  29. package/dist/node/esm/lib/buffer_utils.js +2 -2
  30. package/dist/node/esm/lib/invalid_key_input.js +1 -1
  31. package/dist/node/esm/lib/secs.js +21 -10
  32. package/dist/node/esm/lib/validate_crit.js +1 -1
  33. package/dist/node/esm/runtime/generate.js +2 -1
  34. package/dist/node/esm/runtime/get_named_curve.js +1 -1
  35. package/dist/types/jwt/produce.d.ts +59 -9
  36. package/dist/types/key/import.d.ts +3 -3
  37. package/dist/types/util/errors.d.ts +22 -2
  38. package/package.json +2 -2
package/README.md CHANGED
@@ -28,10 +28,10 @@ const jose = require('jose')
28
28
 
29
29
  The `jose` module supports JSON Web Tokens (JWT) and provides functionality for signing and verifying tokens, as well as their JWT Claims Set validation.
30
30
 
31
+ - [JWT Claims Set Validation & Signature Verification](docs/functions/jwt_verify.jwtVerify.md) using the `jwtVerify` function
32
+ - [Using a remote JSON Web Key Set (JWKS)](docs/functions/jwks_remote.createRemoteJWKSet.md)
33
+ - [Using a local JSON Web Key Set (JWKS)](docs/functions/jwks_local.createLocalJWKSet.md)
31
34
  - [Signing](docs/classes/jwt_sign.SignJWT.md) using the `SignJWT` class
32
- - [Verification & JWT Claims Set Validation](docs/functions/jwt_verify.jwtVerify.md) using the `jwtVerify` function
33
- - [Using a remote JWKS](docs/functions/jwks_remote.createRemoteJWKSet.md)
34
- - [Using a local JWKS](docs/functions/jwks_local.createLocalJWKSet.md)
35
35
  - Utility functions
36
36
  - [Decoding Token's Protected Header](docs/functions/util_decode_protected_header.decodeProtectedHeader.md)
37
37
  - [Decoding JWT Claims Set](docs/functions/util_decode_jwt.decodeJwt.md) prior to its validation
@@ -40,8 +40,8 @@ The `jose` module supports JSON Web Tokens (JWT) and provides functionality for
40
40
 
41
41
  The `jose` module supports encrypted JSON Web Tokens and provides functionality for encrypting and decrypting tokens, as well as their JWT Claims Set validation.
42
42
 
43
- - [Encryption](docs/classes/jwt_encrypt.EncryptJWT.md) using the `EncryptJWT` class
44
43
  - [Decryption & JWT Claims Set Validation](docs/functions/jwt_decrypt.jwtDecrypt.md) using the `jwtDecrypt` function
44
+ - [Encryption](docs/classes/jwt_encrypt.EncryptJWT.md) using the `EncryptJWT` class
45
45
  - Utility functions
46
46
  - [Decoding Token's Protected Header](docs/functions/util_decode_protected_header.decodeProtectedHeader.md)
47
47
 
@@ -68,8 +68,8 @@ The `jose` module supports signing and verification of JWS messages with arbitra
68
68
 
69
69
  - Signing - [Compact](docs/classes/jws_compact_sign.CompactSign.md), [Flattened JSON](docs/classes/jws_flattened_sign.FlattenedSign.md), [General JSON](docs/classes/jws_general_sign.GeneralSign.md)
70
70
  - Verification - [Compact](docs/functions/jws_compact_verify.compactVerify.md), [Flattened JSON](docs/functions/jws_flattened_verify.flattenedVerify.md), [General JSON](docs/functions/jws_general_verify.generalVerify.md)
71
- - [Verify using a remote JWKS](docs/functions/jwks_remote.createRemoteJWKSet.md)
72
- - [Verify using a local JWKS](docs/functions/jwks_local.createLocalJWKSet.md)
71
+ - [Using a remote JSON Web Key Set (JWKS)](docs/functions/jwks_remote.createRemoteJWKSet.md)
72
+ - [Using a local JSON Web Key Set (JWKS)](docs/functions/jwks_local.createLocalJWKSet.md)
73
73
  - Utility functions
74
74
  - [Decoding Token's Protected Header](docs/functions/util_decode_protected_header.decodeProtectedHeader.md)
75
75
 
@@ -131,7 +131,7 @@ export async function flattenedDecrypt(jwe, key, options) {
131
131
  catch {
132
132
  throw new JWEInvalid('Failed to base64url decode the ciphertext');
133
133
  }
134
- let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
134
+ const plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
135
135
  const result = { plaintext };
136
136
  if (jwe.protected !== undefined) {
137
137
  result.protectedHeader = parsedProt;
@@ -68,7 +68,7 @@ export class GeneralEncrypt {
68
68
  .setSharedUnprotectedHeader(this._unprotectedHeader)
69
69
  .setUnprotectedHeader(recipient.unprotectedHeader)
70
70
  .encrypt(recipient.key, { ...recipient.options });
71
- let jwe = {
71
+ const jwe = {
72
72
  ciphertext: flattened.ciphertext,
73
73
  iv: flattened.iv,
74
74
  recipients: [{}],
@@ -119,7 +119,7 @@ export class GeneralEncrypt {
119
119
  }
120
120
  }
121
121
  const cek = generateCek(enc);
122
- let jwe = {
122
+ const jwe = {
123
123
  ciphertext: '',
124
124
  iv: '',
125
125
  recipients: [],
@@ -79,7 +79,7 @@ export class LocalJWKSet {
79
79
  if (length === 0) {
80
80
  throw new JWKSNoMatchingKey();
81
81
  }
82
- else if (length !== 1) {
82
+ if (length !== 1) {
83
83
  const error = new JWKSMultipleMatchingKeys();
84
84
  const { _cached } = this;
85
85
  error[Symbol.asyncIterator] = async function* () {
@@ -87,9 +87,7 @@ export class LocalJWKSet {
87
87
  try {
88
88
  yield await importWithAlgCache(_cached, jwk, alg);
89
89
  }
90
- catch {
91
- continue;
92
- }
90
+ catch { }
93
91
  }
94
92
  };
95
93
  throw error;
@@ -110,7 +108,5 @@ async function importWithAlgCache(cache, jwk, alg) {
110
108
  }
111
109
  export function createLocalJWKSet(jwks) {
112
110
  const set = new LocalJWKSet(jwks);
113
- return async function (protectedHeader, token) {
114
- return set.getKey(protectedHeader, token);
115
- };
111
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
116
112
  }
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
9
9
  let USER_AGENT;
10
10
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
11
11
  const NAME = 'jose';
12
- const VERSION = 'v5.1.3';
12
+ const VERSION = 'v5.2.1';
13
13
  USER_AGENT = `${NAME}/${VERSION}`;
14
14
  }
15
15
  class RemoteJWKSet extends LocalJWKSet {
@@ -81,7 +81,5 @@ class RemoteJWKSet extends LocalJWKSet {
81
81
  }
82
82
  export function createRemoteJWKSet(url, options) {
83
83
  const set = new RemoteJWKSet(url, options);
84
- return async function (protectedHeader, token) {
85
- return set.getKey(protectedHeader, token);
86
- };
84
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
87
85
  }
@@ -61,6 +61,12 @@ export class ProduceJWT {
61
61
  else if (input instanceof Date) {
62
62
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', epoch(input)) };
63
63
  }
64
+ else if (typeof input === 'string') {
65
+ this._payload = {
66
+ ...this._payload,
67
+ iat: validateInput('setIssuedAt', epoch(new Date()) + secs(input)),
68
+ };
69
+ }
64
70
  else {
65
71
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', input) };
66
72
  }
@@ -6,10 +6,10 @@ export function concat(...buffers) {
6
6
  const size = buffers.reduce((acc, { length }) => acc + length, 0);
7
7
  const buf = new Uint8Array(size);
8
8
  let i = 0;
9
- buffers.forEach((buffer) => {
9
+ for (const buffer of buffers) {
10
10
  buf.set(buffer, i);
11
11
  i += buffer.length;
12
- });
12
+ }
13
13
  return buf;
14
14
  }
15
15
  export function p2s(alg, p2sInput) {
@@ -16,7 +16,7 @@ function message(msg, actual, ...types) {
16
16
  msg += ` Received function ${actual.name}`;
17
17
  }
18
18
  else if (typeof actual === 'object' && actual != null) {
19
- if (actual.constructor && actual.constructor.name) {
19
+ if (actual.constructor?.name) {
20
20
  msg += ` Received an instance of ${actual.constructor.name}`;
21
21
  }
22
22
  }
@@ -3,42 +3,53 @@ const hour = minute * 60;
3
3
  const day = hour * 24;
4
4
  const week = day * 7;
5
5
  const year = day * 365.25;
6
- const REGEX = /^(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)$/i;
6
+ 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;
7
7
  export default (str) => {
8
8
  const matched = REGEX.exec(str);
9
- if (!matched) {
9
+ if (!matched || (matched[4] && matched[1])) {
10
10
  throw new TypeError('Invalid time period format');
11
11
  }
12
- const value = parseFloat(matched[1]);
13
- const unit = matched[2].toLowerCase();
12
+ const value = parseFloat(matched[2]);
13
+ const unit = matched[3].toLowerCase();
14
+ let numericDate;
14
15
  switch (unit) {
15
16
  case 'sec':
16
17
  case 'secs':
17
18
  case 'second':
18
19
  case 'seconds':
19
20
  case 's':
20
- return Math.round(value);
21
+ numericDate = Math.round(value);
22
+ break;
21
23
  case 'minute':
22
24
  case 'minutes':
23
25
  case 'min':
24
26
  case 'mins':
25
27
  case 'm':
26
- return Math.round(value * minute);
28
+ numericDate = Math.round(value * minute);
29
+ break;
27
30
  case 'hour':
28
31
  case 'hours':
29
32
  case 'hr':
30
33
  case 'hrs':
31
34
  case 'h':
32
- return Math.round(value * hour);
35
+ numericDate = Math.round(value * hour);
36
+ break;
33
37
  case 'day':
34
38
  case 'days':
35
39
  case 'd':
36
- return Math.round(value * day);
40
+ numericDate = Math.round(value * day);
41
+ break;
37
42
  case 'week':
38
43
  case 'weeks':
39
44
  case 'w':
40
- return Math.round(value * week);
45
+ numericDate = Math.round(value * week);
46
+ break;
41
47
  default:
42
- return Math.round(value * year);
48
+ numericDate = Math.round(value * year);
49
+ break;
43
50
  }
51
+ if (matched[1] === '-' || matched[4] === 'ago') {
52
+ return -numericDate;
53
+ }
54
+ return numericDate;
44
55
  };
@@ -25,7 +25,7 @@ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader,
25
25
  if (joseHeader[parameter] === undefined) {
26
26
  throw new Err(`Extension Header Parameter "${parameter}" is missing`);
27
27
  }
28
- else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
28
+ if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
29
29
  throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
30
30
  }
31
31
  }
@@ -27,7 +27,7 @@ const findOid = (keyData, oid, from = 0) => {
27
27
  oid.unshift(oid.length);
28
28
  oid.unshift(0x06);
29
29
  }
30
- let i = keyData.indexOf(oid[0], from);
30
+ const i = keyData.indexOf(oid[0], from);
31
31
  if (i === -1)
32
32
  return false;
33
33
  const sub = keyData.subarray(i, i + oid.length);
@@ -122,10 +122,10 @@ export const fromSPKI = (pem, alg, options) => {
122
122
  return genericImport(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, 'spki', pem, alg, options);
123
123
  };
124
124
  function getElement(seq) {
125
- let result = [];
125
+ const result = [];
126
126
  let next = 0;
127
127
  while (next < seq.length) {
128
- let nextPart = parseElement(seq.subarray(next));
128
+ const nextPart = parseElement(seq.subarray(next));
129
129
  result.push(nextPart);
130
130
  next += nextPart.byteLength;
131
131
  }
@@ -165,7 +165,7 @@ function parseElement(bytes) {
165
165
  };
166
166
  }
167
167
  else {
168
- let numberOfDigits = bytes[position] & 0x7f;
168
+ const numberOfDigits = bytes[position] & 0x7f;
169
169
  position++;
170
170
  length = 0;
171
171
  for (let i = 0; i < numberOfDigits; i++) {
@@ -97,7 +97,7 @@ export async function generateKeyPair(alg, options) {
97
97
  algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
98
98
  keyUsages = ['sign', 'verify'];
99
99
  break;
100
- case 'EdDSA':
100
+ case 'EdDSA': {
101
101
  keyUsages = ['sign', 'verify'];
102
102
  const crv = options?.crv ?? 'Ed25519';
103
103
  switch (crv) {
@@ -109,6 +109,7 @@ export async function generateKeyPair(alg, options) {
109
109
  throw new JOSENotSupported('Invalid or unsupported crv option provided');
110
110
  }
111
111
  break;
112
+ }
112
113
  case 'ECDH-ES':
113
114
  case 'ECDH-ES+A128KW':
114
115
  case 'ECDH-ES+A192KW':
@@ -134,7 +134,7 @@ async function flattenedDecrypt(jwe, key, options) {
134
134
  catch {
135
135
  throw new errors_js_1.JWEInvalid('Failed to base64url decode the ciphertext');
136
136
  }
137
- let plaintext = await (0, decrypt_js_1.default)(enc, cek, ciphertext, iv, tag, additionalData);
137
+ const plaintext = await (0, decrypt_js_1.default)(enc, cek, ciphertext, iv, tag, additionalData);
138
138
  const result = { plaintext };
139
139
  if (jwe.protected !== undefined) {
140
140
  result.protectedHeader = parsedProt;
@@ -79,7 +79,7 @@ class GeneralEncrypt {
79
79
  .setSharedUnprotectedHeader(this._unprotectedHeader)
80
80
  .setUnprotectedHeader(recipient.unprotectedHeader)
81
81
  .encrypt(recipient.key, { ...recipient.options });
82
- let jwe = {
82
+ const jwe = {
83
83
  ciphertext: flattened.ciphertext,
84
84
  iv: flattened.iv,
85
85
  recipients: [{}],
@@ -130,7 +130,7 @@ class GeneralEncrypt {
130
130
  }
131
131
  }
132
132
  const cek = (0, cek_js_1.default)(enc);
133
- let jwe = {
133
+ const jwe = {
134
134
  ciphertext: '',
135
135
  iv: '',
136
136
  recipients: [],
@@ -84,7 +84,7 @@ class LocalJWKSet {
84
84
  if (length === 0) {
85
85
  throw new errors_js_1.JWKSNoMatchingKey();
86
86
  }
87
- else if (length !== 1) {
87
+ if (length !== 1) {
88
88
  const error = new errors_js_1.JWKSMultipleMatchingKeys();
89
89
  const { _cached } = this;
90
90
  error[Symbol.asyncIterator] = async function* () {
@@ -92,9 +92,7 @@ class LocalJWKSet {
92
92
  try {
93
93
  yield await importWithAlgCache(_cached, jwk, alg);
94
94
  }
95
- catch {
96
- continue;
97
- }
95
+ catch { }
98
96
  }
99
97
  };
100
98
  throw error;
@@ -116,8 +114,6 @@ async function importWithAlgCache(cache, jwk, alg) {
116
114
  }
117
115
  function createLocalJWKSet(jwks) {
118
116
  const set = new LocalJWKSet(jwks);
119
- return async function (protectedHeader, token) {
120
- return set.getKey(protectedHeader, token);
121
- };
117
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
122
118
  }
123
119
  exports.createLocalJWKSet = createLocalJWKSet;
@@ -12,7 +12,7 @@ function isCloudflareWorkers() {
12
12
  let USER_AGENT;
13
13
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
14
14
  const NAME = 'jose';
15
- const VERSION = 'v5.1.3';
15
+ const VERSION = 'v5.2.1';
16
16
  USER_AGENT = `${NAME}/${VERSION}`;
17
17
  }
18
18
  class RemoteJWKSet extends local_js_1.LocalJWKSet {
@@ -91,8 +91,6 @@ class RemoteJWKSet extends local_js_1.LocalJWKSet {
91
91
  }
92
92
  function createRemoteJWKSet(url, options) {
93
93
  const set = new RemoteJWKSet(url, options);
94
- return async function (protectedHeader, token) {
95
- return set.getKey(protectedHeader, token);
96
- };
94
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
97
95
  }
98
96
  exports.createRemoteJWKSet = createRemoteJWKSet;
@@ -65,6 +65,12 @@ class ProduceJWT {
65
65
  else if (input instanceof Date) {
66
66
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', (0, epoch_js_1.default)(input)) };
67
67
  }
68
+ else if (typeof input === 'string') {
69
+ this._payload = {
70
+ ...this._payload,
71
+ iat: validateInput('setIssuedAt', (0, epoch_js_1.default)(new Date()) + (0, secs_js_1.default)(input)),
72
+ };
73
+ }
68
74
  else {
69
75
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', input) };
70
76
  }
@@ -9,10 +9,10 @@ function concat(...buffers) {
9
9
  const size = buffers.reduce((acc, { length }) => acc + length, 0);
10
10
  const buf = new Uint8Array(size);
11
11
  let i = 0;
12
- buffers.forEach((buffer) => {
12
+ for (const buffer of buffers) {
13
13
  buf.set(buffer, i);
14
14
  i += buffer.length;
15
- });
15
+ }
16
16
  return buf;
17
17
  }
18
18
  exports.concat = concat;
@@ -19,7 +19,7 @@ function message(msg, actual, ...types) {
19
19
  msg += ` Received function ${actual.name}`;
20
20
  }
21
21
  else if (typeof actual === 'object' && actual != null) {
22
- if (actual.constructor && actual.constructor.name) {
22
+ if (actual.constructor?.name) {
23
23
  msg += ` Received an instance of ${actual.constructor.name}`;
24
24
  }
25
25
  }
@@ -5,42 +5,53 @@ const hour = minute * 60;
5
5
  const day = hour * 24;
6
6
  const week = day * 7;
7
7
  const year = day * 365.25;
8
- const REGEX = /^(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)$/i;
8
+ 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;
9
9
  exports.default = (str) => {
10
10
  const matched = REGEX.exec(str);
11
- if (!matched) {
11
+ if (!matched || (matched[4] && matched[1])) {
12
12
  throw new TypeError('Invalid time period format');
13
13
  }
14
- const value = parseFloat(matched[1]);
15
- const unit = matched[2].toLowerCase();
14
+ const value = parseFloat(matched[2]);
15
+ const unit = matched[3].toLowerCase();
16
+ let numericDate;
16
17
  switch (unit) {
17
18
  case 'sec':
18
19
  case 'secs':
19
20
  case 'second':
20
21
  case 'seconds':
21
22
  case 's':
22
- return Math.round(value);
23
+ numericDate = Math.round(value);
24
+ break;
23
25
  case 'minute':
24
26
  case 'minutes':
25
27
  case 'min':
26
28
  case 'mins':
27
29
  case 'm':
28
- return Math.round(value * minute);
30
+ numericDate = Math.round(value * minute);
31
+ break;
29
32
  case 'hour':
30
33
  case 'hours':
31
34
  case 'hr':
32
35
  case 'hrs':
33
36
  case 'h':
34
- return Math.round(value * hour);
37
+ numericDate = Math.round(value * hour);
38
+ break;
35
39
  case 'day':
36
40
  case 'days':
37
41
  case 'd':
38
- return Math.round(value * day);
42
+ numericDate = Math.round(value * day);
43
+ break;
39
44
  case 'week':
40
45
  case 'weeks':
41
46
  case 'w':
42
- return Math.round(value * week);
47
+ numericDate = Math.round(value * week);
48
+ break;
43
49
  default:
44
- return Math.round(value * year);
50
+ numericDate = Math.round(value * year);
51
+ break;
45
52
  }
53
+ if (matched[1] === '-' || matched[4] === 'ago') {
54
+ return -numericDate;
55
+ }
56
+ return numericDate;
46
57
  };
@@ -27,7 +27,7 @@ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader,
27
27
  if (joseHeader[parameter] === undefined) {
28
28
  throw new Err(`Extension Header Parameter "${parameter}" is missing`);
29
29
  }
30
- else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
30
+ if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
31
31
  throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
32
32
  }
33
33
  }
@@ -79,7 +79,7 @@ async function generateKeyPair(alg, options) {
79
79
  case 'ECDH-ES':
80
80
  case 'ECDH-ES+A128KW':
81
81
  case 'ECDH-ES+A192KW':
82
- case 'ECDH-ES+A256KW':
82
+ case 'ECDH-ES+A256KW': {
83
83
  const crv = options?.crv ?? 'P-256';
84
84
  switch (crv) {
85
85
  case undefined:
@@ -94,6 +94,7 @@ async function generateKeyPair(alg, options) {
94
94
  default:
95
95
  throw new errors_js_1.JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448');
96
96
  }
97
+ }
97
98
  default:
98
99
  throw new errors_js_1.JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
99
100
  }
@@ -44,7 +44,7 @@ const getNamedCurve = (kee, raw) => {
44
44
  case 'x448':
45
45
  return `X${key.asymmetricKeyType.slice(1)}`;
46
46
  case 'ec': {
47
- let namedCurve = key.asymmetricKeyDetails.namedCurve;
47
+ const namedCurve = key.asymmetricKeyDetails.namedCurve;
48
48
  if (raw) {
49
49
  return namedCurve;
50
50
  }
@@ -131,7 +131,7 @@ export async function flattenedDecrypt(jwe, key, options) {
131
131
  catch {
132
132
  throw new JWEInvalid('Failed to base64url decode the ciphertext');
133
133
  }
134
- let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
134
+ const plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
135
135
  const result = { plaintext };
136
136
  if (jwe.protected !== undefined) {
137
137
  result.protectedHeader = parsedProt;
@@ -76,7 +76,7 @@ export class GeneralEncrypt {
76
76
  .setSharedUnprotectedHeader(this._unprotectedHeader)
77
77
  .setUnprotectedHeader(recipient.unprotectedHeader)
78
78
  .encrypt(recipient.key, { ...recipient.options });
79
- let jwe = {
79
+ const jwe = {
80
80
  ciphertext: flattened.ciphertext,
81
81
  iv: flattened.iv,
82
82
  recipients: [{}],
@@ -127,7 +127,7 @@ export class GeneralEncrypt {
127
127
  }
128
128
  }
129
129
  const cek = generateCek(enc);
130
- let jwe = {
130
+ const jwe = {
131
131
  ciphertext: '',
132
132
  iv: '',
133
133
  recipients: [],
@@ -80,7 +80,7 @@ export class LocalJWKSet {
80
80
  if (length === 0) {
81
81
  throw new JWKSNoMatchingKey();
82
82
  }
83
- else if (length !== 1) {
83
+ if (length !== 1) {
84
84
  const error = new JWKSMultipleMatchingKeys();
85
85
  const { _cached } = this;
86
86
  error[Symbol.asyncIterator] = async function* () {
@@ -88,9 +88,7 @@ export class LocalJWKSet {
88
88
  try {
89
89
  yield await importWithAlgCache(_cached, jwk, alg);
90
90
  }
91
- catch {
92
- continue;
93
- }
91
+ catch { }
94
92
  }
95
93
  };
96
94
  throw error;
@@ -111,7 +109,5 @@ async function importWithAlgCache(cache, jwk, alg) {
111
109
  }
112
110
  export function createLocalJWKSet(jwks) {
113
111
  const set = new LocalJWKSet(jwks);
114
- return async function (protectedHeader, token) {
115
- return set.getKey(protectedHeader, token);
116
- };
112
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
117
113
  }
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
9
9
  let USER_AGENT;
10
10
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
11
11
  const NAME = 'jose';
12
- const VERSION = 'v5.1.3';
12
+ const VERSION = 'v5.2.1';
13
13
  USER_AGENT = `${NAME}/${VERSION}`;
14
14
  }
15
15
  class RemoteJWKSet extends LocalJWKSet {
@@ -88,7 +88,5 @@ class RemoteJWKSet extends LocalJWKSet {
88
88
  }
89
89
  export function createRemoteJWKSet(url, options) {
90
90
  const set = new RemoteJWKSet(url, options);
91
- return async function (protectedHeader, token) {
92
- return set.getKey(protectedHeader, token);
93
- };
91
+ return async (protectedHeader, token) => set.getKey(protectedHeader, token);
94
92
  }
@@ -62,6 +62,12 @@ export class ProduceJWT {
62
62
  else if (input instanceof Date) {
63
63
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', epoch(input)) };
64
64
  }
65
+ else if (typeof input === 'string') {
66
+ this._payload = {
67
+ ...this._payload,
68
+ iat: validateInput('setIssuedAt', epoch(new Date()) + secs(input)),
69
+ };
70
+ }
65
71
  else {
66
72
  this._payload = { ...this._payload, iat: validateInput('setIssuedAt', input) };
67
73
  }
@@ -6,10 +6,10 @@ export function concat(...buffers) {
6
6
  const size = buffers.reduce((acc, { length }) => acc + length, 0);
7
7
  const buf = new Uint8Array(size);
8
8
  let i = 0;
9
- buffers.forEach((buffer) => {
9
+ for (const buffer of buffers) {
10
10
  buf.set(buffer, i);
11
11
  i += buffer.length;
12
- });
12
+ }
13
13
  return buf;
14
14
  }
15
15
  export function p2s(alg, p2sInput) {
@@ -16,7 +16,7 @@ function message(msg, actual, ...types) {
16
16
  msg += ` Received function ${actual.name}`;
17
17
  }
18
18
  else if (typeof actual === 'object' && actual != null) {
19
- if (actual.constructor && actual.constructor.name) {
19
+ if (actual.constructor?.name) {
20
20
  msg += ` Received an instance of ${actual.constructor.name}`;
21
21
  }
22
22
  }
@@ -3,42 +3,53 @@ const hour = minute * 60;
3
3
  const day = hour * 24;
4
4
  const week = day * 7;
5
5
  const year = day * 365.25;
6
- const REGEX = /^(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)$/i;
6
+ 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;
7
7
  export default (str) => {
8
8
  const matched = REGEX.exec(str);
9
- if (!matched) {
9
+ if (!matched || (matched[4] && matched[1])) {
10
10
  throw new TypeError('Invalid time period format');
11
11
  }
12
- const value = parseFloat(matched[1]);
13
- const unit = matched[2].toLowerCase();
12
+ const value = parseFloat(matched[2]);
13
+ const unit = matched[3].toLowerCase();
14
+ let numericDate;
14
15
  switch (unit) {
15
16
  case 'sec':
16
17
  case 'secs':
17
18
  case 'second':
18
19
  case 'seconds':
19
20
  case 's':
20
- return Math.round(value);
21
+ numericDate = Math.round(value);
22
+ break;
21
23
  case 'minute':
22
24
  case 'minutes':
23
25
  case 'min':
24
26
  case 'mins':
25
27
  case 'm':
26
- return Math.round(value * minute);
28
+ numericDate = Math.round(value * minute);
29
+ break;
27
30
  case 'hour':
28
31
  case 'hours':
29
32
  case 'hr':
30
33
  case 'hrs':
31
34
  case 'h':
32
- return Math.round(value * hour);
35
+ numericDate = Math.round(value * hour);
36
+ break;
33
37
  case 'day':
34
38
  case 'days':
35
39
  case 'd':
36
- return Math.round(value * day);
40
+ numericDate = Math.round(value * day);
41
+ break;
37
42
  case 'week':
38
43
  case 'weeks':
39
44
  case 'w':
40
- return Math.round(value * week);
45
+ numericDate = Math.round(value * week);
46
+ break;
41
47
  default:
42
- return Math.round(value * year);
48
+ numericDate = Math.round(value * year);
49
+ break;
43
50
  }
51
+ if (matched[1] === '-' || matched[4] === 'ago') {
52
+ return -numericDate;
53
+ }
54
+ return numericDate;
44
55
  };
@@ -25,7 +25,7 @@ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader,
25
25
  if (joseHeader[parameter] === undefined) {
26
26
  throw new Err(`Extension Header Parameter "${parameter}" is missing`);
27
27
  }
28
- else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
28
+ if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
29
29
  throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
30
30
  }
31
31
  }
@@ -75,7 +75,7 @@ export async function generateKeyPair(alg, options) {
75
75
  case 'ECDH-ES':
76
76
  case 'ECDH-ES+A128KW':
77
77
  case 'ECDH-ES+A192KW':
78
- case 'ECDH-ES+A256KW':
78
+ case 'ECDH-ES+A256KW': {
79
79
  const crv = options?.crv ?? 'P-256';
80
80
  switch (crv) {
81
81
  case undefined:
@@ -90,6 +90,7 @@ export async function generateKeyPair(alg, options) {
90
90
  default:
91
91
  throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448');
92
92
  }
93
+ }
93
94
  default:
94
95
  throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
95
96
  }
@@ -41,7 +41,7 @@ const getNamedCurve = (kee, raw) => {
41
41
  case 'x448':
42
42
  return `X${key.asymmetricKeyType.slice(1)}`;
43
43
  case 'ec': {
44
- let namedCurve = key.asymmetricKeyDetails.namedCurve;
44
+ const namedCurve = key.asymmetricKeyDetails.namedCurve;
45
45
  if (raw) {
46
46
  return namedCurve;
47
47
  }
@@ -31,24 +31,74 @@ export declare class ProduceJWT {
31
31
  /**
32
32
  * Set the "nbf" (Not Before) Claim.
33
33
  *
34
- * @param input "nbf" (Not Before) Claim value to set on the JWT Claims Set. When number is passed
35
- * that is used as a value, when string is passed it is resolved to a time span and added to the
36
- * current timestamp.
34
+ * - If a `number` is passed as an argument it is used as the claim directly.
35
+ * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the
36
+ * claim.
37
+ * - If a `string` is passed as an argument it is resolved to a time span, and then added to the
38
+ * current unix timestamp and used as the claim.
39
+ *
40
+ * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1
41
+ * day".
42
+ *
43
+ * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins",
44
+ * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year",
45
+ * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an
46
+ * alias for a year.
47
+ *
48
+ * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets
49
+ * subtracted from the current unix timestamp. A "from now" suffix can also be used for
50
+ * readability when adding to the current unix timestamp.
51
+ *
52
+ * @param input "nbf" (Not Before) Claim value to set on the JWT Claims Set.
37
53
  */
38
54
  setNotBefore(input: number | string | Date): this;
39
55
  /**
40
56
  * Set the "exp" (Expiration Time) Claim.
41
57
  *
42
- * @param input "exp" (Expiration Time) Claim value to set on the JWT Claims Set. When number is
43
- * passed that is used as a value, when string is passed it is resolved to a time span and added
44
- * to the current timestamp.
58
+ * - If a `number` is passed as an argument it is used as the claim directly.
59
+ * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the
60
+ * claim.
61
+ * - If a `string` is passed as an argument it is resolved to a time span, and then added to the
62
+ * current unix timestamp and used as the claim.
63
+ *
64
+ * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1
65
+ * day".
66
+ *
67
+ * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins",
68
+ * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year",
69
+ * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an
70
+ * alias for a year.
71
+ *
72
+ * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets
73
+ * subtracted from the current unix timestamp. A "from now" suffix can also be used for
74
+ * readability when adding to the current unix timestamp.
75
+ *
76
+ * @param input "exp" (Expiration Time) Claim value to set on the JWT Claims Set.
45
77
  */
46
78
  setExpirationTime(input: number | string | Date): this;
47
79
  /**
48
80
  * Set the "iat" (Issued At) Claim.
49
81
  *
50
- * @param input "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current
51
- * timestamp.
82
+ * - If no argument is used the current unix timestamp is used as the claim.
83
+ * - If a `number` is passed as an argument it is used as the claim directly.
84
+ * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the
85
+ * claim.
86
+ * - If a `string` is passed as an argument it is resolved to a time span, and then added to the
87
+ * current unix timestamp and used as the claim.
88
+ *
89
+ * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1
90
+ * day".
91
+ *
92
+ * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins",
93
+ * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year",
94
+ * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an
95
+ * alias for a year.
96
+ *
97
+ * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets
98
+ * subtracted from the current unix timestamp. A "from now" suffix can also be used for
99
+ * readability when adding to the current unix timestamp.
100
+ *
101
+ * @param input "iat" (Expiration Time) Claim value to set on the JWT Claims Set.
52
102
  */
53
- setIssuedAt(input?: number | Date): this;
103
+ setIssuedAt(input?: number | string | Date): this;
54
104
  }
@@ -11,7 +11,7 @@ export interface PEMImportOptions {
11
11
  * Imports a PEM-encoded SPKI string as a runtime-specific public key representation (KeyObject or
12
12
  * CryptoKey).
13
13
  *
14
- * @param pem PEM-encoded SPKI string
14
+ * @param spki PEM-encoded SPKI string
15
15
  * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
16
16
  * with the imported key, its presence is only enforced in Web Crypto API runtimes. See
17
17
  * {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements}.
@@ -21,7 +21,7 @@ export declare function importSPKI<KeyLikeType extends KeyLike = KeyLike>(spki:
21
21
  * Imports the SPKI from an X.509 string certificate as a runtime-specific public key representation
22
22
  * (KeyObject or CryptoKey).
23
23
  *
24
- * @param pem X.509 certificate string
24
+ * @param x509 X.509 certificate string
25
25
  * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
26
26
  * with the imported key, its presence is only enforced in Web Crypto API runtimes. See
27
27
  * {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements}.
@@ -31,7 +31,7 @@ export declare function importX509<KeyLikeType extends KeyLike = KeyLike>(x509:
31
31
  * Imports a PEM-encoded PKCS#8 string as a runtime-specific private key representation (KeyObject
32
32
  * or CryptoKey).
33
33
  *
34
- * @param pem PEM-encoded PKCS#8 string
34
+ * @param pkcs8 PEM-encoded PKCS#8 string
35
35
  * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
36
36
  * with the imported key, its presence is only enforced in Web Crypto API runtimes. See
37
37
  * {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements}.
@@ -4,10 +4,15 @@ import type { KeyLike } from '../types';
4
4
  *
5
5
  */
6
6
  export declare class JOSEError extends Error {
7
- /** A unique error code for the particular error subclass. */
7
+ /**
8
+ * A unique error code for the particular error subclass.
9
+ *
10
+ * @ignore
11
+ */
8
12
  static get code(): string;
9
- /** A unique error code for the particular error subclass. */
13
+ /** A unique error code for this particular error subclass. */
10
14
  code: string;
15
+ /** @ignore */
11
16
  constructor(message?: string);
12
17
  }
13
18
  /**
@@ -15,12 +20,14 @@ export declare class JOSEError extends Error {
15
20
  *
16
21
  */
17
22
  export declare class JWTClaimValidationFailed extends JOSEError {
23
+ /** @ignore */
18
24
  static get code(): 'ERR_JWT_CLAIM_VALIDATION_FAILED';
19
25
  code: string;
20
26
  /** The Claim for which the validation failed. */
21
27
  claim: string;
22
28
  /** Reason code for the validation failure. */
23
29
  reason: string;
30
+ /** @ignore */
24
31
  constructor(message: string, claim?: string, reason?: string);
25
32
  }
26
33
  /**
@@ -28,12 +35,14 @@ export declare class JWTClaimValidationFailed extends JOSEError {
28
35
  *
29
36
  */
30
37
  export declare class JWTExpired extends JOSEError implements JWTClaimValidationFailed {
38
+ /** @ignore */
31
39
  static get code(): 'ERR_JWT_EXPIRED';
32
40
  code: string;
33
41
  /** The Claim for which the validation failed. */
34
42
  claim: string;
35
43
  /** Reason code for the validation failure. */
36
44
  reason: string;
45
+ /** @ignore */
37
46
  constructor(message: string, claim?: string, reason?: string);
38
47
  }
39
48
  /**
@@ -41,6 +50,7 @@ export declare class JWTExpired extends JOSEError implements JWTClaimValidationF
41
50
  *
42
51
  */
43
52
  export declare class JOSEAlgNotAllowed extends JOSEError {
53
+ /** @ignore */
44
54
  static get code(): 'ERR_JOSE_ALG_NOT_ALLOWED';
45
55
  code: string;
46
56
  }
@@ -50,6 +60,7 @@ export declare class JOSEAlgNotAllowed extends JOSEError {
50
60
  *
51
61
  */
52
62
  export declare class JOSENotSupported extends JOSEError {
63
+ /** @ignore */
53
64
  static get code(): 'ERR_JOSE_NOT_SUPPORTED';
54
65
  code: string;
55
66
  }
@@ -58,6 +69,7 @@ export declare class JOSENotSupported extends JOSEError {
58
69
  *
59
70
  */
60
71
  export declare class JWEDecryptionFailed extends JOSEError {
72
+ /** @ignore */
61
73
  static get code(): 'ERR_JWE_DECRYPTION_FAILED';
62
74
  code: string;
63
75
  message: string;
@@ -67,6 +79,7 @@ export declare class JWEDecryptionFailed extends JOSEError {
67
79
  *
68
80
  */
69
81
  export declare class JWEInvalid extends JOSEError {
82
+ /** @ignore */
70
83
  static get code(): 'ERR_JWE_INVALID';
71
84
  code: string;
72
85
  }
@@ -75,6 +88,7 @@ export declare class JWEInvalid extends JOSEError {
75
88
  *
76
89
  */
77
90
  export declare class JWSInvalid extends JOSEError {
91
+ /** @ignore */
78
92
  static get code(): 'ERR_JWS_INVALID';
79
93
  code: string;
80
94
  }
@@ -83,6 +97,7 @@ export declare class JWSInvalid extends JOSEError {
83
97
  *
84
98
  */
85
99
  export declare class JWTInvalid extends JOSEError {
100
+ /** @ignore */
86
101
  static get code(): 'ERR_JWT_INVALID';
87
102
  code: string;
88
103
  }
@@ -91,6 +106,7 @@ export declare class JWTInvalid extends JOSEError {
91
106
  *
92
107
  */
93
108
  export declare class JWKInvalid extends JOSEError {
109
+ /** @ignore */
94
110
  static get code(): 'ERR_JWK_INVALID';
95
111
  code: string;
96
112
  }
@@ -99,6 +115,7 @@ export declare class JWKInvalid extends JOSEError {
99
115
  *
100
116
  */
101
117
  export declare class JWKSInvalid extends JOSEError {
118
+ /** @ignore */
102
119
  static get code(): 'ERR_JWKS_INVALID';
103
120
  code: string;
104
121
  }
@@ -107,6 +124,7 @@ export declare class JWKSInvalid extends JOSEError {
107
124
  *
108
125
  */
109
126
  export declare class JWKSNoMatchingKey extends JOSEError {
127
+ /** @ignore */
110
128
  static get code(): 'ERR_JWKS_NO_MATCHING_KEY';
111
129
  code: string;
112
130
  message: string;
@@ -127,6 +145,7 @@ export declare class JWKSMultipleMatchingKeys extends JOSEError {
127
145
  *
128
146
  */
129
147
  export declare class JWKSTimeout extends JOSEError {
148
+ /** @ignore */
130
149
  static get code(): 'ERR_JWKS_TIMEOUT';
131
150
  code: string;
132
151
  message: string;
@@ -136,6 +155,7 @@ export declare class JWKSTimeout extends JOSEError {
136
155
  *
137
156
  */
138
157
  export declare class JWSSignatureVerificationFailed extends JOSEError {
158
+ /** @ignore */
139
159
  static get code(): 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
140
160
  code: string;
141
161
  message: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "5.1.3",
4
- "description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
3
+ "version": "5.2.1",
4
+ "description": "JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
5
5
  "keywords": [
6
6
  "browser",
7
7
  "bun",