unjwt 0.8.3 → 0.8.4

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.
@@ -1,6 +1,6 @@
1
1
  import { sanitizeObjectCopy } from "./libs/unsecure.mjs";
2
2
  import { JWTError, computeDurationInSeconds, expiredClaimMessage, isCryptoKey, isJWK, isJWKSet, isJWTError, isPlainObject, isPrivateJWK, isPublicJWK, isSymmetricJWK } from "./_jwt-internal.mjs";
3
- import { importKey, quoteTokenValue } from "./jwk.mjs";
3
+ import { importKey, quoteTokenValue } from "./_import-key.mjs";
4
4
  import { sign, verify } from "./jws.mjs";
5
5
  import { decrypt, encrypt } from "./jwe.mjs";
6
6
  const RESERVED_CLAIMS = [
@@ -46,8 +46,8 @@ function rethrowAsInvalidToken(error, options) {
46
46
  const TOKEN = /^[!#$%&'*+\-.^_`|~\w]+$/;
47
47
  const CHUNK_SUFFIX = /\.\d+$/;
48
48
  function assertSessionName(name, options) {
49
- if (!isToken(name)) throw invalidConfigError(`${options.prefix} Session "name" must be a cookie name (RFC 6265 §4.1.1): letters, digits and !#$%&'*+-.^_\`|~ only. Got ${quoteTokenValue(name)}.`);
50
- if (CHUNK_SUFFIX.test(name)) throw invalidConfigError(`${options.prefix} Session "name" cannot end in a dot and digits: ${quoteTokenValue(name)} is the cookie holding a chunk of the session named ${quoteTokenValue(name.replace(CHUNK_SUFFIX, ""))}.`);
49
+ if (!isToken(name)) throw invalidConfigError(`${options.prefix} Session "name" must be a valid cookie name (got ${quoteTokenValue(name)}).`);
50
+ if (CHUNK_SUFFIX.test(name)) throw invalidConfigError(`${options.prefix} Session "name" ${quoteTokenValue(name)} cannot end in a dot and digits.`);
51
51
  }
52
52
  function isToken(value) {
53
53
  return typeof value === "string" && TOKEN.test(value);
@@ -57,7 +57,7 @@ function assertCookiePrefix(name, attrs, options) {
57
57
  const host = lower.startsWith("__host-");
58
58
  if (!host && !lower.startsWith("__secure-")) return;
59
59
  const rule = host ? "\"__Host-\" cookie must be Secure, with Path=/ and no Domain" : "\"__Secure-\" cookie must be Secure";
60
- if (attrs.secure === false || host && (attrs.domain !== void 0 || attrs.path !== void 0 && attrs.path !== "/")) throw invalidConfigError(`${options.prefix} Session ${quoteTokenValue(name)}: a ${rule} (RFC 6265bis §4.1.3).`);
60
+ if (attrs.secure === false || host && (attrs.domain !== void 0 || attrs.path !== void 0 && attrs.path !== "/")) throw invalidConfigError(`${options.prefix} Session ${quoteTokenValue(name)}: a ${rule}.`);
61
61
  }
62
62
  function assertRolling(config, options) {
63
63
  const { rolling } = config;
@@ -65,10 +65,10 @@ function assertRolling(config, options) {
65
65
  if (config.maxAge === void 0) throw invalidConfigError(`${options.prefix} "rolling" needs a "maxAge" to extend.`);
66
66
  if (rolling === true) return;
67
67
  if (!isExpiresIn(rolling)) throw new JWTError(`${options.prefix} "rolling" must be true or a duration.`, "ERR_INVALID_OPTION");
68
- if (computeDurationInSeconds(rolling) >= computeDurationInSeconds(config.maxAge)) throw invalidConfigError(`${options.prefix} "rolling" must be shorter than "maxAge": the session would expire before it rolls.`);
68
+ if (computeDurationInSeconds(rolling) >= computeDurationInSeconds(config.maxAge)) throw invalidConfigError(`${options.prefix} "rolling" must be shorter than "maxAge".`);
69
69
  }
70
70
  function assertKeyMaterial(key, options) {
71
- if (typeof key === "string") throw invalidKeyError(`${options.prefix} Session "key" must be a JWK or a CryptoKey, not a password string. Derive one once with deriveJWKFromPassword() and pass the result.`);
71
+ if (typeof key === "string") throw invalidKeyError(`${options.prefix} Session "key" cannot be a string, use deriveJWKFromPassword().`);
72
72
  if (!key) throw invalidKeyError(`${options.prefix} Session "key" is required.`);
73
73
  }
74
74
  async function assertImportableKey(key, options) {
@@ -109,7 +109,7 @@ function sessionRequiredClaims(configured, options) {
109
109
  return [...required];
110
110
  }
111
111
  function sanitizeSessionUpdate(update, options) {
112
- if (!isPlainObject(update)) throw new JWTError(`${options.prefix} Session data must be a plain object, got ${Array.isArray(update) ? "an array" : typeof update}.`, "ERR_INVALID_OPTION");
112
+ if (!isPlainObject(update)) throw new JWTError(`${options.prefix} Session data must be a plain object.`, "ERR_INVALID_OPTION");
113
113
  const sanitized = Object.create(null);
114
114
  for (const key of Object.keys(update)) {
115
115
  if (FORBIDDEN_KEYS.includes(key)) throw new JWTError(`${options.prefix} Session data cannot carry the key "${key}".`, "ERR_INVALID_OPTION");
@@ -205,7 +205,7 @@ function assertKeyPair(pair, options) {
205
205
  if (!options.isPublic(pair.publicKey)) throw invalidKeyError(`${prefix} Invalid ${family} key: "publicKey" must be ${options.publicHalf}.`, pair);
206
206
  }
207
207
  function assertPinnedCryptoKey(key, options) {
208
- if (isCryptoKey(key) && !options.pinned) throw invalidConfigError(`${options.prefix} A CryptoKey session key carries no algorithm: set ${options.hint}.`);
208
+ if (isCryptoKey(key) && !options.pinned) throw invalidConfigError(`${options.prefix} A CryptoKey session key carries no algorithm, set ${options.hint}.`);
209
209
  }
210
210
  function sessionPayload(state) {
211
211
  const iat = Math.floor(state.createdAt / 1e3);
@@ -219,7 +219,7 @@ function sessionPayload(state) {
219
219
  }
220
220
  function assertNotFromTheFuture(payload, options) {
221
221
  const tolerance = options.clockTolerance === void 0 ? 0 : computeDurationInSeconds(options.clockTolerance);
222
- if (payload.iat > Math.floor(options.now / 1e3) + tolerance) throw invalidTokenError(`${options.prefix} Invalid session token: issued in the future (iat: ${(/* @__PURE__ */ new Date(payload.iat * 1e3)).toISOString()}).`);
222
+ if (payload.iat > Math.floor(options.now / 1e3) + tolerance) throw invalidTokenError(`${options.prefix} Invalid session token: "iat" is in the future (${(/* @__PURE__ */ new Date(payload.iat * 1e3)).toISOString()}).`);
223
223
  }
224
224
  function openedSession(payload) {
225
225
  const data = Object.create(null);
@@ -294,7 +294,7 @@ function getEncryptKey(config, prefix) {
294
294
  assertJWEKeyPair(key, prefix);
295
295
  resolved = key.publicKey;
296
296
  }
297
- if (!resolved) throw invalidKeyError(`${prefix} Invalid JWE key. It must be a JWK or a CryptoKey.`, key);
297
+ if (!resolved) throw invalidKeyError(`${prefix} Invalid JWE key, expected a JWK or a CryptoKey.`, key);
298
298
  assertPinnedAlgEnc(resolved, config, prefix);
299
299
  return resolved;
300
300
  }
@@ -307,7 +307,7 @@ function getDecryptKey(config, prefix) {
307
307
  assertJWEKeyPair(key, prefix);
308
308
  resolved = key.privateKey;
309
309
  }
310
- if (!resolved) throw invalidKeyError(`${prefix} Invalid JWE key. It must be a JWK, a private JWK, or a CryptoKey.`, key);
310
+ if (!resolved) throw invalidKeyError(`${prefix} Invalid JWE key, expected a JWK, a private JWK or a CryptoKey.`, key);
311
311
  assertPinnedAlgEnc(resolved, config, prefix);
312
312
  return resolved;
313
313
  }
@@ -448,7 +448,7 @@ function resolveTransport(driver, event, options) {
448
448
  return transport;
449
449
  }
450
450
  function assertTokenSource(transport, options) {
451
- if (!transport.read) throw invalidConfigError(`${options.prefix} Session has no token source: "cookie" and "sessionHeader" are both disabled.`);
451
+ if (!transport.read) throw invalidConfigError(`${options.prefix} Session has no token source, enable "cookie" or "sessionHeader".`);
452
452
  }
453
453
  function assertWritable(transport, options) {
454
454
  const { operation, prefix } = options;
@@ -458,7 +458,7 @@ function assertWritable(transport, options) {
458
458
  function assertSessionHeader(header, options) {
459
459
  if (header === void 0 || typeof header === "boolean") return;
460
460
  if (isToken(header)) return;
461
- throw invalidConfigError(`${options.prefix} Session "sessionHeader" must be true, false or a header name: letters, digits and !#$%&'*+-.^_\`|~ only. Got ${quoteTokenValue(header)}.`);
461
+ throw invalidConfigError(`${options.prefix} Session "sessionHeader" must be true, false or a header name (got ${quoteTokenValue(header)}).`);
462
462
  }
463
463
  function sessionHeaderName(sessionName, configured) {
464
464
  if (typeof configured === "string") return configured.toLowerCase();
@@ -561,7 +561,7 @@ function claimSessionName(record, options) {
561
561
  return;
562
562
  }
563
563
  if (held === family) return;
564
- throw invalidConfigError(`${prefix} Session name "${name}" is already used by a ${held.toUpperCase()} session on this request; a name is one cookie, so give this session a "name" of its own.`);
564
+ throw invalidConfigError(`${prefix} Session name "${name}" is already used by a ${held.toUpperCase()} session on this request.`);
565
565
  }
566
566
  const kSessionPending = Symbol("unjwt_session_pending");
567
567
  function sessionInstant(source) {
@@ -914,7 +914,7 @@ function getSignKey(config, prefix) {
914
914
  assertJWSKeyPair(key, prefix);
915
915
  resolved = key.privateKey;
916
916
  }
917
- if (!resolved) throw invalidKeyError(`${prefix} Invalid JWS key. It must be a symmetric JWK, a private JWK, or a CryptoKey.`, key);
917
+ if (!resolved) throw invalidKeyError(`${prefix} Invalid JWS key, expected a symmetric JWK, a private JWK or a CryptoKey.`, key);
918
918
  assertPinnedAlg(resolved, config, prefix);
919
919
  return resolved;
920
920
  }
@@ -927,7 +927,7 @@ function getVerifyKey(config, prefix) {
927
927
  assertJWSKeyPair(key, prefix);
928
928
  resolved = Array.isArray(key.publicKey) ? { keys: key.publicKey } : key.publicKey;
929
929
  }
930
- if (!resolved) throw invalidKeyError(`${prefix} Invalid JWS key. It must be a symmetric JWK, a public JWK/set, or a CryptoKey.`, key);
930
+ if (!resolved) throw invalidKeyError(`${prefix} Invalid JWS key, expected a symmetric JWK, a public JWK/set or a CryptoKey.`, key);
931
931
  assertPinnedAlg(resolved, config, prefix);
932
932
  return resolved;
933
933
  }
@@ -936,7 +936,7 @@ function assertJWSKeyPair(key, prefix) {
936
936
  prefix,
937
937
  family: "JWS",
938
938
  isPublic: (half) => isCryptoKey(half) || isPublicJWK(half) || isPublicKeyList(Array.isArray(half) ? half : isJWKSet(half) ? half.keys : void 0),
939
- publicHalf: "a public JWK, a non-empty list or set of public JWKs, or a CryptoKey"
939
+ publicHalf: "a public JWK, a non-empty JWK set or a CryptoKey"
940
940
  });
941
941
  }
942
942
  function isPublicKeyList(keys) {