iron-session 8.0.0-beta.6 → 8.0.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/README.md +67 -13
- package/dist/index.cjs +30 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -20
- package/dist/index.d.ts +8 -20
- package/dist/index.js +31 -36
- package/dist/index.js.map +1 -1
- package/package.json +6 -9
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**`iron-session` is a secure, stateless, and cookie-based session library for JavaScript.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<p align="center">Online demo: <a href="https://get-iron-session.vercel.app/">https://get-iron-session.vercel.app</a> 👀</p>
|
|
6
|
+
|
|
7
|
+
The session data is stored in signed and encrypted cookies which are decoded by your server code in a stateless fashion (= no network involved). This is the same technique used by frameworks like
|
|
6
8
|
[Ruby On Rails](https://guides.rubyonrails.org/security.html#session-storage).
|
|
7
9
|
|
|
8
10
|
<p align="center"><i>⭐️ Featured in the <a href="https://nextjs.org/docs/authentication">Next.js documentation</a></i></p>
|
|
@@ -12,12 +14,21 @@ The session data is stored in signed and encrypted cookies which are decoded by
|
|
|
12
14
|
- [Table of Contents](#table-of-contents)
|
|
13
15
|
- [Installation](#installation)
|
|
14
16
|
- [Usage](#usage)
|
|
17
|
+
- [Examples](#examples)
|
|
18
|
+
- [Project status](#project-status)
|
|
15
19
|
- [Session options](#session-options)
|
|
16
20
|
- [API](#api)
|
|
17
21
|
- [`getIronSession<T>(req, res, sessionOptions): Promise<IronSession<T>>`](#getironsessiontreq-res-sessionoptions-promiseironsessiont)
|
|
18
22
|
- [`getIronSession<T>(cookieStore, sessionOptions): Promise<IronSession<T>>`](#getironsessiontcookiestore-sessionoptions-promiseironsessiont)
|
|
19
|
-
- [session.save()](#sessionsave)
|
|
20
|
-
- [session.destroy()](#sessiondestroy)
|
|
23
|
+
- [`session.save(): Promise<void>`](#sessionsave-promisevoid)
|
|
24
|
+
- [`session.destroy(): void`](#sessiondestroy-void)
|
|
25
|
+
- [`sealData(data: unknown, { password, ttl }): Promise<string>`](#sealdatadata-unknown--password-ttl--promisestring)
|
|
26
|
+
- [`unSealData<T>(seal: string, { password, ttl }): Promise<T>`](#unsealdatatseal-string--password-ttl--promiset)
|
|
27
|
+
- [FAQ](#faq)
|
|
28
|
+
- [Why use pure cookies for sessions?](#why-use-pure-cookies-for-sessions)
|
|
29
|
+
- [How to invalidate sessions?](#how-to-invalidate-sessions)
|
|
30
|
+
- [Can I use something else than cookies?](#can-i-use-something-else-than-cookies)
|
|
31
|
+
- [How is this different from JWT?](#how-is-this-different-from-jwt)
|
|
21
32
|
- [Credits](#credits)
|
|
22
33
|
- [Good Reads](#good-reads)
|
|
23
34
|
|
|
@@ -32,7 +43,7 @@ pnpm add iron-session
|
|
|
32
43
|
To get a session, there's a single method to know: `getIronSession`.
|
|
33
44
|
|
|
34
45
|
```ts
|
|
35
|
-
// Next.js
|
|
46
|
+
// Next.js API Routes and Node.js/Express/Connect.
|
|
36
47
|
import { getIronSession } from 'iron-session';
|
|
37
48
|
|
|
38
49
|
export function get(req, res) {
|
|
@@ -47,7 +58,7 @@ export function post(req, res) {
|
|
|
47
58
|
```
|
|
48
59
|
|
|
49
60
|
```ts
|
|
50
|
-
// Next.js App Router
|
|
61
|
+
// Next.js Route Handlers (App Router)
|
|
51
62
|
import { cookies } from 'next/header';
|
|
52
63
|
import { getIronSession } from 'iron-session';
|
|
53
64
|
|
|
@@ -56,14 +67,14 @@ export function GET() {
|
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
export function POST() {
|
|
59
|
-
const session = getIronSession(
|
|
70
|
+
const session = getIronSession(cookies(), { password: "...", cookieName: "..." });
|
|
60
71
|
session.username = "Alison";
|
|
61
72
|
await session.save();
|
|
62
73
|
}
|
|
63
74
|
```
|
|
64
75
|
|
|
65
|
-
```
|
|
66
|
-
// Next.js
|
|
76
|
+
```tsx
|
|
77
|
+
// Next.js Server Components and Server Actions (App Router)
|
|
67
78
|
import { cookies } from 'next/header';
|
|
68
79
|
import { getIronSession } from 'iron-session';
|
|
69
80
|
|
|
@@ -78,10 +89,17 @@ function Profile() {
|
|
|
78
89
|
}
|
|
79
90
|
```
|
|
80
91
|
|
|
92
|
+
## Examples
|
|
93
|
+
|
|
94
|
+
We have many different patterns and examples on the online demo, have a look: https://get-iron-session.vercel.app/.
|
|
95
|
+
|
|
96
|
+
## Project status
|
|
97
|
+
|
|
98
|
+
✅ Production ready and maintained.
|
|
81
99
|
|
|
82
100
|
## Session options
|
|
83
101
|
|
|
84
|
-
Two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed
|
|
102
|
+
Two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed.****
|
|
85
103
|
|
|
86
104
|
- `password`, **required**: Private key used to encrypt the cookie. It has to be at least 32 characters long. Use <https://1password.com/password-generator/> to generate strong passwords. `password` can be either a `string` or an `array` of objects like this: `[{id: 2, password: "..."}, {id: 1, password: "..."}]` to allow for password rotation.
|
|
87
105
|
- `cookieName`, **required**: Name of the cookie to be stored
|
|
@@ -112,22 +130,58 @@ const session = getIronSession<SessionData>(req, res, sessionOptions);
|
|
|
112
130
|
const session = getIronSession<SessionData>(cookies(), sessionOptions);
|
|
113
131
|
```
|
|
114
132
|
|
|
115
|
-
### session.save()
|
|
133
|
+
### `session.save(): Promise<void>`
|
|
116
134
|
|
|
117
|
-
Saves the session.
|
|
135
|
+
Saves the session. This is an asynchronous operation. It must be done and awaited before headers are sent to the client.
|
|
118
136
|
|
|
119
137
|
```ts
|
|
120
138
|
await session.save()
|
|
121
139
|
```
|
|
122
140
|
|
|
123
|
-
### session.destroy()
|
|
141
|
+
### `session.destroy(): void`
|
|
124
142
|
|
|
125
|
-
Destroys the session.
|
|
143
|
+
Destroys the session. This is a synchronous operation as it only removes the cookie. It must be done before headers are sent to the client.
|
|
126
144
|
|
|
127
145
|
```ts
|
|
128
146
|
await session.destroy()
|
|
129
147
|
```
|
|
130
148
|
|
|
149
|
+
### `sealData(data: unknown, { password, ttl }): Promise<string>`
|
|
150
|
+
|
|
151
|
+
This is the underlying method and seal mechanism that powers `iron-session`. You can use it to seal any `data` you want and pass it around. One usecase are magic links: you generate a seal that contains a user id to login and send it to a route on your website (like `/magic-login`). Once received, you can safely decode the seal with `unsealData` and log the user in.
|
|
152
|
+
|
|
153
|
+
### `unSealData<T>(seal: string, { password, ttl }): Promise<T>`
|
|
154
|
+
|
|
155
|
+
This is the opposite of `sealData` and allow you to decode a seal to get the original data back.
|
|
156
|
+
|
|
157
|
+
## FAQ
|
|
158
|
+
|
|
159
|
+
### Why use pure cookies for sessions?
|
|
160
|
+
|
|
161
|
+
This makes your sessions stateless: since the data is passed around in cookies, you do not need any server or service to store session data.
|
|
162
|
+
|
|
163
|
+
More information can also be found on the [Ruby On Rails website](https://guides.rubyonrails.org/security.html#session-storage) which uses the same technique.
|
|
164
|
+
|
|
165
|
+
### How to invalidate sessions?
|
|
166
|
+
|
|
167
|
+
Sessions cannot be instantly invalidated (or "disconnect this customer") as there is typically no state stored about sessions on the server by default. However, in most applications, the first step upon receiving an authenticated request is to validate the user and their permissions in the database. So, to easily disconnect customers (or invalidate sessions), you can add an `isBlocked`` state in the database and create a UI to block customers.
|
|
168
|
+
|
|
169
|
+
Then, every time a request is received that involves reading or altering sensitive data, make sure to check this flag.
|
|
170
|
+
|
|
171
|
+
### Can I use something else than cookies?
|
|
172
|
+
|
|
173
|
+
Yes, we expose `sealData` and `unsealData` which are not tied to cookies. This way you can seal and unseal any object in your application and move seals around to login users.
|
|
174
|
+
|
|
175
|
+
### How is this different from [JWT](https://jwt.io/)?
|
|
176
|
+
|
|
177
|
+
Not so much:
|
|
178
|
+
|
|
179
|
+
- JWT is a standard, it stores metadata in the JWT token themselves to ensure communication between different systems is flawless.
|
|
180
|
+
- JWT tokens are not encrypted, the payload is visible by customers if they manage to inspect the seal. You would have to use [JWE](https://tools.ietf.org/html/rfc7516) to achieve the same.
|
|
181
|
+
- @hapi/iron mechanism is not a standard, it's a way to sign and encrypt data into seals
|
|
182
|
+
|
|
183
|
+
Depending on your own needs and preferences, `iron-session` may or may not fit you.
|
|
184
|
+
|
|
131
185
|
## Credits
|
|
132
186
|
|
|
133
187
|
- [Eran Hammer and hapi.js contributors](https://github.com/hapijs/iron/graphs/contributors)
|
package/dist/index.cjs
CHANGED
|
@@ -85,7 +85,6 @@ function createSealData(_crypto) {
|
|
|
85
85
|
);
|
|
86
86
|
const passwordForSeal = {
|
|
87
87
|
id: mostRecentPasswordId.toString(),
|
|
88
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
89
88
|
secret: passwordsMap[mostRecentPasswordId]
|
|
90
89
|
};
|
|
91
90
|
const seal = await ironWebcrypto.seal(_crypto, data, passwordForSeal, {
|
|
@@ -121,15 +120,13 @@ function createUnsealData(_crypto) {
|
|
|
121
120
|
}
|
|
122
121
|
};
|
|
123
122
|
}
|
|
124
|
-
function
|
|
123
|
+
function getSessionConfig(sessionOptions) {
|
|
125
124
|
const options = {
|
|
126
125
|
...defaultOptions,
|
|
127
126
|
...sessionOptions,
|
|
128
|
-
...overrides,
|
|
129
127
|
cookieOptions: {
|
|
130
128
|
...defaultOptions.cookieOptions,
|
|
131
|
-
...sessionOptions.cookieOptions
|
|
132
|
-
...overrides?.cookieOptions
|
|
129
|
+
...sessionOptions.cookieOptions || {}
|
|
133
130
|
}
|
|
134
131
|
};
|
|
135
132
|
if (sessionOptions.cookieOptions && "maxAge" in sessionOptions.cookieOptions) {
|
|
@@ -141,7 +138,7 @@ function mergeOptions(sessionOptions, overrides) {
|
|
|
141
138
|
}
|
|
142
139
|
return options;
|
|
143
140
|
}
|
|
144
|
-
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(
|
|
141
|
+
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options).";
|
|
145
142
|
function createGetIronSession(sealData2, unsealData2) {
|
|
146
143
|
return getIronSession2;
|
|
147
144
|
async function getIronSession2(reqOrCookieStore, resOrsessionOptions, sessionOptions) {
|
|
@@ -162,7 +159,7 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
162
159
|
const req = reqOrCookieStore;
|
|
163
160
|
const res = resOrsessionOptions;
|
|
164
161
|
if (!sessionOptions) {
|
|
165
|
-
throw new Error(
|
|
162
|
+
throw new Error(badUsageMessage);
|
|
166
163
|
}
|
|
167
164
|
if (!sessionOptions.cookieName) {
|
|
168
165
|
throw new Error("iron-session: Bad usage. Missing cookie name.");
|
|
@@ -176,29 +173,33 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
176
173
|
"iron-session: Bad usage. Password must be at least 32 characters long."
|
|
177
174
|
);
|
|
178
175
|
}
|
|
179
|
-
|
|
180
|
-
const sealFromCookies = getCookie(req,
|
|
176
|
+
let sessionConfig = getSessionConfig(sessionOptions);
|
|
177
|
+
const sealFromCookies = getCookie(req, sessionConfig.cookieName);
|
|
181
178
|
const session = sealFromCookies ? await unsealData2(sealFromCookies, {
|
|
182
179
|
password: passwordsMap,
|
|
183
|
-
ttl:
|
|
180
|
+
ttl: sessionConfig.ttl
|
|
184
181
|
}) : {};
|
|
185
182
|
Object.defineProperties(session, {
|
|
183
|
+
updateConfig: {
|
|
184
|
+
value: function updateConfig(newSessionOptions) {
|
|
185
|
+
sessionConfig = getSessionConfig(newSessionOptions);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
186
188
|
save: {
|
|
187
|
-
value: async function save(
|
|
189
|
+
value: async function save() {
|
|
188
190
|
if ("headersSent" in res && res.headersSent) {
|
|
189
191
|
throw new Error(
|
|
190
192
|
"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()"
|
|
191
193
|
);
|
|
192
194
|
}
|
|
193
|
-
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
|
|
194
195
|
const seal = await sealData2(session, {
|
|
195
196
|
password: passwordsMap,
|
|
196
|
-
ttl:
|
|
197
|
+
ttl: sessionConfig.ttl
|
|
197
198
|
});
|
|
198
199
|
const cookieValue = cookie.serialize(
|
|
199
|
-
|
|
200
|
+
sessionConfig.cookieName,
|
|
200
201
|
seal,
|
|
201
|
-
|
|
202
|
+
sessionConfig.cookieOptions
|
|
202
203
|
);
|
|
203
204
|
if (cookieValue.length > 4096) {
|
|
204
205
|
throw new Error(
|
|
@@ -209,13 +210,12 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
209
210
|
}
|
|
210
211
|
},
|
|
211
212
|
destroy: {
|
|
212
|
-
value:
|
|
213
|
+
value: function destroy() {
|
|
213
214
|
Object.keys(session).forEach((key) => {
|
|
214
215
|
delete session[key];
|
|
215
216
|
});
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
...mergedOptions.cookieOptions,
|
|
217
|
+
const cookieValue = cookie.serialize(sessionConfig.cookieName, "", {
|
|
218
|
+
...sessionConfig.cookieOptions,
|
|
219
219
|
maxAge: 0
|
|
220
220
|
});
|
|
221
221
|
setCookie(res, cookieValue);
|
|
@@ -226,9 +226,6 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
async function getIronSessionFromCookieStore(cookieStore, sessionOptions, sealData2, unsealData2) {
|
|
229
|
-
if (!sessionOptions) {
|
|
230
|
-
throw new Error("iron-session: Bad usage. Missing options.");
|
|
231
|
-
}
|
|
232
229
|
if (!sessionOptions.cookieName) {
|
|
233
230
|
throw new Error("iron-session: Bad usage. Missing cookie name.");
|
|
234
231
|
}
|
|
@@ -241,44 +238,42 @@ async function getIronSessionFromCookieStore(cookieStore, sessionOptions, sealDa
|
|
|
241
238
|
"iron-session: Bad usage. Password must be at least 32 characters long."
|
|
242
239
|
);
|
|
243
240
|
}
|
|
244
|
-
const
|
|
241
|
+
const sessionConfig = getSessionConfig(sessionOptions);
|
|
245
242
|
const sealFromCookies = getServerActionCookie(
|
|
246
|
-
|
|
243
|
+
sessionConfig.cookieName,
|
|
247
244
|
cookieStore
|
|
248
245
|
);
|
|
249
246
|
const session = sealFromCookies ? await unsealData2(sealFromCookies, {
|
|
250
247
|
password: passwordsMap,
|
|
251
|
-
ttl:
|
|
248
|
+
ttl: sessionConfig.ttl
|
|
252
249
|
}) : {};
|
|
253
250
|
Object.defineProperties(session, {
|
|
254
251
|
save: {
|
|
255
|
-
value: async function save(
|
|
256
|
-
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
|
|
252
|
+
value: async function save() {
|
|
257
253
|
const seal = await sealData2(session, {
|
|
258
254
|
password: passwordsMap,
|
|
259
|
-
ttl:
|
|
255
|
+
ttl: sessionConfig.ttl
|
|
260
256
|
});
|
|
261
|
-
const cookieLength =
|
|
257
|
+
const cookieLength = sessionConfig.cookieName.length + seal.length + JSON.stringify(sessionConfig.cookieOptions).length;
|
|
262
258
|
if (cookieLength > 4096) {
|
|
263
259
|
throw new Error(
|
|
264
260
|
`iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`
|
|
265
261
|
);
|
|
266
262
|
}
|
|
267
263
|
cookieStore.set(
|
|
268
|
-
|
|
264
|
+
sessionConfig.cookieName,
|
|
269
265
|
seal,
|
|
270
|
-
|
|
266
|
+
sessionConfig.cookieOptions
|
|
271
267
|
);
|
|
272
268
|
}
|
|
273
269
|
},
|
|
274
270
|
destroy: {
|
|
275
|
-
value:
|
|
271
|
+
value: function destroy() {
|
|
276
272
|
Object.keys(session).forEach((key) => {
|
|
277
273
|
delete session[key];
|
|
278
274
|
});
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
cookieStore.set(mergedOptions.cookieName, "", cookieOptions);
|
|
275
|
+
const cookieOptions = { ...sessionConfig.cookieOptions, maxAge: 0 };
|
|
276
|
+
cookieStore.set(sessionConfig.cookieName, "", cookieOptions);
|
|
282
277
|
}
|
|
283
278
|
}
|
|
284
279
|
});
|
|
@@ -288,9 +283,6 @@ var sealData = createSealData(crypto__namespace);
|
|
|
288
283
|
var unsealData = createUnsealData(crypto__namespace);
|
|
289
284
|
var getIronSession = createGetIronSession(sealData, unsealData);
|
|
290
285
|
|
|
291
|
-
exports.createGetIronSession = createGetIronSession;
|
|
292
|
-
exports.createSealData = createSealData;
|
|
293
|
-
exports.createUnsealData = createUnsealData;
|
|
294
286
|
exports.getIronSession = getIronSession;
|
|
295
287
|
exports.sealData = sealData;
|
|
296
288
|
exports.unsealData = unsealData;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"names":["sealData","unsealData","getIronSession"],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from \"http\";\nimport { parse, serialize, type CookieSerializeOptions } from \"cookie\";\nimport {\n defaults as ironDefaults,\n seal as ironSeal,\n unseal as ironUnseal,\n} from \"iron-webcrypto\";\n\ntype PasswordsMap = Record<string, string>;\ntype Password = PasswordsMap | string;\ntype RequestType = IncomingMessage | Request;\ntype ResponseType = Response | ServerResponse;\n\n/**\n * {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}\n * as specified by W3C.\n */\ninterface CookieListItem\n extends Pick<\n CookieSerializeOptions,\n \"domain\" | \"path\" | \"sameSite\" | \"secure\"\n > {\n /** A string with the name of a cookie. */\n name: string;\n /** A string containing the value of the cookie. */\n value: string;\n /** A number of milliseconds or Date interface containing the expires of the cookie. */\n expires?: CookieSerializeOptions[\"expires\"] | number;\n}\n\n/**\n * Superset of {@link CookieListItem} extending it with\n * the `httpOnly`, `maxAge` and `priority` properties.\n */\ntype ResponseCookie = CookieListItem &\n Pick<CookieSerializeOptions, \"httpOnly\" | \"maxAge\" | \"priority\">;\n\n/**\n * The high-level type definition of the .get() and .set() methods\n * of { cookies() } from \"next/headers\"\n */\nexport interface CookieStore {\n get: (name: string) => { name: string; value: string } | undefined;\n set: {\n (name: string, value: string, cookie?: Partial<ResponseCookie>): void;\n (options: ResponseCookie): void;\n };\n}\n\n/**\n * Set-Cookie Attributes do not include `encode`. We omit this from our `cookieOptions` type.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie\n * @see https://developer.chrome.com/docs/devtools/application/cookies/\n */\ntype CookieOptions = Omit<CookieSerializeOptions, \"encode\">;\n\nexport interface SessionOptions {\n /**\n * The cookie name that will be used inside the browser. Make sure it's unique\n * given your application.\n *\n * @example 'vercel-session'\n */\n cookieName: string;\n\n /**\n * The password(s) that will be used to encrypt the cookie. Can either be a string\n * or an object.\n *\n * When you provide multiple passwords then all of them will be used to decrypt\n * the cookie. But only the most recent (`= highest key`, `2` in the example)\n * password will be used to encrypt the cookie. This allows password rotation.\n *\n * @example { 1: 'password-1', 2: 'password-2' }\n */\n password: Password;\n\n /**\n * The time (in seconds) that the session will be valid for. Also sets the\n * `max-age` attribute of the cookie automatically (`= ttl - 60s`, so that the\n * cookie always expire before the session).\n *\n * `ttl = 0` means no expiration.\n *\n * @default 1209600\n */\n ttl?: number;\n\n /**\n * The options that will be passed to the cookie library.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser\n * is closed) then you need to pass `cookieOptions: { maxAge: undefined }`\n *\n * @see https://github.com/jshttp/cookie#options-1\n */\n cookieOptions?: CookieOptions;\n}\n\ntype OverridableOptions = Pick<SessionOptions, \"cookieOptions\" | \"ttl\">;\n\nexport type IronSession<T> = T & {\n /**\n * Destroys the session data and removes the cookie.\n */\n readonly destroy: (destroyOptions?: OverridableOptions) => Promise<void>;\n\n /**\n * Encrypts the session data and sets the cookie.\n */\n readonly save: (saveOptions?: OverridableOptions) => Promise<void>;\n};\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/module/iron/api/?v=7.0.1#options\nconst timestampSkewSec = 60;\nconst fourteenDaysInSeconds = 14 * 24 * 3600;\n\n// We store a token major version to handle data format changes so that the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: Required<OverridableOptions> = {\n ttl: fourteenDaysInSeconds,\n cookieOptions: { httpOnly: true, secure: true, sameSite: \"lax\", path: \"/\" },\n};\n\nfunction normalizeStringPasswordToMap(password: Password): PasswordsMap {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n const tokenVersion =\n tokenVersionAsString == null ? null : parseInt(tokenVersionAsString, 10);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { sealWithoutVersion: sealWithoutVersion!, tokenVersion };\n}\n\nfunction computeCookieMaxAge(ttl: number): number {\n if (ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n return 2147483647;\n }\n\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds between server and clients.\n return ttl - timestampSkewSec;\n}\n\nfunction getCookie(req: RequestType, cookieName: string): string {\n return (\n parse(\n (\"headers\" in req && typeof req.headers.get === \"function\"\n ? req.headers.get(\"cookie\")\n : (req as IncomingMessage).headers.cookie) ?? \"\",\n )[cookieName] ?? \"\"\n );\n}\n\nfunction getServerActionCookie(\n cookieName: string,\n cookieHandler: CookieStore,\n): string {\n const cookieObject = cookieHandler.get(cookieName);\n const cookie = cookieObject?.value;\n if (typeof cookie === \"string\") {\n return cookie;\n }\n return \"\";\n}\n\nfunction setCookie(res: ResponseType, cookieValue: string): void {\n if (\"headers\" in res && typeof res.headers.append === \"function\") {\n res.headers.append(\"set-cookie\", cookieValue);\n return;\n }\n let existingSetCookie = (res as ServerResponse).getHeader(\"set-cookie\") ?? [];\n if (!Array.isArray(existingSetCookie)) {\n existingSetCookie = [existingSetCookie.toString()];\n }\n (res as ServerResponse).setHeader(\"set-cookie\", [\n ...existingSetCookie,\n cookieValue,\n ]);\n}\n\nexport function createSealData(_crypto: Crypto) {\n return async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<string> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsMap).map(Number),\n );\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n secret: passwordsMap[mostRecentPasswordId]!,\n };\n\n const seal = await ironSeal(_crypto, data, passwordForSeal, {\n ...ironDefaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n };\n}\n\nexport function createUnsealData(_crypto: Crypto) {\n return async function unsealData<T>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<T> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data =\n (await ironUnseal(_crypto, sealWithoutVersion, passwordsMap, {\n ...ironDefaults,\n ttl: ttl * 1000,\n })) /* c8 ignore next */ ?? {};\n\n if (tokenVersion === 2) {\n return data as T;\n }\n\n // @ts-expect-error `persistent` does not exist on newer tokens\n return { ...data.persistent } as T;\n } catch (error) {\n if (\n error instanceof Error &&\n /^(Expired seal|Bad hmac value|Cannot find password|Incorrect number of sealed components)/.test(\n error.message,\n )\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are badly rotated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return {} as T;\n }\n\n /* c8 ignore next 2 */\n throw error;\n }\n };\n}\n\nfunction mergeOptions(\n sessionOptions: SessionOptions,\n overrides?: OverridableOptions,\n): Required<SessionOptions> {\n const options: Required<SessionOptions> = {\n ...defaultOptions,\n ...sessionOptions,\n ...overrides,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...sessionOptions.cookieOptions,\n ...overrides?.cookieOptions,\n },\n };\n\n if (\n sessionOptions.cookieOptions &&\n \"maxAge\" in sessionOptions.cookieOptions\n ) {\n if (sessionOptions.cookieOptions.maxAge === undefined) {\n // session cookies, do not set maxAge, consider token as infinite\n options.ttl = 0;\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n return options;\n}\n\nconst badUsageMessage =\n \"iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookies, options).\";\n\nexport function createGetIronSession(\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n) {\n return getIronSession;\n\n async function getIronSession<T extends object>(\n cookies: CookieStore,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n req: RequestType,\n res: ResponseType,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n reqOrCookieStore: RequestType | CookieStore,\n resOrsessionOptions: ResponseType | SessionOptions,\n sessionOptions?: SessionOptions,\n ): Promise<IronSession<T>> {\n if (!reqOrCookieStore) {\n throw new Error(badUsageMessage);\n }\n\n if (!resOrsessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions) {\n return getIronSessionFromCookieStore<T>(\n reqOrCookieStore as CookieStore,\n resOrsessionOptions as SessionOptions,\n sealData,\n unsealData,\n );\n }\n\n const req = reqOrCookieStore as RequestType;\n const res = resOrsessionOptions as ResponseType;\n\n if (!sessionOptions) {\n throw new Error(\"iron-session: Bad usage. Missing options.\");\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const options = mergeOptions(sessionOptions);\n const sealFromCookies = getCookie(req, options.cookieName);\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: options.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save(saveOptions?: OverridableOptions) {\n if (\"headersSent\" in res && res.headersSent) {\n throw new Error(\n \"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()\",\n );\n }\n\n const mergedOptions = mergeOptions(sessionOptions, saveOptions);\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: mergedOptions.ttl,\n });\n const cookieValue = serialize(\n mergedOptions.cookieName,\n seal,\n mergedOptions.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieValue.length} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n setCookie(res, cookieValue);\n },\n },\n\n destroy: {\n value: async function destroy(destroyOptions?: OverridableOptions) {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n\n const mergedOptions = mergeOptions(sessionOptions, destroyOptions);\n const cookieValue = serialize(mergedOptions.cookieName, \"\", {\n ...mergedOptions.cookieOptions,\n maxAge: 0,\n });\n\n setCookie(res, cookieValue);\n },\n },\n });\n\n return session as IronSession<T>;\n }\n}\n\nasync function getIronSessionFromCookieStore<T extends object>(\n cookieStore: CookieStore,\n sessionOptions: SessionOptions,\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n): Promise<IronSession<T>> {\n if (!sessionOptions) {\n throw new Error(\"iron-session: Bad usage. Missing options.\");\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const options = mergeOptions(sessionOptions);\n const sealFromCookies = getServerActionCookie(\n options.cookieName,\n cookieStore,\n );\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: options.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save(saveOptions?: OverridableOptions) {\n const mergedOptions = mergeOptions(sessionOptions, saveOptions);\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: mergedOptions.ttl,\n });\n\n const cookieLength =\n mergedOptions.cookieName.length +\n seal.length +\n JSON.stringify(mergedOptions.cookieOptions).length;\n\n if (cookieLength > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n cookieStore.set(\n mergedOptions.cookieName,\n seal,\n mergedOptions.cookieOptions,\n );\n },\n },\n\n destroy: {\n value: async function destroy(destroyOptions: OverridableOptions) {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n const mergedOptions = mergeOptions(sessionOptions, destroyOptions);\n const cookieOptions = { ...mergedOptions.cookieOptions, maxAge: 0 };\n\n cookieStore.set(mergedOptions.cookieName, \"\", cookieOptions);\n },\n },\n });\n\n return session as IronSession<T>;\n}\n","import {\n createGetIronSession,\n createSealData,\n createUnsealData,\n} from \"./core.js\";\n\nimport * as crypto from \"uncrypto\";\n\nexport * from \"./core.js\";\nexport const sealData = createSealData(crypto);\nexport const unsealData = createUnsealData(crypto);\nexport const getIronSession = createGetIronSession(sealData, unsealData);\n// export const getServerActionIronSession = createGetServerActionIronSession(\n// sealData,\n// unsealData,\n// );\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"names":["sealData","unsealData","getIronSession"],"mappings":";AACA,SAAS,OAAO,iBAA8C;AAC9D;AAAA,EACE,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,OACL;AAiHP,IAAM,mBAAmB;AACzB,IAAM,wBAAwB,KAAK,KAAK;AAIxC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAEzB,IAAM,iBACJ;AAAA,EACE,KAAK;AAAA,EACL,eAAe,EAAE,UAAU,MAAM,QAAQ,MAAM,UAAU,OAAO,MAAM,IAAI;AAC5E;AAEF,SAAS,6BAA6B,UAAkC;AACtE,SAAO,OAAO,aAAa,WAAW,EAAE,GAAG,SAAS,IAAI;AAC1D;AAEA,SAAS,UAAU,MAGjB;AACA,QAAM,CAAC,oBAAoB,oBAAoB,IAC7C,KAAK,MAAM,gBAAgB;AAC7B,QAAM,eACJ,wBAAwB,OAAO,OAAO,SAAS,sBAAsB,EAAE;AAGzE,SAAO,EAAE,oBAAyC,aAAa;AACjE;AAEA,SAAS,oBAAoB,KAAqB;AAChD,MAAI,QAAQ,GAAG;AAKb,WAAO;AAAA,EACT;AAIA,SAAO,MAAM;AACf;AAEA,SAAS,UAAU,KAAkB,YAA4B;AAC/D,SACE;AAAA,KACG,aAAa,OAAO,OAAO,IAAI,QAAQ,QAAQ,aAC5C,IAAI,QAAQ,IAAI,QAAQ,IACvB,IAAwB,QAAQ,WAAW;AAAA,EAClD,EAAE,UAAU,KAAK;AAErB;AAEA,SAAS,sBACP,YACA,eACQ;AACR,QAAM,eAAe,cAAc,IAAI,UAAU;AACjD,QAAM,SAAS,cAAc;AAC7B,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,UAAU,KAAmB,aAA2B;AAC/D,MAAI,aAAa,OAAO,OAAO,IAAI,QAAQ,WAAW,YAAY;AAChE,QAAI,QAAQ,OAAO,cAAc,WAAW;AAC5C;AAAA,EACF;AACA,MAAI,oBAAqB,IAAuB,UAAU,YAAY,KAAK,CAAC;AAC5E,MAAI,CAAC,MAAM,QAAQ,iBAAiB,GAAG;AACrC,wBAAoB,CAAC,kBAAkB,SAAS,CAAC;AAAA,EACnD;AACA,EAAC,IAAuB,UAAU,cAAc;AAAA,IAC9C,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAEO,SAAS,eAAe,SAAiB;AAC9C,SAAO,eAAeA,UACpB,MACA;AAAA,IACE;AAAA,IACA,MAAM;AAAA,EACR,GACiB;AACjB,UAAM,eAAe,6BAA6B,QAAQ;AAE1D,UAAM,uBAAuB,KAAK;AAAA,MAChC,GAAG,OAAO,KAAK,YAAY,EAAE,IAAI,MAAM;AAAA,IACzC;AACA,UAAM,kBAAkB;AAAA,MACtB,IAAI,qBAAqB,SAAS;AAAA,MAClC,QAAQ,aAAa,oBAAoB;AAAA,IAC3C;AAEA,UAAM,OAAO,MAAM,SAAS,SAAS,MAAM,iBAAiB;AAAA,MAC1D,GAAG;AAAA,MACH,KAAK,MAAM;AAAA,IACb,CAAC;AAED,WAAO,GAAG,IAAI,GAAG,gBAAgB,GAAG,mBAAmB;AAAA,EACzD;AACF;AAEO,SAAS,iBAAiB,SAAiB;AAChD,SAAO,eAAeC,YACpB,MACA;AAAA,IACE;AAAA,IACA,MAAM;AAAA,EACR,GACY;AACZ,UAAM,eAAe,6BAA6B,QAAQ;AAC1D,UAAM,EAAE,oBAAoB,aAAa,IAAI,UAAU,IAAI;AAE3D,QAAI;AACF,YAAM,OACH,MAAM,WAAW,SAAS,oBAAoB,cAAc;AAAA,QAC3D,GAAG;AAAA,QACH,KAAK,MAAM;AAAA,MACb,CAAC,KAAM,CAAC;AAEV,UAAI,iBAAiB,GAAG;AACtB,eAAO;AAAA,MACT;AAGA,aAAO,EAAE,GAAG,KAAK,WAAW;AAAA,IAC9B,SAAS,OAAO;AACd,UACE,iBAAiB,SACjB,4FAA4F;AAAA,QAC1F,MAAM;AAAA,MACR,GACA;AAKA,eAAO,CAAC;AAAA,MACV;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,iBACP,gBAC0B;AAC1B,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,GAAG;AAAA,IACH,eAAe;AAAA,MACb,GAAG,eAAe;AAAA,MAClB,GAAI,eAAe,iBAAiB,CAAC;AAAA,IACvC;AAAA,EACF;AAEA,MACE,eAAe,iBACf,YAAY,eAAe,eAC3B;AACA,QAAI,eAAe,cAAc,WAAW,QAAW;AAErD,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF,OAAO;AACL,YAAQ,cAAc,SAAS,oBAAoB,QAAQ,GAAG;AAAA,EAChE;AAEA,SAAO;AACT;AAEA,IAAM,kBACJ;AAEK,SAAS,qBACdD,WACAC,aACA;AACA,SAAOC;AAWP,iBAAeA,gBACb,kBACA,qBACA,gBACyB;AACzB,QAAI,CAAC,kBAAkB;AACrB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACAF;AAAA,QACAC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM;AACZ,UAAM,MAAM;AAEZ,QAAI,CAAC,gBAAgB;AACnB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,eAAe,YAAY;AAC9B,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,QAAI,CAAC,eAAe,UAAU;AAC5B,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,eAAe,6BAA6B,eAAe,QAAQ;AAEzE,QAAI,OAAO,OAAO,YAAY,EAAE,KAAK,CAAC,aAAa,SAAS,SAAS,EAAE,GAAG;AACxE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,gBAAgB,iBAAiB,cAAc;AAEnD,UAAM,kBAAkB,UAAU,KAAK,cAAc,UAAU;AAC/D,UAAM,UAAU,kBACZ,MAAMA,YAAc,iBAAiB;AAAA,MACnC,UAAU;AAAA,MACV,KAAK,cAAc;AAAA,IACrB,CAAC,IACA,CAAC;AAEN,WAAO,iBAAiB,SAAS;AAAA,MAC/B,cAAc;AAAA,QACZ,OAAO,SAAS,aAAa,mBAAmC;AAC9D,0BAAgB,iBAAiB,iBAAiB;AAAA,QACpD;AAAA,MACF;AAAA,MACA,MAAM;AAAA,QACJ,OAAO,eAAe,OAAO;AAC3B,cAAI,iBAAiB,OAAO,IAAI,aAAa;AAC3C,kBAAM,IAAI;AAAA,cACR;AAAA,YACF;AAAA,UACF;AAEA,gBAAM,OAAO,MAAMD,UAAS,SAAS;AAAA,YACnC,UAAU;AAAA,YACV,KAAK,cAAc;AAAA,UACrB,CAAC;AACD,gBAAM,cAAc;AAAA,YAClB,cAAc;AAAA,YACd;AAAA,YACA,cAAc;AAAA,UAChB;AAEA,cAAI,YAAY,SAAS,MAAM;AAC7B,kBAAM,IAAI;AAAA,cACR,2CAA2C,YAAY,MAAM;AAAA,YAC/D;AAAA,UACF;AAEA,oBAAU,KAAK,WAAW;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,SAAS;AAAA,QACP,OAAO,SAAS,UAAU;AACxB,iBAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,mBAAQ,QAAoC,GAAG;AAAA,UACjD,CAAC;AACD,gBAAM,cAAc,UAAU,cAAc,YAAY,IAAI;AAAA,YAC1D,GAAG,cAAc;AAAA,YACjB,QAAQ;AAAA,UACV,CAAC;AAED,oBAAU,KAAK,WAAW;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;AAEA,eAAe,8BACb,aACA,gBACAA,WACAC,aACyB;AACzB,MAAI,CAAC,eAAe,YAAY;AAC9B,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,MAAI,CAAC,eAAe,UAAU;AAC5B,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,QAAM,eAAe,6BAA6B,eAAe,QAAQ;AAEzE,MAAI,OAAO,OAAO,YAAY,EAAE,KAAK,CAAC,aAAa,SAAS,SAAS,EAAE,GAAG;AACxE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBAAgB,iBAAiB,cAAc;AACrD,QAAM,kBAAkB;AAAA,IACtB,cAAc;AAAA,IACd;AAAA,EACF;AACA,QAAM,UAAU,kBACZ,MAAMA,YAAc,iBAAiB;AAAA,IACnC,UAAU;AAAA,IACV,KAAK,cAAc;AAAA,EACrB,CAAC,IACA,CAAC;AAEN,SAAO,iBAAiB,SAAS;AAAA,IAC/B,MAAM;AAAA,MACJ,OAAO,eAAe,OAAO;AAC3B,cAAM,OAAO,MAAMD,UAAS,SAAS;AAAA,UACnC,UAAU;AAAA,UACV,KAAK,cAAc;AAAA,QACrB,CAAC;AAED,cAAM,eACJ,cAAc,WAAW,SACzB,KAAK,SACL,KAAK,UAAU,cAAc,aAAa,EAAE;AAE9C,YAAI,eAAe,MAAM;AACvB,gBAAM,IAAI;AAAA,YACR,2CAA2C,YAAY;AAAA,UACzD;AAAA,QACF;AAEA,oBAAY;AAAA,UACV,cAAc;AAAA,UACd;AAAA,UACA,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,OAAO,SAAS,UAAU;AACxB,eAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,iBAAQ,QAAoC,GAAG;AAAA,QACjD,CAAC;AAED,cAAM,gBAAgB,EAAE,GAAG,cAAc,eAAe,QAAQ,EAAE;AAClE,oBAAY,IAAI,cAAc,YAAY,IAAI,aAAa;AAAA,MAC7D;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AC5eA,YAAY,YAAY;AAGjB,IAAM,WAAW,eAAe,MAAM;AACtC,IAAM,aAAa,iBAAiB,MAAM;AAC1C,IAAM,iBAAiB,qBAAqB,UAAU,UAAU","sourcesContent":["import type { IncomingMessage, ServerResponse } from \"http\";\nimport { parse, serialize, type CookieSerializeOptions } from \"cookie\";\nimport {\n defaults as ironDefaults,\n seal as ironSeal,\n unseal as ironUnseal,\n} from \"iron-webcrypto\";\n\ntype PasswordsMap = Record<string, string>;\ntype Password = PasswordsMap | string;\ntype RequestType = IncomingMessage | Request;\ntype ResponseType = Response | ServerResponse;\n\n/**\n * {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}\n * as specified by W3C.\n */\ninterface CookieListItem\n extends Pick<\n CookieSerializeOptions,\n \"domain\" | \"path\" | \"sameSite\" | \"secure\"\n > {\n /** A string with the name of a cookie. */\n name: string;\n /** A string containing the value of the cookie. */\n value: string;\n /** A number of milliseconds or Date interface containing the expires of the cookie. */\n expires?: CookieSerializeOptions[\"expires\"] | number;\n}\n\n/**\n * Superset of {@link CookieListItem} extending it with\n * the `httpOnly`, `maxAge` and `priority` properties.\n */\ntype ResponseCookie = CookieListItem &\n Pick<CookieSerializeOptions, \"httpOnly\" | \"maxAge\" | \"priority\">;\n\n/**\n * The high-level type definition of the .get() and .set() methods\n * of { cookies() } from \"next/headers\"\n */\nexport interface CookieStore {\n get: (name: string) => { name: string; value: string } | undefined;\n set: {\n (name: string, value: string, cookie?: Partial<ResponseCookie>): void;\n (options: ResponseCookie): void;\n };\n}\n\n/**\n * Set-Cookie Attributes do not include `encode`. We omit this from our `cookieOptions` type.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie\n * @see https://developer.chrome.com/docs/devtools/application/cookies/\n */\ntype CookieOptions = Omit<CookieSerializeOptions, \"encode\">;\n\nexport interface SessionOptions {\n /**\n * The cookie name that will be used inside the browser. Make sure it's unique\n * given your application.\n *\n * @example 'vercel-session'\n */\n cookieName: string;\n\n /**\n * The password(s) that will be used to encrypt the cookie. Can either be a string\n * or an object.\n *\n * When you provide multiple passwords then all of them will be used to decrypt\n * the cookie. But only the most recent (`= highest key`, `2` in the example)\n * password will be used to encrypt the cookie. This allows password rotation.\n *\n * @example { 1: 'password-1', 2: 'password-2' }\n */\n password: Password;\n\n /**\n * The time (in seconds) that the session will be valid for. Also sets the\n * `max-age` attribute of the cookie automatically (`= ttl - 60s`, so that the\n * cookie always expire before the session).\n *\n * `ttl = 0` means no expiration.\n *\n * @default 1209600\n */\n ttl?: number;\n\n /**\n * The options that will be passed to the cookie library.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser\n * is closed) then you need to pass `cookieOptions: { maxAge: undefined }`\n *\n * @see https://github.com/jshttp/cookie#options-1\n */\n cookieOptions?: CookieOptions;\n}\n\nexport type IronSession<T> = T & {\n /**\n * Encrypts the session data and sets the cookie.\n */\n readonly save: () => Promise<void>;\n\n /**\n * Destroys the session data and removes the cookie.\n */\n readonly destroy: () => Promise<void>;\n\n /**\n * Update the session configuration. You still need to call save() to send the new cookie.\n */\n readonly updateConfig: (newSessionOptions: SessionOptions) => void;\n};\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/module/iron/api/?v=7.0.1#options\nconst timestampSkewSec = 60;\nconst fourteenDaysInSeconds = 14 * 24 * 3600;\n\n// We store a token major version to handle data format changes so that the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: Required<Pick<SessionOptions, \"ttl\" | \"cookieOptions\">> =\n {\n ttl: fourteenDaysInSeconds,\n cookieOptions: { httpOnly: true, secure: true, sameSite: \"lax\", path: \"/\" },\n };\n\nfunction normalizeStringPasswordToMap(password: Password): PasswordsMap {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n const tokenVersion =\n tokenVersionAsString == null ? null : parseInt(tokenVersionAsString, 10);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { sealWithoutVersion: sealWithoutVersion!, tokenVersion };\n}\n\nfunction computeCookieMaxAge(ttl: number): number {\n if (ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n return 2147483647;\n }\n\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds between server and clients.\n return ttl - timestampSkewSec;\n}\n\nfunction getCookie(req: RequestType, cookieName: string): string {\n return (\n parse(\n (\"headers\" in req && typeof req.headers.get === \"function\"\n ? req.headers.get(\"cookie\")\n : (req as IncomingMessage).headers.cookie) ?? \"\",\n )[cookieName] ?? \"\"\n );\n}\n\nfunction getServerActionCookie(\n cookieName: string,\n cookieHandler: CookieStore,\n): string {\n const cookieObject = cookieHandler.get(cookieName);\n const cookie = cookieObject?.value;\n if (typeof cookie === \"string\") {\n return cookie;\n }\n return \"\";\n}\n\nfunction setCookie(res: ResponseType, cookieValue: string): void {\n if (\"headers\" in res && typeof res.headers.append === \"function\") {\n res.headers.append(\"set-cookie\", cookieValue);\n return;\n }\n let existingSetCookie = (res as ServerResponse).getHeader(\"set-cookie\") ?? [];\n if (!Array.isArray(existingSetCookie)) {\n existingSetCookie = [existingSetCookie.toString()];\n }\n (res as ServerResponse).setHeader(\"set-cookie\", [\n ...existingSetCookie,\n cookieValue,\n ]);\n}\n\nexport function createSealData(_crypto: Crypto) {\n return async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<string> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsMap).map(Number),\n );\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n secret: passwordsMap[mostRecentPasswordId]!,\n };\n\n const seal = await ironSeal(_crypto, data, passwordForSeal, {\n ...ironDefaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n };\n}\n\nexport function createUnsealData(_crypto: Crypto) {\n return async function unsealData<T>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<T> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data =\n (await ironUnseal(_crypto, sealWithoutVersion, passwordsMap, {\n ...ironDefaults,\n ttl: ttl * 1000,\n })) ?? {};\n\n if (tokenVersion === 2) {\n return data as T;\n }\n\n // @ts-expect-error `persistent` does not exist on newer tokens\n return { ...data.persistent } as T;\n } catch (error) {\n if (\n error instanceof Error &&\n /^(Expired seal|Bad hmac value|Cannot find password|Incorrect number of sealed components)/.test(\n error.message,\n )\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are badly rotated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return {} as T;\n }\n\n throw error;\n }\n };\n}\n\nfunction getSessionConfig(\n sessionOptions: SessionOptions,\n): Required<SessionOptions> {\n const options = {\n ...defaultOptions,\n ...sessionOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(sessionOptions.cookieOptions || {}),\n },\n };\n\n if (\n sessionOptions.cookieOptions &&\n \"maxAge\" in sessionOptions.cookieOptions\n ) {\n if (sessionOptions.cookieOptions.maxAge === undefined) {\n // session cookies, do not set maxAge, consider token as infinite\n options.ttl = 0;\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n return options;\n}\n\nconst badUsageMessage =\n \"iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options).\";\n\nexport function createGetIronSession(\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n) {\n return getIronSession;\n\n async function getIronSession<T extends object>(\n cookies: CookieStore,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n req: RequestType,\n res: ResponseType,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n reqOrCookieStore: RequestType | CookieStore,\n resOrsessionOptions: ResponseType | SessionOptions,\n sessionOptions?: SessionOptions,\n ): Promise<IronSession<T>> {\n if (!reqOrCookieStore) {\n throw new Error(badUsageMessage);\n }\n\n if (!resOrsessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions) {\n return getIronSessionFromCookieStore<T>(\n reqOrCookieStore as CookieStore,\n resOrsessionOptions as SessionOptions,\n sealData,\n unsealData,\n );\n }\n\n const req = reqOrCookieStore as RequestType;\n const res = resOrsessionOptions as ResponseType;\n\n if (!sessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n let sessionConfig = getSessionConfig(sessionOptions);\n\n const sealFromCookies = getCookie(req, sessionConfig.cookieName);\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n updateConfig: {\n value: function updateConfig(newSessionOptions: SessionOptions) {\n sessionConfig = getSessionConfig(newSessionOptions);\n },\n },\n save: {\n value: async function save() {\n if (\"headersSent\" in res && res.headersSent) {\n throw new Error(\n \"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()\",\n );\n }\n\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n });\n const cookieValue = serialize(\n sessionConfig.cookieName,\n seal,\n sessionConfig.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieValue.length} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n setCookie(res, cookieValue);\n },\n },\n\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n const cookieValue = serialize(sessionConfig.cookieName, \"\", {\n ...sessionConfig.cookieOptions,\n maxAge: 0,\n });\n\n setCookie(res, cookieValue);\n },\n },\n });\n\n return session as IronSession<T>;\n }\n}\n\nasync function getIronSessionFromCookieStore<T extends object>(\n cookieStore: CookieStore,\n sessionOptions: SessionOptions,\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n): Promise<IronSession<T>> {\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const sessionConfig = getSessionConfig(sessionOptions);\n const sealFromCookies = getServerActionCookie(\n sessionConfig.cookieName,\n cookieStore,\n );\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save() {\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n });\n\n const cookieLength =\n sessionConfig.cookieName.length +\n seal.length +\n JSON.stringify(sessionConfig.cookieOptions).length;\n\n if (cookieLength > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n cookieStore.set(\n sessionConfig.cookieName,\n seal,\n sessionConfig.cookieOptions,\n );\n },\n },\n\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n\n const cookieOptions = { ...sessionConfig.cookieOptions, maxAge: 0 };\n cookieStore.set(sessionConfig.cookieName, \"\", cookieOptions);\n },\n },\n });\n\n return session as IronSession<T>;\n}\n","import {\n createGetIronSession,\n createSealData,\n createUnsealData,\n} from \"./core.js\";\n\nimport * as crypto from \"uncrypto\";\n\nexport type { IronSession, SessionOptions } from \"./core.js\";\nexport const sealData = createSealData(crypto);\nexport const unsealData = createUnsealData(crypto);\nexport const getIronSession = createGetIronSession(sealData, unsealData);\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
|
-
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
2
|
import { CookieSerializeOptions } from 'cookie';
|
|
4
3
|
|
|
5
4
|
type PasswordsMap = Record<string, string>;
|
|
6
5
|
type Password = PasswordsMap | string;
|
|
7
|
-
type RequestType = IncomingMessage | Request;
|
|
8
|
-
type ResponseType = Response | ServerResponse;
|
|
9
6
|
/**
|
|
10
7
|
* {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}
|
|
11
8
|
* as specified by W3C.
|
|
@@ -83,28 +80,19 @@ interface SessionOptions {
|
|
|
83
80
|
*/
|
|
84
81
|
cookieOptions?: CookieOptions;
|
|
85
82
|
}
|
|
86
|
-
type OverridableOptions = Pick<SessionOptions, "cookieOptions" | "ttl">;
|
|
87
83
|
type IronSession<T> = T & {
|
|
84
|
+
/**
|
|
85
|
+
* Encrypts the session data and sets the cookie.
|
|
86
|
+
*/
|
|
87
|
+
readonly save: () => Promise<void>;
|
|
88
88
|
/**
|
|
89
89
|
* Destroys the session data and removes the cookie.
|
|
90
90
|
*/
|
|
91
|
-
readonly destroy: (
|
|
91
|
+
readonly destroy: () => Promise<void>;
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
93
|
+
* Update the session configuration. You still need to call save() to send the new cookie.
|
|
94
94
|
*/
|
|
95
|
-
readonly
|
|
96
|
-
};
|
|
97
|
-
declare function createSealData(_crypto: Crypto): (data: unknown, { password, ttl, }: {
|
|
98
|
-
password: Password;
|
|
99
|
-
ttl?: number;
|
|
100
|
-
}) => Promise<string>;
|
|
101
|
-
declare function createUnsealData(_crypto: Crypto): <T>(seal: string, { password, ttl, }: {
|
|
102
|
-
password: Password;
|
|
103
|
-
ttl?: number;
|
|
104
|
-
}) => Promise<T>;
|
|
105
|
-
declare function createGetIronSession(sealData: ReturnType<typeof createSealData>, unsealData: ReturnType<typeof createUnsealData>): {
|
|
106
|
-
<T extends object>(cookies: CookieStore, sessionOptions: SessionOptions): Promise<IronSession<T>>;
|
|
107
|
-
<T_1 extends object>(req: RequestType, res: ResponseType, sessionOptions: SessionOptions): Promise<IronSession<T_1>>;
|
|
95
|
+
readonly updateConfig: (newSessionOptions: SessionOptions) => void;
|
|
108
96
|
};
|
|
109
97
|
|
|
110
98
|
declare const sealData: (data: unknown, { password, ttl, }: {
|
|
@@ -124,4 +112,4 @@ declare const getIronSession: {
|
|
|
124
112
|
<T_1 extends object>(req: http.IncomingMessage | Request, res: Response | http.ServerResponse<http.IncomingMessage>, sessionOptions: SessionOptions): Promise<IronSession<T_1>>;
|
|
125
113
|
};
|
|
126
114
|
|
|
127
|
-
export {
|
|
115
|
+
export { type IronSession, type SessionOptions, getIronSession, sealData, unsealData };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
|
-
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
2
|
import { CookieSerializeOptions } from 'cookie';
|
|
4
3
|
|
|
5
4
|
type PasswordsMap = Record<string, string>;
|
|
6
5
|
type Password = PasswordsMap | string;
|
|
7
|
-
type RequestType = IncomingMessage | Request;
|
|
8
|
-
type ResponseType = Response | ServerResponse;
|
|
9
6
|
/**
|
|
10
7
|
* {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}
|
|
11
8
|
* as specified by W3C.
|
|
@@ -83,28 +80,19 @@ interface SessionOptions {
|
|
|
83
80
|
*/
|
|
84
81
|
cookieOptions?: CookieOptions;
|
|
85
82
|
}
|
|
86
|
-
type OverridableOptions = Pick<SessionOptions, "cookieOptions" | "ttl">;
|
|
87
83
|
type IronSession<T> = T & {
|
|
84
|
+
/**
|
|
85
|
+
* Encrypts the session data and sets the cookie.
|
|
86
|
+
*/
|
|
87
|
+
readonly save: () => Promise<void>;
|
|
88
88
|
/**
|
|
89
89
|
* Destroys the session data and removes the cookie.
|
|
90
90
|
*/
|
|
91
|
-
readonly destroy: (
|
|
91
|
+
readonly destroy: () => Promise<void>;
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
93
|
+
* Update the session configuration. You still need to call save() to send the new cookie.
|
|
94
94
|
*/
|
|
95
|
-
readonly
|
|
96
|
-
};
|
|
97
|
-
declare function createSealData(_crypto: Crypto): (data: unknown, { password, ttl, }: {
|
|
98
|
-
password: Password;
|
|
99
|
-
ttl?: number;
|
|
100
|
-
}) => Promise<string>;
|
|
101
|
-
declare function createUnsealData(_crypto: Crypto): <T>(seal: string, { password, ttl, }: {
|
|
102
|
-
password: Password;
|
|
103
|
-
ttl?: number;
|
|
104
|
-
}) => Promise<T>;
|
|
105
|
-
declare function createGetIronSession(sealData: ReturnType<typeof createSealData>, unsealData: ReturnType<typeof createUnsealData>): {
|
|
106
|
-
<T extends object>(cookies: CookieStore, sessionOptions: SessionOptions): Promise<IronSession<T>>;
|
|
107
|
-
<T_1 extends object>(req: RequestType, res: ResponseType, sessionOptions: SessionOptions): Promise<IronSession<T_1>>;
|
|
95
|
+
readonly updateConfig: (newSessionOptions: SessionOptions) => void;
|
|
108
96
|
};
|
|
109
97
|
|
|
110
98
|
declare const sealData: (data: unknown, { password, ttl, }: {
|
|
@@ -124,4 +112,4 @@ declare const getIronSession: {
|
|
|
124
112
|
<T_1 extends object>(req: http.IncomingMessage | Request, res: Response | http.ServerResponse<http.IncomingMessage>, sessionOptions: SessionOptions): Promise<IronSession<T_1>>;
|
|
125
113
|
};
|
|
126
114
|
|
|
127
|
-
export {
|
|
115
|
+
export { type IronSession, type SessionOptions, getIronSession, sealData, unsealData };
|
package/dist/index.js
CHANGED
|
@@ -63,7 +63,6 @@ function createSealData(_crypto) {
|
|
|
63
63
|
);
|
|
64
64
|
const passwordForSeal = {
|
|
65
65
|
id: mostRecentPasswordId.toString(),
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
67
66
|
secret: passwordsMap[mostRecentPasswordId]
|
|
68
67
|
};
|
|
69
68
|
const seal$1 = await seal(_crypto, data, passwordForSeal, {
|
|
@@ -99,15 +98,13 @@ function createUnsealData(_crypto) {
|
|
|
99
98
|
}
|
|
100
99
|
};
|
|
101
100
|
}
|
|
102
|
-
function
|
|
101
|
+
function getSessionConfig(sessionOptions) {
|
|
103
102
|
const options = {
|
|
104
103
|
...defaultOptions,
|
|
105
104
|
...sessionOptions,
|
|
106
|
-
...overrides,
|
|
107
105
|
cookieOptions: {
|
|
108
106
|
...defaultOptions.cookieOptions,
|
|
109
|
-
...sessionOptions.cookieOptions
|
|
110
|
-
...overrides?.cookieOptions
|
|
107
|
+
...sessionOptions.cookieOptions || {}
|
|
111
108
|
}
|
|
112
109
|
};
|
|
113
110
|
if (sessionOptions.cookieOptions && "maxAge" in sessionOptions.cookieOptions) {
|
|
@@ -119,7 +116,7 @@ function mergeOptions(sessionOptions, overrides) {
|
|
|
119
116
|
}
|
|
120
117
|
return options;
|
|
121
118
|
}
|
|
122
|
-
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(
|
|
119
|
+
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options).";
|
|
123
120
|
function createGetIronSession(sealData2, unsealData2) {
|
|
124
121
|
return getIronSession2;
|
|
125
122
|
async function getIronSession2(reqOrCookieStore, resOrsessionOptions, sessionOptions) {
|
|
@@ -140,7 +137,7 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
140
137
|
const req = reqOrCookieStore;
|
|
141
138
|
const res = resOrsessionOptions;
|
|
142
139
|
if (!sessionOptions) {
|
|
143
|
-
throw new Error(
|
|
140
|
+
throw new Error(badUsageMessage);
|
|
144
141
|
}
|
|
145
142
|
if (!sessionOptions.cookieName) {
|
|
146
143
|
throw new Error("iron-session: Bad usage. Missing cookie name.");
|
|
@@ -154,29 +151,33 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
154
151
|
"iron-session: Bad usage. Password must be at least 32 characters long."
|
|
155
152
|
);
|
|
156
153
|
}
|
|
157
|
-
|
|
158
|
-
const sealFromCookies = getCookie(req,
|
|
154
|
+
let sessionConfig = getSessionConfig(sessionOptions);
|
|
155
|
+
const sealFromCookies = getCookie(req, sessionConfig.cookieName);
|
|
159
156
|
const session = sealFromCookies ? await unsealData2(sealFromCookies, {
|
|
160
157
|
password: passwordsMap,
|
|
161
|
-
ttl:
|
|
158
|
+
ttl: sessionConfig.ttl
|
|
162
159
|
}) : {};
|
|
163
160
|
Object.defineProperties(session, {
|
|
161
|
+
updateConfig: {
|
|
162
|
+
value: function updateConfig(newSessionOptions) {
|
|
163
|
+
sessionConfig = getSessionConfig(newSessionOptions);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
164
166
|
save: {
|
|
165
|
-
value: async function save(
|
|
167
|
+
value: async function save() {
|
|
166
168
|
if ("headersSent" in res && res.headersSent) {
|
|
167
169
|
throw new Error(
|
|
168
170
|
"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()"
|
|
169
171
|
);
|
|
170
172
|
}
|
|
171
|
-
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
|
|
172
173
|
const seal = await sealData2(session, {
|
|
173
174
|
password: passwordsMap,
|
|
174
|
-
ttl:
|
|
175
|
+
ttl: sessionConfig.ttl
|
|
175
176
|
});
|
|
176
177
|
const cookieValue = serialize(
|
|
177
|
-
|
|
178
|
+
sessionConfig.cookieName,
|
|
178
179
|
seal,
|
|
179
|
-
|
|
180
|
+
sessionConfig.cookieOptions
|
|
180
181
|
);
|
|
181
182
|
if (cookieValue.length > 4096) {
|
|
182
183
|
throw new Error(
|
|
@@ -187,13 +188,12 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
187
188
|
}
|
|
188
189
|
},
|
|
189
190
|
destroy: {
|
|
190
|
-
value:
|
|
191
|
+
value: function destroy() {
|
|
191
192
|
Object.keys(session).forEach((key) => {
|
|
192
193
|
delete session[key];
|
|
193
194
|
});
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
...mergedOptions.cookieOptions,
|
|
195
|
+
const cookieValue = serialize(sessionConfig.cookieName, "", {
|
|
196
|
+
...sessionConfig.cookieOptions,
|
|
197
197
|
maxAge: 0
|
|
198
198
|
});
|
|
199
199
|
setCookie(res, cookieValue);
|
|
@@ -204,9 +204,6 @@ function createGetIronSession(sealData2, unsealData2) {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
async function getIronSessionFromCookieStore(cookieStore, sessionOptions, sealData2, unsealData2) {
|
|
207
|
-
if (!sessionOptions) {
|
|
208
|
-
throw new Error("iron-session: Bad usage. Missing options.");
|
|
209
|
-
}
|
|
210
207
|
if (!sessionOptions.cookieName) {
|
|
211
208
|
throw new Error("iron-session: Bad usage. Missing cookie name.");
|
|
212
209
|
}
|
|
@@ -219,44 +216,42 @@ async function getIronSessionFromCookieStore(cookieStore, sessionOptions, sealDa
|
|
|
219
216
|
"iron-session: Bad usage. Password must be at least 32 characters long."
|
|
220
217
|
);
|
|
221
218
|
}
|
|
222
|
-
const
|
|
219
|
+
const sessionConfig = getSessionConfig(sessionOptions);
|
|
223
220
|
const sealFromCookies = getServerActionCookie(
|
|
224
|
-
|
|
221
|
+
sessionConfig.cookieName,
|
|
225
222
|
cookieStore
|
|
226
223
|
);
|
|
227
224
|
const session = sealFromCookies ? await unsealData2(sealFromCookies, {
|
|
228
225
|
password: passwordsMap,
|
|
229
|
-
ttl:
|
|
226
|
+
ttl: sessionConfig.ttl
|
|
230
227
|
}) : {};
|
|
231
228
|
Object.defineProperties(session, {
|
|
232
229
|
save: {
|
|
233
|
-
value: async function save(
|
|
234
|
-
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
|
|
230
|
+
value: async function save() {
|
|
235
231
|
const seal = await sealData2(session, {
|
|
236
232
|
password: passwordsMap,
|
|
237
|
-
ttl:
|
|
233
|
+
ttl: sessionConfig.ttl
|
|
238
234
|
});
|
|
239
|
-
const cookieLength =
|
|
235
|
+
const cookieLength = sessionConfig.cookieName.length + seal.length + JSON.stringify(sessionConfig.cookieOptions).length;
|
|
240
236
|
if (cookieLength > 4096) {
|
|
241
237
|
throw new Error(
|
|
242
238
|
`iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`
|
|
243
239
|
);
|
|
244
240
|
}
|
|
245
241
|
cookieStore.set(
|
|
246
|
-
|
|
242
|
+
sessionConfig.cookieName,
|
|
247
243
|
seal,
|
|
248
|
-
|
|
244
|
+
sessionConfig.cookieOptions
|
|
249
245
|
);
|
|
250
246
|
}
|
|
251
247
|
},
|
|
252
248
|
destroy: {
|
|
253
|
-
value:
|
|
249
|
+
value: function destroy() {
|
|
254
250
|
Object.keys(session).forEach((key) => {
|
|
255
251
|
delete session[key];
|
|
256
252
|
});
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
cookieStore.set(mergedOptions.cookieName, "", cookieOptions);
|
|
253
|
+
const cookieOptions = { ...sessionConfig.cookieOptions, maxAge: 0 };
|
|
254
|
+
cookieStore.set(sessionConfig.cookieName, "", cookieOptions);
|
|
260
255
|
}
|
|
261
256
|
}
|
|
262
257
|
});
|
|
@@ -266,6 +261,6 @@ var sealData = createSealData(crypto);
|
|
|
266
261
|
var unsealData = createUnsealData(crypto);
|
|
267
262
|
var getIronSession = createGetIronSession(sealData, unsealData);
|
|
268
263
|
|
|
269
|
-
export {
|
|
264
|
+
export { getIronSession, sealData, unsealData };
|
|
270
265
|
//# sourceMappingURL=out.js.map
|
|
271
266
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"names":["sealData","unsealData","getIronSession"],"mappings":";AACA,SAAS,OAAO,iBAA8C;AAC9D;AAAA,EACE,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,OACL;AA8GP,IAAM,mBAAmB;AACzB,IAAM,wBAAwB,KAAK,KAAK;AAIxC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAEzB,IAAM,iBAA+C;AAAA,EACnD,KAAK;AAAA,EACL,eAAe,EAAE,UAAU,MAAM,QAAQ,MAAM,UAAU,OAAO,MAAM,IAAI;AAC5E;AAEA,SAAS,6BAA6B,UAAkC;AACtE,SAAO,OAAO,aAAa,WAAW,EAAE,GAAG,SAAS,IAAI;AAC1D;AAEA,SAAS,UAAU,MAGjB;AACA,QAAM,CAAC,oBAAoB,oBAAoB,IAC7C,KAAK,MAAM,gBAAgB;AAC7B,QAAM,eACJ,wBAAwB,OAAO,OAAO,SAAS,sBAAsB,EAAE;AAGzE,SAAO,EAAE,oBAAyC,aAAa;AACjE;AAEA,SAAS,oBAAoB,KAAqB;AAChD,MAAI,QAAQ,GAAG;AAKb,WAAO;AAAA,EACT;AAIA,SAAO,MAAM;AACf;AAEA,SAAS,UAAU,KAAkB,YAA4B;AAC/D,SACE;AAAA,KACG,aAAa,OAAO,OAAO,IAAI,QAAQ,QAAQ,aAC5C,IAAI,QAAQ,IAAI,QAAQ,IACvB,IAAwB,QAAQ,WAAW;AAAA,EAClD,EAAE,UAAU,KAAK;AAErB;AAEA,SAAS,sBACP,YACA,eACQ;AACR,QAAM,eAAe,cAAc,IAAI,UAAU;AACjD,QAAM,SAAS,cAAc;AAC7B,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,UAAU,KAAmB,aAA2B;AAC/D,MAAI,aAAa,OAAO,OAAO,IAAI,QAAQ,WAAW,YAAY;AAChE,QAAI,QAAQ,OAAO,cAAc,WAAW;AAC5C;AAAA,EACF;AACA,MAAI,oBAAqB,IAAuB,UAAU,YAAY,KAAK,CAAC;AAC5E,MAAI,CAAC,MAAM,QAAQ,iBAAiB,GAAG;AACrC,wBAAoB,CAAC,kBAAkB,SAAS,CAAC;AAAA,EACnD;AACA,EAAC,IAAuB,UAAU,cAAc;AAAA,IAC9C,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAEO,SAAS,eAAe,SAAiB;AAC9C,SAAO,eAAeA,UACpB,MACA;AAAA,IACE;AAAA,IACA,MAAM;AAAA,EACR,GACiB;AACjB,UAAM,eAAe,6BAA6B,QAAQ;AAE1D,UAAM,uBAAuB,KAAK;AAAA,MAChC,GAAG,OAAO,KAAK,YAAY,EAAE,IAAI,MAAM;AAAA,IACzC;AACA,UAAM,kBAAkB;AAAA,MACtB,IAAI,qBAAqB,SAAS;AAAA;AAAA,MAElC,QAAQ,aAAa,oBAAoB;AAAA,IAC3C;AAEA,UAAM,OAAO,MAAM,SAAS,SAAS,MAAM,iBAAiB;AAAA,MAC1D,GAAG;AAAA,MACH,KAAK,MAAM;AAAA,IACb,CAAC;AAED,WAAO,GAAG,IAAI,GAAG,gBAAgB,GAAG,mBAAmB;AAAA,EACzD;AACF;AAEO,SAAS,iBAAiB,SAAiB;AAChD,SAAO,eAAeC,YACpB,MACA;AAAA,IACE;AAAA,IACA,MAAM;AAAA,EACR,GACY;AACZ,UAAM,eAAe,6BAA6B,QAAQ;AAC1D,UAAM,EAAE,oBAAoB,aAAa,IAAI,UAAU,IAAI;AAE3D,QAAI;AACF,YAAM,OACH,MAAM,WAAW,SAAS,oBAAoB,cAAc;AAAA,QAC3D,GAAG;AAAA,QACH,KAAK,MAAM;AAAA,MACb,CAAC,KAA2B,CAAC;AAE/B,UAAI,iBAAiB,GAAG;AACtB,eAAO;AAAA,MACT;AAGA,aAAO,EAAE,GAAG,KAAK,WAAW;AAAA,IAC9B,SAAS,OAAO;AACd,UACE,iBAAiB,SACjB,4FAA4F;AAAA,QAC1F,MAAM;AAAA,MACR,GACA;AAKA,eAAO,CAAC;AAAA,MACV;AAGA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,aACP,gBACA,WAC0B;AAC1B,QAAM,UAAoC;AAAA,IACxC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,eAAe;AAAA,MACb,GAAG,eAAe;AAAA,MAClB,GAAG,eAAe;AAAA,MAClB,GAAG,WAAW;AAAA,IAChB;AAAA,EACF;AAEA,MACE,eAAe,iBACf,YAAY,eAAe,eAC3B;AACA,QAAI,eAAe,cAAc,WAAW,QAAW;AAErD,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF,OAAO;AACL,YAAQ,cAAc,SAAS,oBAAoB,QAAQ,GAAG;AAAA,EAChE;AAEA,SAAO;AACT;AAEA,IAAM,kBACJ;AAEK,SAAS,qBACdD,WACAC,aACA;AACA,SAAOC;AAWP,iBAAeA,gBACb,kBACA,qBACA,gBACyB;AACzB,QAAI,CAAC,kBAAkB;AACrB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,qBAAqB;AACxB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACAF;AAAA,QACAC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM;AACZ,UAAM,MAAM;AAEZ,QAAI,CAAC,gBAAgB;AACnB,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAEA,QAAI,CAAC,eAAe,YAAY;AAC9B,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,QAAI,CAAC,eAAe,UAAU;AAC5B,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,eAAe,6BAA6B,eAAe,QAAQ;AAEzE,QAAI,OAAO,OAAO,YAAY,EAAE,KAAK,CAAC,aAAa,SAAS,SAAS,EAAE,GAAG;AACxE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,cAAc;AAC3C,UAAM,kBAAkB,UAAU,KAAK,QAAQ,UAAU;AACzD,UAAM,UAAU,kBACZ,MAAMA,YAAc,iBAAiB;AAAA,MACnC,UAAU;AAAA,MACV,KAAK,QAAQ;AAAA,IACf,CAAC,IACA,CAAC;AAEN,WAAO,iBAAiB,SAAS;AAAA,MAC/B,MAAM;AAAA,QACJ,OAAO,eAAe,KAAK,aAAkC;AAC3D,cAAI,iBAAiB,OAAO,IAAI,aAAa;AAC3C,kBAAM,IAAI;AAAA,cACR;AAAA,YACF;AAAA,UACF;AAEA,gBAAM,gBAAgB,aAAa,gBAAgB,WAAW;AAC9D,gBAAM,OAAO,MAAMD,UAAS,SAAS;AAAA,YACnC,UAAU;AAAA,YACV,KAAK,cAAc;AAAA,UACrB,CAAC;AACD,gBAAM,cAAc;AAAA,YAClB,cAAc;AAAA,YACd;AAAA,YACA,cAAc;AAAA,UAChB;AAEA,cAAI,YAAY,SAAS,MAAM;AAC7B,kBAAM,IAAI;AAAA,cACR,2CAA2C,YAAY,MAAM;AAAA,YAC/D;AAAA,UACF;AAEA,oBAAU,KAAK,WAAW;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,SAAS;AAAA,QACP,OAAO,eAAe,QAAQ,gBAAqC;AACjE,iBAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,mBAAQ,QAAoC,GAAG;AAAA,UACjD,CAAC;AAED,gBAAM,gBAAgB,aAAa,gBAAgB,cAAc;AACjE,gBAAM,cAAc,UAAU,cAAc,YAAY,IAAI;AAAA,YAC1D,GAAG,cAAc;AAAA,YACjB,QAAQ;AAAA,UACV,CAAC;AAED,oBAAU,KAAK,WAAW;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;AAEA,eAAe,8BACb,aACA,gBACAA,WACAC,aACyB;AACzB,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,MAAI,CAAC,eAAe,YAAY;AAC9B,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,MAAI,CAAC,eAAe,UAAU;AAC5B,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,QAAM,eAAe,6BAA6B,eAAe,QAAQ;AAEzE,MAAI,OAAO,OAAO,YAAY,EAAE,KAAK,CAAC,aAAa,SAAS,SAAS,EAAE,GAAG;AACxE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,aAAa,cAAc;AAC3C,QAAM,kBAAkB;AAAA,IACtB,QAAQ;AAAA,IACR;AAAA,EACF;AACA,QAAM,UAAU,kBACZ,MAAMA,YAAc,iBAAiB;AAAA,IACnC,UAAU;AAAA,IACV,KAAK,QAAQ;AAAA,EACf,CAAC,IACA,CAAC;AAEN,SAAO,iBAAiB,SAAS;AAAA,IAC/B,MAAM;AAAA,MACJ,OAAO,eAAe,KAAK,aAAkC;AAC3D,cAAM,gBAAgB,aAAa,gBAAgB,WAAW;AAC9D,cAAM,OAAO,MAAMD,UAAS,SAAS;AAAA,UACnC,UAAU;AAAA,UACV,KAAK,cAAc;AAAA,QACrB,CAAC;AAED,cAAM,eACJ,cAAc,WAAW,SACzB,KAAK,SACL,KAAK,UAAU,cAAc,aAAa,EAAE;AAE9C,YAAI,eAAe,MAAM;AACvB,gBAAM,IAAI;AAAA,YACR,2CAA2C,YAAY;AAAA,UACzD;AAAA,QACF;AAEA,oBAAY;AAAA,UACV,cAAc;AAAA,UACd;AAAA,UACA,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,MACP,OAAO,eAAe,QAAQ,gBAAoC;AAChE,eAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,iBAAQ,QAAoC,GAAG;AAAA,QACjD,CAAC;AACD,cAAM,gBAAgB,aAAa,gBAAgB,cAAc;AACjE,cAAM,gBAAgB,EAAE,GAAG,cAAc,eAAe,QAAQ,EAAE;AAElE,oBAAY,IAAI,cAAc,YAAY,IAAI,aAAa;AAAA,MAC7D;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AChfA,YAAY,YAAY;AAGjB,IAAM,WAAW,eAAe,MAAM;AACtC,IAAM,aAAa,iBAAiB,MAAM;AAC1C,IAAM,iBAAiB,qBAAqB,UAAU,UAAU","sourcesContent":["import type { IncomingMessage, ServerResponse } from \"http\";\nimport { parse, serialize, type CookieSerializeOptions } from \"cookie\";\nimport {\n defaults as ironDefaults,\n seal as ironSeal,\n unseal as ironUnseal,\n} from \"iron-webcrypto\";\n\ntype PasswordsMap = Record<string, string>;\ntype Password = PasswordsMap | string;\ntype RequestType = IncomingMessage | Request;\ntype ResponseType = Response | ServerResponse;\n\n/**\n * {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}\n * as specified by W3C.\n */\ninterface CookieListItem\n extends Pick<\n CookieSerializeOptions,\n \"domain\" | \"path\" | \"sameSite\" | \"secure\"\n > {\n /** A string with the name of a cookie. */\n name: string;\n /** A string containing the value of the cookie. */\n value: string;\n /** A number of milliseconds or Date interface containing the expires of the cookie. */\n expires?: CookieSerializeOptions[\"expires\"] | number;\n}\n\n/**\n * Superset of {@link CookieListItem} extending it with\n * the `httpOnly`, `maxAge` and `priority` properties.\n */\ntype ResponseCookie = CookieListItem &\n Pick<CookieSerializeOptions, \"httpOnly\" | \"maxAge\" | \"priority\">;\n\n/**\n * The high-level type definition of the .get() and .set() methods\n * of { cookies() } from \"next/headers\"\n */\nexport interface CookieStore {\n get: (name: string) => { name: string; value: string } | undefined;\n set: {\n (name: string, value: string, cookie?: Partial<ResponseCookie>): void;\n (options: ResponseCookie): void;\n };\n}\n\n/**\n * Set-Cookie Attributes do not include `encode`. We omit this from our `cookieOptions` type.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie\n * @see https://developer.chrome.com/docs/devtools/application/cookies/\n */\ntype CookieOptions = Omit<CookieSerializeOptions, \"encode\">;\n\nexport interface SessionOptions {\n /**\n * The cookie name that will be used inside the browser. Make sure it's unique\n * given your application.\n *\n * @example 'vercel-session'\n */\n cookieName: string;\n\n /**\n * The password(s) that will be used to encrypt the cookie. Can either be a string\n * or an object.\n *\n * When you provide multiple passwords then all of them will be used to decrypt\n * the cookie. But only the most recent (`= highest key`, `2` in the example)\n * password will be used to encrypt the cookie. This allows password rotation.\n *\n * @example { 1: 'password-1', 2: 'password-2' }\n */\n password: Password;\n\n /**\n * The time (in seconds) that the session will be valid for. Also sets the\n * `max-age` attribute of the cookie automatically (`= ttl - 60s`, so that the\n * cookie always expire before the session).\n *\n * `ttl = 0` means no expiration.\n *\n * @default 1209600\n */\n ttl?: number;\n\n /**\n * The options that will be passed to the cookie library.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser\n * is closed) then you need to pass `cookieOptions: { maxAge: undefined }`\n *\n * @see https://github.com/jshttp/cookie#options-1\n */\n cookieOptions?: CookieOptions;\n}\n\ntype OverridableOptions = Pick<SessionOptions, \"cookieOptions\" | \"ttl\">;\n\nexport type IronSession<T> = T & {\n /**\n * Destroys the session data and removes the cookie.\n */\n readonly destroy: (destroyOptions?: OverridableOptions) => Promise<void>;\n\n /**\n * Encrypts the session data and sets the cookie.\n */\n readonly save: (saveOptions?: OverridableOptions) => Promise<void>;\n};\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/module/iron/api/?v=7.0.1#options\nconst timestampSkewSec = 60;\nconst fourteenDaysInSeconds = 14 * 24 * 3600;\n\n// We store a token major version to handle data format changes so that the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: Required<OverridableOptions> = {\n ttl: fourteenDaysInSeconds,\n cookieOptions: { httpOnly: true, secure: true, sameSite: \"lax\", path: \"/\" },\n};\n\nfunction normalizeStringPasswordToMap(password: Password): PasswordsMap {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n const tokenVersion =\n tokenVersionAsString == null ? null : parseInt(tokenVersionAsString, 10);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { sealWithoutVersion: sealWithoutVersion!, tokenVersion };\n}\n\nfunction computeCookieMaxAge(ttl: number): number {\n if (ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n return 2147483647;\n }\n\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds between server and clients.\n return ttl - timestampSkewSec;\n}\n\nfunction getCookie(req: RequestType, cookieName: string): string {\n return (\n parse(\n (\"headers\" in req && typeof req.headers.get === \"function\"\n ? req.headers.get(\"cookie\")\n : (req as IncomingMessage).headers.cookie) ?? \"\",\n )[cookieName] ?? \"\"\n );\n}\n\nfunction getServerActionCookie(\n cookieName: string,\n cookieHandler: CookieStore,\n): string {\n const cookieObject = cookieHandler.get(cookieName);\n const cookie = cookieObject?.value;\n if (typeof cookie === \"string\") {\n return cookie;\n }\n return \"\";\n}\n\nfunction setCookie(res: ResponseType, cookieValue: string): void {\n if (\"headers\" in res && typeof res.headers.append === \"function\") {\n res.headers.append(\"set-cookie\", cookieValue);\n return;\n }\n let existingSetCookie = (res as ServerResponse).getHeader(\"set-cookie\") ?? [];\n if (!Array.isArray(existingSetCookie)) {\n existingSetCookie = [existingSetCookie.toString()];\n }\n (res as ServerResponse).setHeader(\"set-cookie\", [\n ...existingSetCookie,\n cookieValue,\n ]);\n}\n\nexport function createSealData(_crypto: Crypto) {\n return async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<string> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsMap).map(Number),\n );\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n secret: passwordsMap[mostRecentPasswordId]!,\n };\n\n const seal = await ironSeal(_crypto, data, passwordForSeal, {\n ...ironDefaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n };\n}\n\nexport function createUnsealData(_crypto: Crypto) {\n return async function unsealData<T>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<T> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data =\n (await ironUnseal(_crypto, sealWithoutVersion, passwordsMap, {\n ...ironDefaults,\n ttl: ttl * 1000,\n })) /* c8 ignore next */ ?? {};\n\n if (tokenVersion === 2) {\n return data as T;\n }\n\n // @ts-expect-error `persistent` does not exist on newer tokens\n return { ...data.persistent } as T;\n } catch (error) {\n if (\n error instanceof Error &&\n /^(Expired seal|Bad hmac value|Cannot find password|Incorrect number of sealed components)/.test(\n error.message,\n )\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are badly rotated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return {} as T;\n }\n\n /* c8 ignore next 2 */\n throw error;\n }\n };\n}\n\nfunction mergeOptions(\n sessionOptions: SessionOptions,\n overrides?: OverridableOptions,\n): Required<SessionOptions> {\n const options: Required<SessionOptions> = {\n ...defaultOptions,\n ...sessionOptions,\n ...overrides,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...sessionOptions.cookieOptions,\n ...overrides?.cookieOptions,\n },\n };\n\n if (\n sessionOptions.cookieOptions &&\n \"maxAge\" in sessionOptions.cookieOptions\n ) {\n if (sessionOptions.cookieOptions.maxAge === undefined) {\n // session cookies, do not set maxAge, consider token as infinite\n options.ttl = 0;\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n return options;\n}\n\nconst badUsageMessage =\n \"iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookies, options).\";\n\nexport function createGetIronSession(\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n) {\n return getIronSession;\n\n async function getIronSession<T extends object>(\n cookies: CookieStore,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n req: RequestType,\n res: ResponseType,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n reqOrCookieStore: RequestType | CookieStore,\n resOrsessionOptions: ResponseType | SessionOptions,\n sessionOptions?: SessionOptions,\n ): Promise<IronSession<T>> {\n if (!reqOrCookieStore) {\n throw new Error(badUsageMessage);\n }\n\n if (!resOrsessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions) {\n return getIronSessionFromCookieStore<T>(\n reqOrCookieStore as CookieStore,\n resOrsessionOptions as SessionOptions,\n sealData,\n unsealData,\n );\n }\n\n const req = reqOrCookieStore as RequestType;\n const res = resOrsessionOptions as ResponseType;\n\n if (!sessionOptions) {\n throw new Error(\"iron-session: Bad usage. Missing options.\");\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const options = mergeOptions(sessionOptions);\n const sealFromCookies = getCookie(req, options.cookieName);\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: options.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save(saveOptions?: OverridableOptions) {\n if (\"headersSent\" in res && res.headersSent) {\n throw new Error(\n \"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()\",\n );\n }\n\n const mergedOptions = mergeOptions(sessionOptions, saveOptions);\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: mergedOptions.ttl,\n });\n const cookieValue = serialize(\n mergedOptions.cookieName,\n seal,\n mergedOptions.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieValue.length} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n setCookie(res, cookieValue);\n },\n },\n\n destroy: {\n value: async function destroy(destroyOptions?: OverridableOptions) {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n\n const mergedOptions = mergeOptions(sessionOptions, destroyOptions);\n const cookieValue = serialize(mergedOptions.cookieName, \"\", {\n ...mergedOptions.cookieOptions,\n maxAge: 0,\n });\n\n setCookie(res, cookieValue);\n },\n },\n });\n\n return session as IronSession<T>;\n }\n}\n\nasync function getIronSessionFromCookieStore<T extends object>(\n cookieStore: CookieStore,\n sessionOptions: SessionOptions,\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n): Promise<IronSession<T>> {\n if (!sessionOptions) {\n throw new Error(\"iron-session: Bad usage. Missing options.\");\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const options = mergeOptions(sessionOptions);\n const sealFromCookies = getServerActionCookie(\n options.cookieName,\n cookieStore,\n );\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: options.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save(saveOptions?: OverridableOptions) {\n const mergedOptions = mergeOptions(sessionOptions, saveOptions);\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: mergedOptions.ttl,\n });\n\n const cookieLength =\n mergedOptions.cookieName.length +\n seal.length +\n JSON.stringify(mergedOptions.cookieOptions).length;\n\n if (cookieLength > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n cookieStore.set(\n mergedOptions.cookieName,\n seal,\n mergedOptions.cookieOptions,\n );\n },\n },\n\n destroy: {\n value: async function destroy(destroyOptions: OverridableOptions) {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n const mergedOptions = mergeOptions(sessionOptions, destroyOptions);\n const cookieOptions = { ...mergedOptions.cookieOptions, maxAge: 0 };\n\n cookieStore.set(mergedOptions.cookieName, \"\", cookieOptions);\n },\n },\n });\n\n return session as IronSession<T>;\n}\n","import {\n createGetIronSession,\n createSealData,\n createUnsealData,\n} from \"./core.js\";\n\nimport * as crypto from \"uncrypto\";\n\nexport * from \"./core.js\";\nexport const sealData = createSealData(crypto);\nexport const unsealData = createUnsealData(crypto);\nexport const getIronSession = createGetIronSession(sealData, unsealData);\n// export const getServerActionIronSession = createGetServerActionIronSession(\n// sealData,\n// unsealData,\n// );\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"names":["sealData","unsealData","getIronSession"],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from \"http\";\nimport { parse, serialize, type CookieSerializeOptions } from \"cookie\";\nimport {\n defaults as ironDefaults,\n seal as ironSeal,\n unseal as ironUnseal,\n} from \"iron-webcrypto\";\n\ntype PasswordsMap = Record<string, string>;\ntype Password = PasswordsMap | string;\ntype RequestType = IncomingMessage | Request;\ntype ResponseType = Response | ServerResponse;\n\n/**\n * {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}\n * as specified by W3C.\n */\ninterface CookieListItem\n extends Pick<\n CookieSerializeOptions,\n \"domain\" | \"path\" | \"sameSite\" | \"secure\"\n > {\n /** A string with the name of a cookie. */\n name: string;\n /** A string containing the value of the cookie. */\n value: string;\n /** A number of milliseconds or Date interface containing the expires of the cookie. */\n expires?: CookieSerializeOptions[\"expires\"] | number;\n}\n\n/**\n * Superset of {@link CookieListItem} extending it with\n * the `httpOnly`, `maxAge` and `priority` properties.\n */\ntype ResponseCookie = CookieListItem &\n Pick<CookieSerializeOptions, \"httpOnly\" | \"maxAge\" | \"priority\">;\n\n/**\n * The high-level type definition of the .get() and .set() methods\n * of { cookies() } from \"next/headers\"\n */\nexport interface CookieStore {\n get: (name: string) => { name: string; value: string } | undefined;\n set: {\n (name: string, value: string, cookie?: Partial<ResponseCookie>): void;\n (options: ResponseCookie): void;\n };\n}\n\n/**\n * Set-Cookie Attributes do not include `encode`. We omit this from our `cookieOptions` type.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie\n * @see https://developer.chrome.com/docs/devtools/application/cookies/\n */\ntype CookieOptions = Omit<CookieSerializeOptions, \"encode\">;\n\nexport interface SessionOptions {\n /**\n * The cookie name that will be used inside the browser. Make sure it's unique\n * given your application.\n *\n * @example 'vercel-session'\n */\n cookieName: string;\n\n /**\n * The password(s) that will be used to encrypt the cookie. Can either be a string\n * or an object.\n *\n * When you provide multiple passwords then all of them will be used to decrypt\n * the cookie. But only the most recent (`= highest key`, `2` in the example)\n * password will be used to encrypt the cookie. This allows password rotation.\n *\n * @example { 1: 'password-1', 2: 'password-2' }\n */\n password: Password;\n\n /**\n * The time (in seconds) that the session will be valid for. Also sets the\n * `max-age` attribute of the cookie automatically (`= ttl - 60s`, so that the\n * cookie always expire before the session).\n *\n * `ttl = 0` means no expiration.\n *\n * @default 1209600\n */\n ttl?: number;\n\n /**\n * The options that will be passed to the cookie library.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser\n * is closed) then you need to pass `cookieOptions: { maxAge: undefined }`\n *\n * @see https://github.com/jshttp/cookie#options-1\n */\n cookieOptions?: CookieOptions;\n}\n\nexport type IronSession<T> = T & {\n /**\n * Encrypts the session data and sets the cookie.\n */\n readonly save: () => Promise<void>;\n\n /**\n * Destroys the session data and removes the cookie.\n */\n readonly destroy: () => Promise<void>;\n\n /**\n * Update the session configuration. You still need to call save() to send the new cookie.\n */\n readonly updateConfig: (newSessionOptions: SessionOptions) => void;\n};\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/module/iron/api/?v=7.0.1#options\nconst timestampSkewSec = 60;\nconst fourteenDaysInSeconds = 14 * 24 * 3600;\n\n// We store a token major version to handle data format changes so that the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: Required<Pick<SessionOptions, \"ttl\" | \"cookieOptions\">> =\n {\n ttl: fourteenDaysInSeconds,\n cookieOptions: { httpOnly: true, secure: true, sameSite: \"lax\", path: \"/\" },\n };\n\nfunction normalizeStringPasswordToMap(password: Password): PasswordsMap {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n const tokenVersion =\n tokenVersionAsString == null ? null : parseInt(tokenVersionAsString, 10);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { sealWithoutVersion: sealWithoutVersion!, tokenVersion };\n}\n\nfunction computeCookieMaxAge(ttl: number): number {\n if (ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n return 2147483647;\n }\n\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds between server and clients.\n return ttl - timestampSkewSec;\n}\n\nfunction getCookie(req: RequestType, cookieName: string): string {\n return (\n parse(\n (\"headers\" in req && typeof req.headers.get === \"function\"\n ? req.headers.get(\"cookie\")\n : (req as IncomingMessage).headers.cookie) ?? \"\",\n )[cookieName] ?? \"\"\n );\n}\n\nfunction getServerActionCookie(\n cookieName: string,\n cookieHandler: CookieStore,\n): string {\n const cookieObject = cookieHandler.get(cookieName);\n const cookie = cookieObject?.value;\n if (typeof cookie === \"string\") {\n return cookie;\n }\n return \"\";\n}\n\nfunction setCookie(res: ResponseType, cookieValue: string): void {\n if (\"headers\" in res && typeof res.headers.append === \"function\") {\n res.headers.append(\"set-cookie\", cookieValue);\n return;\n }\n let existingSetCookie = (res as ServerResponse).getHeader(\"set-cookie\") ?? [];\n if (!Array.isArray(existingSetCookie)) {\n existingSetCookie = [existingSetCookie.toString()];\n }\n (res as ServerResponse).setHeader(\"set-cookie\", [\n ...existingSetCookie,\n cookieValue,\n ]);\n}\n\nexport function createSealData(_crypto: Crypto) {\n return async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<string> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsMap).map(Number),\n );\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n secret: passwordsMap[mostRecentPasswordId]!,\n };\n\n const seal = await ironSeal(_crypto, data, passwordForSeal, {\n ...ironDefaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n };\n}\n\nexport function createUnsealData(_crypto: Crypto) {\n return async function unsealData<T>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: Password; ttl?: number },\n ): Promise<T> {\n const passwordsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data =\n (await ironUnseal(_crypto, sealWithoutVersion, passwordsMap, {\n ...ironDefaults,\n ttl: ttl * 1000,\n })) ?? {};\n\n if (tokenVersion === 2) {\n return data as T;\n }\n\n // @ts-expect-error `persistent` does not exist on newer tokens\n return { ...data.persistent } as T;\n } catch (error) {\n if (\n error instanceof Error &&\n /^(Expired seal|Bad hmac value|Cannot find password|Incorrect number of sealed components)/.test(\n error.message,\n )\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are badly rotated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return {} as T;\n }\n\n throw error;\n }\n };\n}\n\nfunction getSessionConfig(\n sessionOptions: SessionOptions,\n): Required<SessionOptions> {\n const options = {\n ...defaultOptions,\n ...sessionOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(sessionOptions.cookieOptions || {}),\n },\n };\n\n if (\n sessionOptions.cookieOptions &&\n \"maxAge\" in sessionOptions.cookieOptions\n ) {\n if (sessionOptions.cookieOptions.maxAge === undefined) {\n // session cookies, do not set maxAge, consider token as infinite\n options.ttl = 0;\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n return options;\n}\n\nconst badUsageMessage =\n \"iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options).\";\n\nexport function createGetIronSession(\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n) {\n return getIronSession;\n\n async function getIronSession<T extends object>(\n cookies: CookieStore,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n req: RequestType,\n res: ResponseType,\n sessionOptions: SessionOptions,\n ): Promise<IronSession<T>>;\n async function getIronSession<T extends object>(\n reqOrCookieStore: RequestType | CookieStore,\n resOrsessionOptions: ResponseType | SessionOptions,\n sessionOptions?: SessionOptions,\n ): Promise<IronSession<T>> {\n if (!reqOrCookieStore) {\n throw new Error(badUsageMessage);\n }\n\n if (!resOrsessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions) {\n return getIronSessionFromCookieStore<T>(\n reqOrCookieStore as CookieStore,\n resOrsessionOptions as SessionOptions,\n sealData,\n unsealData,\n );\n }\n\n const req = reqOrCookieStore as RequestType;\n const res = resOrsessionOptions as ResponseType;\n\n if (!sessionOptions) {\n throw new Error(badUsageMessage);\n }\n\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n let sessionConfig = getSessionConfig(sessionOptions);\n\n const sealFromCookies = getCookie(req, sessionConfig.cookieName);\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n updateConfig: {\n value: function updateConfig(newSessionOptions: SessionOptions) {\n sessionConfig = getSessionConfig(newSessionOptions);\n },\n },\n save: {\n value: async function save() {\n if (\"headersSent\" in res && res.headersSent) {\n throw new Error(\n \"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()\",\n );\n }\n\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n });\n const cookieValue = serialize(\n sessionConfig.cookieName,\n seal,\n sessionConfig.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieValue.length} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n setCookie(res, cookieValue);\n },\n },\n\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n const cookieValue = serialize(sessionConfig.cookieName, \"\", {\n ...sessionConfig.cookieOptions,\n maxAge: 0,\n });\n\n setCookie(res, cookieValue);\n },\n },\n });\n\n return session as IronSession<T>;\n }\n}\n\nasync function getIronSessionFromCookieStore<T extends object>(\n cookieStore: CookieStore,\n sessionOptions: SessionOptions,\n sealData: ReturnType<typeof createSealData>,\n unsealData: ReturnType<typeof createUnsealData>,\n): Promise<IronSession<T>> {\n if (!sessionOptions.cookieName) {\n throw new Error(\"iron-session: Bad usage. Missing cookie name.\");\n }\n\n if (!sessionOptions.password) {\n throw new Error(\"iron-session: Bad usage. Missing password.\");\n }\n\n const passwordsMap = normalizeStringPasswordToMap(sessionOptions.password);\n\n if (Object.values(passwordsMap).some((password) => password.length < 32)) {\n throw new Error(\n \"iron-session: Bad usage. Password must be at least 32 characters long.\",\n );\n }\n\n const sessionConfig = getSessionConfig(sessionOptions);\n const sealFromCookies = getServerActionCookie(\n sessionConfig.cookieName,\n cookieStore,\n );\n const session = sealFromCookies\n ? await unsealData<T>(sealFromCookies, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n })\n : ({} as T);\n\n Object.defineProperties(session, {\n save: {\n value: async function save() {\n const seal = await sealData(session, {\n password: passwordsMap,\n ttl: sessionConfig.ttl,\n });\n\n const cookieLength =\n sessionConfig.cookieName.length +\n seal.length +\n JSON.stringify(sessionConfig.cookieOptions).length;\n\n if (cookieLength > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big (${cookieLength} bytes), browsers will refuse it. Try to remove some data.`,\n );\n }\n\n cookieStore.set(\n sessionConfig.cookieName,\n seal,\n sessionConfig.cookieOptions,\n );\n },\n },\n\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n delete (session as Record<string, unknown>)[key];\n });\n\n const cookieOptions = { ...sessionConfig.cookieOptions, maxAge: 0 };\n cookieStore.set(sessionConfig.cookieName, \"\", cookieOptions);\n },\n },\n });\n\n return session as IronSession<T>;\n}\n","import {\n createGetIronSession,\n createSealData,\n createUnsealData,\n} from \"./core.js\";\n\nimport * as crypto from \"uncrypto\";\n\nexport type { IronSession, SessionOptions } from \"./core.js\";\nexport const sealData = createSealData(crypto);\nexport const unsealData = createUnsealData(crypto);\nexport const getIronSession = createGetIronSession(sealData, unsealData);\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iron-session",
|
|
3
|
-
"version": "8.0.0
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Secure, stateless, and cookie-based session library for JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"session",
|
|
@@ -42,14 +42,13 @@
|
|
|
42
42
|
"uncrypto": "0.1.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@release-it/conventional-changelog": "8.0.1",
|
|
46
45
|
"@types/cookie": "0.5.4",
|
|
47
|
-
"@types/node": "
|
|
46
|
+
"@types/node": "18.18.10",
|
|
48
47
|
"@typescript-eslint/eslint-plugin": "6.11.0",
|
|
49
48
|
"@typescript-eslint/parser": "6.11.0",
|
|
50
49
|
"c8": "8.0.1",
|
|
51
50
|
"concurrently": "8.2.2",
|
|
52
|
-
"eslint": "8.
|
|
51
|
+
"eslint": "8.54.0",
|
|
53
52
|
"eslint-config-prettier": "9.0.0",
|
|
54
53
|
"eslint-import-resolver-node": "0.3.9",
|
|
55
54
|
"eslint-import-resolver-typescript": "3.6.1",
|
|
@@ -58,12 +57,11 @@
|
|
|
58
57
|
"prettier": "3.1.0",
|
|
59
58
|
"prettier-plugin-packagejson": "2.4.6",
|
|
60
59
|
"publint": "0.2.5",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"tsx": "4.1.2",
|
|
60
|
+
"tsup": "8.0.0",
|
|
61
|
+
"tsx": "4.1.4",
|
|
64
62
|
"typescript": "5.2.2"
|
|
65
63
|
},
|
|
66
|
-
"packageManager": "pnpm@8.10.
|
|
64
|
+
"packageManager": "pnpm@8.10.5",
|
|
67
65
|
"publishConfig": {
|
|
68
66
|
"access": "public",
|
|
69
67
|
"registry": "https://registry.npmjs.org"
|
|
@@ -72,7 +70,6 @@
|
|
|
72
70
|
"build": "tsup",
|
|
73
71
|
"dev": "pnpm build && concurrently \"pnpm build --watch\" \"pnpm --filter=next-example dev\" ",
|
|
74
72
|
"lint": "tsc --noEmit && tsc --noEmit -p examples/next/tsconfig.json && pnpm eslint . && publint",
|
|
75
|
-
"release": "pnpm lint",
|
|
76
73
|
"test": "c8 -r text -r lcov node --loader tsx --test src/*.test.ts && pnpm build",
|
|
77
74
|
"test:watch": "node --loader tsx --test --watch src/*.test.ts"
|
|
78
75
|
}
|