iron-session 7.0.6 → 8.0.0-beta.0

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.js CHANGED
@@ -4,9 +4,8 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
9
  };
11
10
  var __copyProps = (to, from, except, desc) => {
12
11
  if (from && typeof from === "object" || typeof from === "function") {
@@ -16,173 +15,760 @@ var __copyProps = (to, from, except, desc) => {
16
15
  }
17
16
  return to;
18
17
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
20
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
21
26
 
22
- // src/index.ts
23
- var src_exports = {};
24
- __export(src_exports, {
25
- getIronSession: () => getIronSession,
26
- sealData: () => sealData,
27
- unsealData: () => unsealData
27
+ // node_modules/.pnpm/cookie@0.6.0/node_modules/cookie/index.js
28
+ var require_cookie = __commonJS({
29
+ "node_modules/.pnpm/cookie@0.6.0/node_modules/cookie/index.js"(exports) {
30
+ exports.parse = parse2;
31
+ exports.serialize = serialize2;
32
+ var __toString = Object.prototype.toString;
33
+ var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
34
+ function parse2(str, options) {
35
+ if (typeof str !== "string") {
36
+ throw new TypeError("argument str must be a string");
37
+ }
38
+ var obj = {};
39
+ var opt = options || {};
40
+ var dec = opt.decode || decode;
41
+ var index = 0;
42
+ while (index < str.length) {
43
+ var eqIdx = str.indexOf("=", index);
44
+ if (eqIdx === -1) {
45
+ break;
46
+ }
47
+ var endIdx = str.indexOf(";", index);
48
+ if (endIdx === -1) {
49
+ endIdx = str.length;
50
+ } else if (endIdx < eqIdx) {
51
+ index = str.lastIndexOf(";", eqIdx - 1) + 1;
52
+ continue;
53
+ }
54
+ var key = str.slice(index, eqIdx).trim();
55
+ if (void 0 === obj[key]) {
56
+ var val = str.slice(eqIdx + 1, endIdx).trim();
57
+ if (val.charCodeAt(0) === 34) {
58
+ val = val.slice(1, -1);
59
+ }
60
+ obj[key] = tryDecode(val, dec);
61
+ }
62
+ index = endIdx + 1;
63
+ }
64
+ return obj;
65
+ }
66
+ function serialize2(name, val, options) {
67
+ var opt = options || {};
68
+ var enc = opt.encode || encode;
69
+ if (typeof enc !== "function") {
70
+ throw new TypeError("option encode is invalid");
71
+ }
72
+ if (!fieldContentRegExp.test(name)) {
73
+ throw new TypeError("argument name is invalid");
74
+ }
75
+ var value = enc(val);
76
+ if (value && !fieldContentRegExp.test(value)) {
77
+ throw new TypeError("argument val is invalid");
78
+ }
79
+ var str = name + "=" + value;
80
+ if (null != opt.maxAge) {
81
+ var maxAge = opt.maxAge - 0;
82
+ if (isNaN(maxAge) || !isFinite(maxAge)) {
83
+ throw new TypeError("option maxAge is invalid");
84
+ }
85
+ str += "; Max-Age=" + Math.floor(maxAge);
86
+ }
87
+ if (opt.domain) {
88
+ if (!fieldContentRegExp.test(opt.domain)) {
89
+ throw new TypeError("option domain is invalid");
90
+ }
91
+ str += "; Domain=" + opt.domain;
92
+ }
93
+ if (opt.path) {
94
+ if (!fieldContentRegExp.test(opt.path)) {
95
+ throw new TypeError("option path is invalid");
96
+ }
97
+ str += "; Path=" + opt.path;
98
+ }
99
+ if (opt.expires) {
100
+ var expires = opt.expires;
101
+ if (!isDate(expires) || isNaN(expires.valueOf())) {
102
+ throw new TypeError("option expires is invalid");
103
+ }
104
+ str += "; Expires=" + expires.toUTCString();
105
+ }
106
+ if (opt.httpOnly) {
107
+ str += "; HttpOnly";
108
+ }
109
+ if (opt.secure) {
110
+ str += "; Secure";
111
+ }
112
+ if (opt.partitioned) {
113
+ str += "; Partitioned";
114
+ }
115
+ if (opt.priority) {
116
+ var priority = typeof opt.priority === "string" ? opt.priority.toLowerCase() : opt.priority;
117
+ switch (priority) {
118
+ case "low":
119
+ str += "; Priority=Low";
120
+ break;
121
+ case "medium":
122
+ str += "; Priority=Medium";
123
+ break;
124
+ case "high":
125
+ str += "; Priority=High";
126
+ break;
127
+ default:
128
+ throw new TypeError("option priority is invalid");
129
+ }
130
+ }
131
+ if (opt.sameSite) {
132
+ var sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite;
133
+ switch (sameSite) {
134
+ case true:
135
+ str += "; SameSite=Strict";
136
+ break;
137
+ case "lax":
138
+ str += "; SameSite=Lax";
139
+ break;
140
+ case "strict":
141
+ str += "; SameSite=Strict";
142
+ break;
143
+ case "none":
144
+ str += "; SameSite=None";
145
+ break;
146
+ default:
147
+ throw new TypeError("option sameSite is invalid");
148
+ }
149
+ }
150
+ return str;
151
+ }
152
+ function decode(str) {
153
+ return str.indexOf("%") !== -1 ? decodeURIComponent(str) : str;
154
+ }
155
+ function encode(val) {
156
+ return encodeURIComponent(val);
157
+ }
158
+ function isDate(val) {
159
+ return __toString.call(val) === "[object Date]" || val instanceof Date;
160
+ }
161
+ function tryDecode(str, decode2) {
162
+ try {
163
+ return decode2(str);
164
+ } catch (e) {
165
+ return str;
166
+ }
167
+ }
168
+ }
169
+ });
170
+
171
+ // src/core.ts
172
+ var import_cookie = __toESM(require_cookie(), 1);
173
+
174
+ // node_modules/.pnpm/iron-webcrypto@1.0.0/node_modules/iron-webcrypto/dist/index.js
175
+ var alphabetByEncoding = {};
176
+ var alphabetByValue = new Array(64);
177
+ for (let i = 0, start = "A".charCodeAt(0), limit = "Z".charCodeAt(0); i + start <= limit; i++) {
178
+ const char = String.fromCharCode(i + start);
179
+ alphabetByEncoding[char] = i;
180
+ alphabetByValue[i] = char;
181
+ }
182
+ for (let i = 0, start = "a".charCodeAt(0), limit = "z".charCodeAt(0); i + start <= limit; i++) {
183
+ const char = String.fromCharCode(i + start);
184
+ const index = i + 26;
185
+ alphabetByEncoding[char] = index;
186
+ alphabetByValue[index] = char;
187
+ }
188
+ for (let i = 0; i < 10; i++) {
189
+ alphabetByEncoding[i.toString(10)] = i + 52;
190
+ const char = i.toString(10);
191
+ const index = i + 52;
192
+ alphabetByEncoding[char] = index;
193
+ alphabetByValue[index] = char;
194
+ }
195
+ alphabetByEncoding["+"] = 62;
196
+ alphabetByValue[62] = "+";
197
+ alphabetByEncoding["/"] = 63;
198
+ alphabetByValue[63] = "/";
199
+ var bitsPerLetter = 6;
200
+ var bitsPerByte = 8;
201
+ var maxLetterValue = 63;
202
+ var fromBase64 = (input) => {
203
+ let totalByteLength = input.length / 4 * 3;
204
+ if (input.slice(-2) === "==") {
205
+ totalByteLength -= 2;
206
+ } else if (input.slice(-1) === "=") {
207
+ totalByteLength--;
208
+ }
209
+ const out = new ArrayBuffer(totalByteLength);
210
+ const dataView = new DataView(out);
211
+ for (let i = 0; i < input.length; i += 4) {
212
+ let bits = 0;
213
+ let bitLength = 0;
214
+ for (let j = i, limit = i + 3; j <= limit; j++) {
215
+ if (input[j] !== "=") {
216
+ if (!(input[j] in alphabetByEncoding)) {
217
+ throw new TypeError(`Invalid character ${input[j]} in base64 string.`);
218
+ }
219
+ bits |= alphabetByEncoding[input[j]] << (limit - j) * bitsPerLetter;
220
+ bitLength += bitsPerLetter;
221
+ } else {
222
+ bits >>= bitsPerLetter;
223
+ }
224
+ }
225
+ const chunkOffset = i / 4 * 3;
226
+ bits >>= bitLength % bitsPerByte;
227
+ const byteLength = Math.floor(bitLength / bitsPerByte);
228
+ for (let k = 0; k < byteLength; k++) {
229
+ const offset = (byteLength - k - 1) * bitsPerByte;
230
+ dataView.setUint8(chunkOffset + k, (bits & 255 << offset) >> offset);
231
+ }
232
+ }
233
+ return new Uint8Array(out);
234
+ };
235
+ function toBase64(input) {
236
+ let str = "";
237
+ for (let i = 0; i < input.length; i += 3) {
238
+ let bits = 0;
239
+ let bitLength = 0;
240
+ for (let j = i, limit = Math.min(i + 3, input.length); j < limit; j++) {
241
+ bits |= input[j] << (limit - j - 1) * bitsPerByte;
242
+ bitLength += bitsPerByte;
243
+ }
244
+ const bitClusterCount = Math.ceil(bitLength / bitsPerLetter);
245
+ bits <<= bitClusterCount * bitsPerLetter - bitLength;
246
+ for (let k = 1; k <= bitClusterCount; k++) {
247
+ const offset = (bitClusterCount - k) * bitsPerLetter;
248
+ str += alphabetByValue[(bits & maxLetterValue << offset) >> offset];
249
+ }
250
+ str += "==".slice(0, 4 - bitClusterCount);
251
+ }
252
+ return str;
253
+ }
254
+ var stringToBuffer = (value) => {
255
+ return new TextEncoder().encode(value);
256
+ };
257
+ var bufferToString = (value) => {
258
+ return new TextDecoder().decode(value);
259
+ };
260
+ var base64urlEncode = (value) => toBase64(typeof value === "string" ? stringToBuffer(value) : value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
261
+ var base64urlDecode = (value) => fromBase64(
262
+ value.replace(/-/g, "+").replace(/_/g, "/") + Array((4 - value.length % 4) % 4 + 1).join("=")
263
+ );
264
+ var defaults = {
265
+ encryption: { saltBits: 256, algorithm: "aes-256-cbc", iterations: 1, minPasswordlength: 32 },
266
+ integrity: { saltBits: 256, algorithm: "sha256", iterations: 1, minPasswordlength: 32 },
267
+ ttl: 0,
268
+ timestampSkewSec: 60,
269
+ localtimeOffsetMsec: 0
270
+ };
271
+ var clone = (options) => ({
272
+ ...options,
273
+ encryption: { ...options.encryption },
274
+ integrity: { ...options.integrity }
28
275
  });
29
- module.exports = __toCommonJS(src_exports);
30
- var Iron = __toESM(require("iron-webcrypto-vvo"));
31
- var import_cookie = __toESM(require("cookie"));
276
+ var algorithms = {
277
+ "aes-128-ctr": { keyBits: 128, ivBits: 128, name: "AES-CTR" },
278
+ "aes-256-cbc": { keyBits: 256, ivBits: 128, name: "AES-CBC" },
279
+ sha256: { keyBits: 256, name: "SHA-256" }
280
+ };
281
+ var macFormatVersion = "2";
282
+ var macPrefix = `Fe26.${macFormatVersion}`;
283
+ var randomBytes = (_crypto, size) => {
284
+ const bytes = new Uint8Array(size);
285
+ _crypto.getRandomValues(bytes);
286
+ return bytes;
287
+ };
288
+ var randomBits = (_crypto, bits) => {
289
+ if (bits < 1)
290
+ throw Error("Invalid random bits count");
291
+ const bytes = Math.ceil(bits / 8);
292
+ return randomBytes(_crypto, bytes);
293
+ };
294
+ var pbkdf2 = async (_crypto, password, salt, iterations, keyLength, hash) => {
295
+ const passwordBuffer = stringToBuffer(password);
296
+ const importedKey = await _crypto.subtle.importKey("raw", passwordBuffer, "PBKDF2", false, [
297
+ "deriveBits"
298
+ ]);
299
+ const saltBuffer = stringToBuffer(salt);
300
+ const params = { name: "PBKDF2", hash, salt: saltBuffer, iterations };
301
+ const derivation = await _crypto.subtle.deriveBits(params, importedKey, keyLength * 8);
302
+ return derivation;
303
+ };
304
+ var generateKey = async (_crypto, password, options) => {
305
+ var _a;
306
+ if (!(password == null ? void 0 : password.length))
307
+ throw new Error("Empty password");
308
+ if (options == null || typeof options !== "object")
309
+ throw new Error("Bad options");
310
+ if (!(options.algorithm in algorithms))
311
+ throw new Error(`Unknown algorithm: ${options.algorithm}`);
312
+ const algorithm = algorithms[options.algorithm];
313
+ const result = {};
314
+ const hmac = (_a = options.hmac) != null ? _a : false;
315
+ const id = hmac ? { name: "HMAC", hash: algorithm.name } : { name: algorithm.name };
316
+ const usage = hmac ? ["sign", "verify"] : ["encrypt", "decrypt"];
317
+ if (typeof password === "string") {
318
+ if (password.length < options.minPasswordlength)
319
+ throw new Error(
320
+ `Password string too short (min ${options.minPasswordlength} characters required)`
321
+ );
322
+ let { salt = "" } = options;
323
+ if (!salt) {
324
+ const { saltBits = 0 } = options;
325
+ if (!saltBits)
326
+ throw new Error("Missing salt and saltBits options");
327
+ const randomSalt = randomBits(_crypto, saltBits);
328
+ salt = [...new Uint8Array(randomSalt)].map((x) => x.toString(16).padStart(2, "0")).join("");
329
+ }
330
+ const derivedKey = await pbkdf2(
331
+ _crypto,
332
+ password,
333
+ salt,
334
+ options.iterations,
335
+ algorithm.keyBits / 8,
336
+ "SHA-1"
337
+ );
338
+ const importedEncryptionKey = await _crypto.subtle.importKey(
339
+ "raw",
340
+ derivedKey,
341
+ id,
342
+ false,
343
+ usage
344
+ );
345
+ result.key = importedEncryptionKey;
346
+ result.salt = salt;
347
+ } else {
348
+ if (password.length < algorithm.keyBits / 8)
349
+ throw new Error("Key buffer (password) too small");
350
+ result.key = await _crypto.subtle.importKey("raw", password, id, false, usage);
351
+ result.salt = "";
352
+ }
353
+ if (options.iv)
354
+ result.iv = options.iv;
355
+ else if ("ivBits" in algorithm)
356
+ result.iv = randomBits(_crypto, algorithm.ivBits);
357
+ return result;
358
+ };
359
+ var encrypt = async (_crypto, password, options, data) => {
360
+ const key = await generateKey(_crypto, password, options);
361
+ const textBuffer = stringToBuffer(data);
362
+ const encrypted = await _crypto.subtle.encrypt(
363
+ { name: algorithms[options.algorithm].name, iv: key.iv },
364
+ key.key,
365
+ textBuffer
366
+ );
367
+ return { encrypted: new Uint8Array(encrypted), key };
368
+ };
369
+ var decrypt = async (_crypto, password, options, data) => {
370
+ const key = await generateKey(_crypto, password, options);
371
+ const decrypted = await _crypto.subtle.decrypt(
372
+ { name: algorithms[options.algorithm].name, iv: key.iv },
373
+ key.key,
374
+ typeof data === "string" ? stringToBuffer(data) : data
375
+ );
376
+ return bufferToString(new Uint8Array(decrypted));
377
+ };
378
+ var hmacWithPassword = async (_crypto, password, options, data) => {
379
+ const key = await generateKey(_crypto, password, { ...options, hmac: true });
380
+ const textBuffer = stringToBuffer(data);
381
+ const signed = await _crypto.subtle.sign({ name: "HMAC" }, key.key, textBuffer);
382
+ const digest = base64urlEncode(new Uint8Array(signed));
383
+ return { digest, salt: key.salt };
384
+ };
385
+ var normalizePassword = (password) => {
386
+ if (typeof password === "string" || password instanceof Uint8Array)
387
+ return { encryption: password, integrity: password };
388
+ if ("secret" in password)
389
+ return { id: password.id, encryption: password.secret, integrity: password.secret };
390
+ return { id: password.id, encryption: password.encryption, integrity: password.integrity };
391
+ };
392
+ var seal = async (_crypto, object, password, options) => {
393
+ if (!password)
394
+ throw Error("Empty password");
395
+ const opts = clone(options);
396
+ const now = Date.now() + (opts.localtimeOffsetMsec || 0);
397
+ const objectString = JSON.stringify(object);
398
+ const pass = normalizePassword(password);
399
+ const { id = "" } = pass;
400
+ if (id && !/^\w+$/.test(id))
401
+ throw new Error("Invalid password id");
402
+ const { encrypted, key } = await encrypt(_crypto, pass.encryption, opts.encryption, objectString);
403
+ const encryptedB64 = base64urlEncode(new Uint8Array(encrypted));
404
+ const iv = base64urlEncode(key.iv);
405
+ const expiration = opts.ttl ? now + opts.ttl : "";
406
+ const macBaseString = `${macPrefix}*${id}*${key.salt}*${iv}*${encryptedB64}*${expiration}`;
407
+ const mac = await hmacWithPassword(_crypto, pass.integrity, opts.integrity, macBaseString);
408
+ const sealed = `${macBaseString}*${mac.salt}*${mac.digest}`;
409
+ return sealed;
410
+ };
411
+ var fixedTimeComparison = (a, b) => {
412
+ let mismatch = a.length === b.length ? 0 : 1;
413
+ if (mismatch)
414
+ b = a;
415
+ for (let i = 0; i < a.length; i += 1)
416
+ mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
417
+ return mismatch === 0;
418
+ };
419
+ var unseal = async (_crypto, sealed, password, options) => {
420
+ if (!password)
421
+ throw Error("Empty password");
422
+ const opts = clone(options);
423
+ const now = Date.now() + (opts.localtimeOffsetMsec || 0);
424
+ const parts = sealed.split("*");
425
+ if (parts.length !== 8)
426
+ throw new Error("Incorrect number of sealed components");
427
+ const prefix = parts[0];
428
+ let passwordId = parts[1];
429
+ const encryptionSalt = parts[2];
430
+ const encryptionIv = parts[3];
431
+ const encryptedB64 = parts[4];
432
+ const expiration = parts[5];
433
+ const hmacSalt = parts[6];
434
+ const hmac = parts[7];
435
+ const macBaseString = `${prefix}*${passwordId}*${encryptionSalt}*${encryptionIv}*${encryptedB64}*${expiration}`;
436
+ if (macPrefix !== prefix)
437
+ throw new Error("Wrong mac prefix");
438
+ if (expiration) {
439
+ if (!/^\d+$/.exec(expiration))
440
+ throw new Error("Invalid expiration");
441
+ const exp = parseInt(expiration, 10);
442
+ if (exp <= now - opts.timestampSkewSec * 1e3)
443
+ throw new Error("Expired seal");
444
+ }
445
+ if (typeof password === "undefined" || typeof password === "string" && password.length === 0)
446
+ throw new Error("Empty password");
447
+ let pass = "";
448
+ passwordId = passwordId || "default";
449
+ if (typeof password === "string" || password instanceof Uint8Array)
450
+ pass = password;
451
+ else if (!(passwordId in password))
452
+ throw new Error(`Cannot find password: ${passwordId}`);
453
+ else
454
+ pass = password[passwordId];
455
+ pass = normalizePassword(pass);
456
+ const macOptions = opts.integrity;
457
+ macOptions.salt = hmacSalt;
458
+ const mac = await hmacWithPassword(_crypto, pass.integrity, macOptions, macBaseString);
459
+ if (!fixedTimeComparison(mac.digest, hmac))
460
+ throw new Error("Bad hmac value");
461
+ const encrypted = base64urlDecode(encryptedB64);
462
+ const decryptOptions = opts.encryption;
463
+ decryptOptions.salt = encryptionSalt;
464
+ decryptOptions.iv = base64urlDecode(encryptionIv);
465
+ const decrypted = await decrypt(_crypto, pass.encryption, decryptOptions, encrypted);
466
+ if (decrypted)
467
+ return JSON.parse(decrypted);
468
+ return null;
469
+ };
470
+
471
+ // src/core.ts
32
472
  var timestampSkewSec = 60;
33
- var fourteenDaysInSeconds = 15 * 24 * 3600;
473
+ var fourteenDaysInSeconds = 14 * 24 * 3600;
34
474
  var currentMajorVersion = 2;
35
475
  var versionDelimiter = "~";
36
476
  var defaultOptions = {
37
477
  ttl: fourteenDaysInSeconds,
38
- cookieOptions: {
39
- httpOnly: true,
40
- secure: true,
41
- sameSite: "lax",
42
- path: "/"
43
- }
478
+ cookieOptions: { httpOnly: true, secure: true, sameSite: "lax", path: "/" }
44
479
  };
45
- async function getIronSession(req, res, userSessionOptions) {
46
- if (!req || !res || !userSessionOptions || !userSessionOptions.cookieName || !userSessionOptions.password) {
47
- throw new Error(`iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: "...", password: "...". Check the usage here: https://github.com/vvo/iron-session`);
480
+ function normalizeStringPasswordToMap(password) {
481
+ return typeof password === "string" ? { 1: password } : password;
482
+ }
483
+ function parseSeal(seal2) {
484
+ const [sealWithoutVersion, tokenVersionAsString] = seal2.split(versionDelimiter);
485
+ const tokenVersion = tokenVersionAsString == null ? null : parseInt(tokenVersionAsString, 10);
486
+ return { sealWithoutVersion, tokenVersion };
487
+ }
488
+ function computeCookieMaxAge(ttl) {
489
+ if (ttl === 0) {
490
+ return 2147483647;
491
+ }
492
+ return ttl - timestampSkewSec;
493
+ }
494
+ function getCookie(req, cookieName) {
495
+ return (0, import_cookie.parse)(
496
+ ("headers" in req && typeof req.headers.get === "function" ? req.headers.get("cookie") : req.headers.cookie) ?? ""
497
+ )[cookieName] ?? "";
498
+ }
499
+ function getServerActionCookie(cookieName, cookieHandler) {
500
+ const cookieObject = cookieHandler.get(cookieName);
501
+ const cookie = cookieObject?.value;
502
+ if (typeof cookie === "string") {
503
+ return cookie;
48
504
  }
49
- const passwordsAsMap = normalizeStringPasswordToMap(userSessionOptions.password);
50
- Object.values(normalizeStringPasswordToMap(userSessionOptions.password)).forEach((password) => {
51
- if (password.length < 32) {
52
- throw new Error(`iron-session: Bad usage. Password must be at least 32 characters long.`);
505
+ return "";
506
+ }
507
+ function setCookie(res, cookieValue) {
508
+ if ("headers" in res && typeof res.headers.append === "function") {
509
+ res.headers.append("set-cookie", cookieValue);
510
+ return;
511
+ }
512
+ let existingSetCookie = res.getHeader("set-cookie") ?? [];
513
+ if (!Array.isArray(existingSetCookie)) {
514
+ existingSetCookie = [existingSetCookie.toString()];
515
+ }
516
+ res.setHeader("set-cookie", [
517
+ ...existingSetCookie,
518
+ cookieValue
519
+ ]);
520
+ }
521
+ function createSealData(_crypto = globalThis.crypto) {
522
+ return async function sealData2(data, {
523
+ password,
524
+ ttl = fourteenDaysInSeconds
525
+ }) {
526
+ const passwordsMap = normalizeStringPasswordToMap(password);
527
+ const mostRecentPasswordId = Math.max(
528
+ ...Object.keys(passwordsMap).map(Number)
529
+ );
530
+ const passwordForSeal = {
531
+ id: mostRecentPasswordId.toString(),
532
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
533
+ secret: passwordsMap[mostRecentPasswordId]
534
+ };
535
+ const seal2 = await seal(_crypto, data, passwordForSeal, {
536
+ ...defaults,
537
+ ttl: ttl * 1e3
538
+ });
539
+ return `${seal2}${versionDelimiter}${currentMajorVersion}`;
540
+ };
541
+ }
542
+ function createUnsealData(_crypto = globalThis.crypto) {
543
+ return async function unsealData2(seal2, {
544
+ password,
545
+ ttl = fourteenDaysInSeconds
546
+ }) {
547
+ const passwordsMap = normalizeStringPasswordToMap(password);
548
+ const { sealWithoutVersion, tokenVersion } = parseSeal(seal2);
549
+ try {
550
+ const data = await unseal(_crypto, sealWithoutVersion, passwordsMap, {
551
+ ...defaults,
552
+ ttl: ttl * 1e3
553
+ }) ?? {};
554
+ if (tokenVersion === 2) {
555
+ return data;
556
+ }
557
+ return { ...data.persistent };
558
+ } catch (error) {
559
+ if (error instanceof Error && /^(Expired seal|Bad hmac value|Cannot find password|Incorrect number of sealed components)/.test(
560
+ error.message
561
+ )) {
562
+ return {};
563
+ }
564
+ throw error;
53
565
  }
54
- });
566
+ };
567
+ }
568
+ function mergeOptions(userSessionOptions, overrides) {
55
569
  const options = {
56
570
  ...defaultOptions,
57
571
  ...userSessionOptions,
572
+ ...overrides,
58
573
  cookieOptions: {
59
574
  ...defaultOptions.cookieOptions,
60
- ...userSessionOptions.cookieOptions || {}
575
+ ...userSessionOptions.cookieOptions,
576
+ ...overrides?.cookieOptions
61
577
  }
62
578
  };
63
- if (options.ttl === 0) {
64
- options.ttl = 2147483647;
65
- }
66
579
  if (userSessionOptions.cookieOptions && "maxAge" in userSessionOptions.cookieOptions) {
67
580
  if (userSessionOptions.cookieOptions.maxAge === void 0) {
68
581
  options.ttl = 0;
69
- } else {
70
- options.cookieOptions.maxAge = computeCookieMaxAge(userSessionOptions.cookieOptions.maxAge);
71
582
  }
72
583
  } else {
73
584
  options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);
74
585
  }
75
- const sealFromCookies = import_cookie.default.parse("credentials" in req ? req.headers.get("cookie") || "" : req.headers.cookie || "")[options.cookieName];
76
- const session = sealFromCookies === void 0 ? {} : await unsealData(sealFromCookies, {
77
- password: passwordsAsMap,
78
- ttl: options.ttl
79
- });
80
- Object.defineProperties(session, {
81
- save: {
82
- value: async function save() {
83
- if ("headersSent" in res && res.headersSent === true) {
84
- throw new Error(`iron-session: Cannot set session cookie: session.save() was called after headers were sent. Make sure to call it before any res.send() or res.end()`);
586
+ return options;
587
+ }
588
+ function createGetIronSession(sealData2, unsealData2) {
589
+ return async function getIronSession2(req, res, userSessionOptions) {
590
+ if (!req) {
591
+ throw new Error("iron-session: Bad usage. Missing request parameter.");
592
+ }
593
+ if (!res) {
594
+ throw new Error("iron-session: Bad usage. Missing response parameter.");
595
+ }
596
+ if (!userSessionOptions) {
597
+ throw new Error("iron-session: Bad usage. Missing options.");
598
+ }
599
+ if (!userSessionOptions.cookieName) {
600
+ throw new Error("iron-session: Bad usage. Missing cookie name.");
601
+ }
602
+ if (!userSessionOptions.password) {
603
+ throw new Error("iron-session: Bad usage. Missing password.");
604
+ }
605
+ const passwordsMap = normalizeStringPasswordToMap(
606
+ userSessionOptions.password
607
+ );
608
+ if (Object.values(passwordsMap).some((password) => password.length < 32)) {
609
+ throw new Error(
610
+ "iron-session: Bad usage. Password must be at least 32 characters long."
611
+ );
612
+ }
613
+ const options = mergeOptions(userSessionOptions);
614
+ const sealFromCookies = getCookie(req, options.cookieName);
615
+ const session = sealFromCookies ? await unsealData2(sealFromCookies, {
616
+ password: passwordsMap,
617
+ ttl: options.ttl
618
+ }) : {};
619
+ Object.defineProperties(session, {
620
+ save: {
621
+ value: async function save(saveOptions) {
622
+ if ("headersSent" in res && res.headersSent) {
623
+ throw new Error(
624
+ "iron-session: Cannot set session cookie: session.save() was called after headers were sent. Make sure to call it before any res.send() or res.end()"
625
+ );
626
+ }
627
+ const mergedOptions = mergeOptions(userSessionOptions, saveOptions);
628
+ const seal2 = await sealData2(session, {
629
+ password: passwordsMap,
630
+ ttl: mergedOptions.ttl
631
+ });
632
+ const cookieValue = (0, import_cookie.serialize)(
633
+ mergedOptions.cookieName,
634
+ seal2,
635
+ mergedOptions.cookieOptions
636
+ );
637
+ if (cookieValue.length > 4096) {
638
+ throw new Error(
639
+ `iron-session: Cookie length is too big (${cookieValue.length} bytes), browsers will refuse it. Try to remove some data.`
640
+ );
641
+ }
642
+ setCookie(res, cookieValue);
85
643
  }
86
- const seal2 = await sealData(session, {
87
- password: passwordsAsMap,
88
- ttl: options.ttl
89
- });
90
- const cookieValue = import_cookie.default.serialize(options.cookieName, seal2, options.cookieOptions);
91
- if (cookieValue.length > 4096) {
92
- throw new Error(`iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`);
644
+ },
645
+ destroy: {
646
+ value: async function destroy(destroyOptions) {
647
+ Object.keys(session).forEach((key) => {
648
+ delete session[key];
649
+ });
650
+ const mergedOptions = mergeOptions(
651
+ userSessionOptions,
652
+ destroyOptions
653
+ );
654
+ const cookieValue = (0, import_cookie.serialize)(mergedOptions.cookieName, "", {
655
+ ...mergedOptions.cookieOptions,
656
+ maxAge: 0
657
+ });
658
+ setCookie(res, cookieValue);
93
659
  }
94
- addToCookies(cookieValue, res);
95
660
  }
96
- },
97
- destroy: {
98
- value: function destroy() {
99
- Object.keys(session).forEach((key) => {
100
- delete session[key];
101
- });
102
- const cookieValue = import_cookie.default.serialize(options.cookieName, "", {
103
- ...options.cookieOptions,
104
- maxAge: 0
105
- });
106
- addToCookies(cookieValue, res);
107
- }
108
- }
109
- });
110
- return session;
111
- }
112
- function addToCookies(cookieValue, res) {
113
- var _a;
114
- if ("headers" in res) {
115
- res.headers.append("set-cookie", cookieValue);
116
- return;
117
- }
118
- let existingSetCookie = (_a = res.getHeader("set-cookie")) != null ? _a : [];
119
- if (typeof existingSetCookie === "string") {
120
- existingSetCookie = [existingSetCookie];
121
- }
122
- res.setHeader("set-cookie", [...existingSetCookie, cookieValue]);
123
- }
124
- function computeCookieMaxAge(ttl) {
125
- return ttl - timestampSkewSec;
126
- }
127
- async function unsealData(seal2, {
128
- password,
129
- ttl = fourteenDaysInSeconds
130
- }) {
131
- const passwordsAsMap = normalizeStringPasswordToMap(password);
132
- const { sealWithoutVersion, tokenVersion } = parseSeal(seal2);
133
- try {
134
- const data = await Iron.unseal(sealWithoutVersion, passwordsAsMap, {
135
- ...Iron.defaults,
136
- ttl: ttl * 1e3
137
661
  });
138
- if (tokenVersion === 2) {
139
- return data;
662
+ return session;
663
+ };
664
+ }
665
+ function createGetServerActionIronSession(sealData2, unsealData2) {
666
+ return async function getServerActionIronSession2(userSessionOptions, cookieHandler) {
667
+ if (!userSessionOptions) {
668
+ throw new Error("iron-session: Bad usage. Missing options.");
140
669
  }
141
- return {
142
- ...data.persistent
143
- };
144
- } catch (error) {
145
- if (error instanceof Error) {
146
- if (error.message === "Expired seal" || error.message === "Bad hmac value" || error.message === "Cannot find password: " || error.message === "Incorrect number of sealed components") {
147
- return {};
148
- }
670
+ if (!cookieHandler) {
671
+ throw new Error(
672
+ "iron-session: Bad usage. Missing NextJS cookies() handler."
673
+ );
149
674
  }
150
- throw error;
151
- }
152
- }
153
- function parseSeal(seal2) {
154
- if (seal2[seal2.length - 2] === versionDelimiter) {
155
- const [sealWithoutVersion, tokenVersionAsString] = seal2.split(versionDelimiter);
156
- return {
157
- sealWithoutVersion,
158
- tokenVersion: parseInt(tokenVersionAsString, 10)
159
- };
160
- }
161
- return { sealWithoutVersion: seal2, tokenVersion: null };
162
- }
163
- async function sealData(data, {
164
- password,
165
- ttl = fourteenDaysInSeconds
166
- }) {
167
- const passwordsAsMap = normalizeStringPasswordToMap(password);
168
- const mostRecentPasswordId = Math.max(...Object.keys(passwordsAsMap).map((id) => parseInt(id, 10)));
169
- const passwordForSeal = {
170
- id: mostRecentPasswordId.toString(),
171
- secret: passwordsAsMap[mostRecentPasswordId]
675
+ if (!userSessionOptions.cookieName) {
676
+ throw new Error("iron-session: Bad usage. Missing cookie name.");
677
+ }
678
+ if (!userSessionOptions.password) {
679
+ throw new Error("iron-session: Bad usage. Missing password.");
680
+ }
681
+ const passwordsMap = normalizeStringPasswordToMap(
682
+ userSessionOptions.password
683
+ );
684
+ if (Object.values(passwordsMap).some((password) => password.length < 32)) {
685
+ throw new Error(
686
+ "iron-session: Bad usage. Password must be at least 32 characters long."
687
+ );
688
+ }
689
+ const options = mergeOptions(userSessionOptions);
690
+ const sealFromCookies = getServerActionCookie(
691
+ options.cookieName,
692
+ cookieHandler
693
+ );
694
+ const session = sealFromCookies ? await unsealData2(sealFromCookies, {
695
+ password: passwordsMap,
696
+ ttl: options.ttl
697
+ }) : {};
698
+ Object.defineProperties(session, {
699
+ save: {
700
+ value: async function save(saveOptions) {
701
+ const mergedOptions = mergeOptions(userSessionOptions, saveOptions);
702
+ const seal2 = await sealData2(session, {
703
+ password: passwordsMap,
704
+ ttl: mergedOptions.ttl
705
+ });
706
+ const cookieLength = mergedOptions.cookieName.length + seal2.length + JSON.stringify(mergedOptions.cookieOptions).length;
707
+ if (cookieLength > 4096) {
708
+ throw new Error(
709
+ `iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`
710
+ );
711
+ }
712
+ cookieHandler.set(
713
+ mergedOptions.cookieName,
714
+ seal2,
715
+ mergedOptions.cookieOptions
716
+ );
717
+ }
718
+ },
719
+ destroy: {
720
+ value: async function destroy(destroyOptions) {
721
+ Object.keys(session).forEach((key) => {
722
+ delete session[key];
723
+ });
724
+ const mergedOptions = mergeOptions(
725
+ userSessionOptions,
726
+ destroyOptions
727
+ );
728
+ const cookieOptions = { ...mergedOptions.cookieOptions, maxAge: 0 };
729
+ cookieHandler.set(mergedOptions.cookieName, "", cookieOptions);
730
+ }
731
+ }
732
+ });
733
+ return session;
172
734
  };
173
- const seal2 = await Iron.seal(data, passwordForSeal, {
174
- ...Iron.defaults,
175
- ttl: ttl * 1e3
735
+ }
736
+ function mergeHeaders(...headersList) {
737
+ const mergedHeaders = new Headers();
738
+ headersList.forEach((headers) => {
739
+ new Headers(headers).forEach((value, key) => {
740
+ mergedHeaders.append(key, value);
741
+ });
176
742
  });
177
- return `${seal2}${versionDelimiter}${currentMajorVersion}`;
743
+ return mergedHeaders;
178
744
  }
179
- function normalizeStringPasswordToMap(password) {
180
- return typeof password === "string" ? { 1: password } : password;
745
+ function createResponse(originalResponse, bodyString, options) {
746
+ return new Response(bodyString, {
747
+ status: options?.status ?? originalResponse.status,
748
+ statusText: options?.statusText ?? originalResponse.statusText,
749
+ headers: mergeHeaders(options?.headers, originalResponse.headers)
750
+ });
181
751
  }
182
- // Annotate the CommonJS export names for ESM import in node:
183
- 0 && (module.exports = {
184
- getIronSession,
752
+
753
+ // src/index.ts
754
+ var sealData = createSealData();
755
+ var unsealData = createUnsealData();
756
+ var getIronSession = createGetIronSession(sealData, unsealData);
757
+ var getServerActionIronSession = createGetServerActionIronSession(
185
758
  sealData,
186
759
  unsealData
187
- });
760
+ );
761
+ /*! Bundled license information:
762
+
763
+ cookie/index.js:
764
+ (*!
765
+ * cookie
766
+ * Copyright(c) 2012-2014 Roman Shtylman
767
+ * Copyright(c) 2015 Douglas Christopher Wilson
768
+ * MIT Licensed
769
+ *)
770
+ */
771
+
772
+ export { createGetIronSession, createGetServerActionIronSession, createResponse, createSealData, createUnsealData, getIronSession, getServerActionIronSession, mergeHeaders, sealData, unsealData };
773
+ //# sourceMappingURL=out.js.map
188
774
  //# sourceMappingURL=index.js.map