@cauthyhq/node 1.2.0 → 1.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.
package/dist/index.mjs CHANGED
@@ -54,9 +54,12 @@ async function unseal(sealed, key) {
54
54
  }
55
55
  }
56
56
  async function unsealAny(sealed, ring) {
57
- for (const key of ring) {
58
- const value = await unseal(sealed, key);
59
- if (value !== null) return value;
57
+ return (await unsealIndexed(sealed, ring))?.value ?? null;
58
+ }
59
+ async function unsealIndexed(sealed, ring) {
60
+ for (let index = 0; index < ring.length; index++) {
61
+ const value = await unseal(sealed, ring[index]);
62
+ if (value !== null) return { value, index };
60
63
  }
61
64
  return null;
62
65
  }
@@ -2304,12 +2307,13 @@ function byKey(given) {
2304
2307
  }
2305
2308
  const legacySecret = env3("CAUTHY_SECRET") || void 0;
2306
2309
  const legacyRoot = env3("PACT_ROOT_KEY") || void 0;
2310
+ const legacyRootPrevious = legacyRoot ? env3("PACT_ROOT_KEY_PREVIOUS") || void 0 : void 0;
2307
2311
  if (legacySecret) deprecated("CAUTHY_SECRET beside CAUTHY_KEY", "It is read only for sessions made before the move: remove it after the rotation window.");
2308
2312
  if (legacyRoot) deprecated("PACT_ROOT_KEY beside CAUTHY_KEY", "It is read only for sessions made before the move: remove it, the keys option and its table after the rotation window.");
2309
2313
  if (given.keys && !(legacyRoot && given.contract)) {
2310
2314
  throw new CauthyConfigError("with CAUTHY_KEY the application keeps no key store: remove keys (it is read only beside PACT_ROOT_KEY and a contract, while moving)");
2311
2315
  }
2312
- return { key, previous, legacySecret, legacyRoot };
2316
+ return { key, previous, legacySecret, legacyRoot, legacyRootPrevious };
2313
2317
  }
2314
2318
  var UnknownOriginError = class extends Error {
2315
2319
  constructor(origin, registered) {
@@ -2349,6 +2353,12 @@ function byContract(given) {
2349
2353
  return { contract, root, previous: given.rootKeyPrevious ?? env3("PACT_ROOT_KEY_PREVIOUS") };
2350
2354
  }
2351
2355
  var toldOfHeader = false;
2356
+ var toldOfUnopened = false;
2357
+ function toldUnopened() {
2358
+ if (toldOfUnopened) return;
2359
+ toldOfUnopened = true;
2360
+ console.warn("@cauthyhq/node: a session cookie arrived that no key of this application opens; it was cleared and the person is signed out. Moving to CAUTHY_KEY, keep the secret that sealed the old sessions (CAUTHY_SECRET, or PACT_ROOT_KEY and PACT_ROOT_KEY_PREVIOUS) beside it for the rotation window; rotating the key, set CAUTHY_KEY_PREVIOUS.");
2361
+ }
2352
2362
  function createCauthy(given = {}) {
2353
2363
  const keyed = byKey(given);
2354
2364
  const pacted = given.contract && !keyed ? byContract(given) : void 0;
@@ -2370,11 +2380,11 @@ function createCauthy(given = {}) {
2370
2380
  }, () => void 0);
2371
2381
  const derived = pacted ? deriveKeys(pacted.root, pacted.previous) : void 0;
2372
2382
  const single = derived || fromKey ? void 0 : keyOf(secret).then((k) => [k]);
2373
- const legacyRings = keyed?.legacyRoot ? deriveKeys(keyed.legacyRoot) : void 0;
2383
+ const legacyRings = keyed?.legacyRoot ? deriveKeys(keyed.legacyRoot, keyed.legacyRootPrevious) : void 0;
2374
2384
  const legacySingle = keyed?.legacySecret ? keyOf(keyed.legacySecret) : void 0;
2375
2385
  const withLegacy = async (own, purpose) => [
2376
2386
  ...await own,
2377
- ...legacyRings ? [(await legacyRings[purpose])[0]] : [],
2387
+ ...legacyRings ? await legacyRings[purpose] : [],
2378
2388
  ...legacySingle ? [await legacySingle] : []
2379
2389
  ];
2380
2390
  const cookieKeys = fromKey ? withLegacy(fromKey.cookie, "cookie") : derived?.cookie ?? single;
@@ -2540,10 +2550,11 @@ function createCauthy(given = {}) {
2540
2550
  async function read(request) {
2541
2551
  const had = readCookies(request.headers.get("cookie"));
2542
2552
  const raw = readParts(had, cookieName);
2543
- if (raw === null) return { had, value: null, present: false };
2544
- const value = await unsealAny(raw, await cookieKeys);
2553
+ if (raw === null) return { had, value: null, present: false, stale: false };
2554
+ const opened = await unsealIndexed(raw, await cookieKeys);
2555
+ const value = opened?.value ?? null;
2545
2556
  const sound = value !== null && typeof value.at === "string" && typeof value.rt === "string" && typeof value.exp === "number";
2546
- return { had, value: sound ? value : null, present: true };
2557
+ return { had, value: sound ? value : null, present: true, stale: sound && opened.index > 0 };
2547
2558
  }
2548
2559
  async function write(request, s, had) {
2549
2560
  return writeParts(cookieName, await seal(s, (await cookieKeys)[0]), attrs(request, s.p === 1 ? PERSISTENT_SECONDS : void 0), had);
@@ -2580,12 +2591,13 @@ function createCauthy(given = {}) {
2580
2591
  return running;
2581
2592
  }
2582
2593
  async function resolve2(request) {
2583
- const { had, value, present } = await read(request);
2594
+ const { had, value, present, stale } = await read(request);
2584
2595
  if (value === null) {
2596
+ if (present) toldUnopened();
2585
2597
  return { session: null, status: "unauthenticated", cookies: present ? clearParts(cookieName, attrs(request, 0), had) : [] };
2586
2598
  }
2587
2599
  if (unverified(value.u)) return { session: null, status: "unauthenticated", cookies: clearParts(cookieName, attrs(request, 0), had) };
2588
- if (fresh(value)) return { session: toSession(value), status: "authenticated", cookies: [] };
2600
+ if (fresh(value)) return { session: toSession(value), status: "authenticated", cookies: stale ? await write(request, value, had) : [] };
2589
2601
  const renewed = await renew(value);
2590
2602
  if (renewed === "ended") {
2591
2603
  return { session: null, status: "unauthenticated", cookies: clearParts(cookieName, attrs(request, 0), had) };