iron-session 6.0.4 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -12
- package/dist/index.js +3 -3
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +2 -2
- package/next/dist/index.d.ts +6 -3
- package/next/dist/index.js +14 -2
- package/next/dist/index.js.map +2 -2
- package/next/dist/index.mjs +14 -2
- package/next/dist/index.mjs.map +2 -2
- package/next/index.d.ts +6 -3
- package/next/index.js +14 -2
- package/next/index.js.map +2 -2
- package/next/index.mjs +14 -2
- package/next/index.mjs.map +2 -2
- package/next/index.test.ts +70 -1
- package/next/index.ts +42 -4
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# iron-session [](https://github.com/vvo/iron-session/blob/master/LICENSE) [](https://github.com/vvo/iron-session/actions)  [](http://npm-stat.com/charts.html?package=iron-session)
|
|
1
|
+
# iron-session [](https://github.com/vvo/iron-session/blob/master/LICENSE) [](https://github.com/vvo/iron-session/actions) [](https://www.npmjs.com/package/iron-session) [](http://npm-stat.com/charts.html?package=iron-session)
|
|
2
2
|
|
|
3
3
|
<p align="center"><b>⭐️ Featured in the <a href="https://nextjs.org/docs/authentication">Next.js documentation</a></b></p>
|
|
4
4
|
|
|
@@ -32,8 +32,8 @@ _Table of contents:_
|
|
|
32
32
|
- [Firebase usage](#firebase-usage)
|
|
33
33
|
- [API](#api)
|
|
34
34
|
- [ironOptions](#ironoptions)
|
|
35
|
-
- [Next.js: withIronSessionApiRoute(handler, ironOptions)](#nextjs-withironsessionapiroutehandler-ironoptions)
|
|
36
|
-
- [Next.js: withIronSessionSsr(handler, ironOptions)](#nextjs-
|
|
35
|
+
- [Next.js: withIronSessionApiRoute(handler, ironOptions)](#nextjs-withironsessionapiroutehandler-ironoptions--req-nextapirequest-res-nextapiresponse--ironoptions--promiseironoptions)
|
|
36
|
+
- [Next.js: withIronSessionSsr(handler, ironOptions)](#nextjs-withironsessionapiroutehandler-ironoptions--req-nextapirequest-res-nextapiresponse--ironoptions--promiseironoptions)
|
|
37
37
|
- [Express: ironSession(ironOptions)](#express-ironsessionironoptions)
|
|
38
38
|
- [session.save()](#sessionsave)
|
|
39
39
|
- [session.destroy()](#sessiondestroy)
|
|
@@ -186,13 +186,13 @@ import { ironOptions } from "lib/config";
|
|
|
186
186
|
export default withIronSessionApiRoute(loginRoute, ironOptions);
|
|
187
187
|
|
|
188
188
|
async function loginRoute(req, res) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
189
|
+
// get user from database then:
|
|
190
|
+
req.session.user = {
|
|
191
|
+
id: 230,
|
|
192
|
+
admin: true,
|
|
193
|
+
};
|
|
194
|
+
await req.session.save();
|
|
195
|
+
res.send({ ok: true });
|
|
196
196
|
}
|
|
197
197
|
```
|
|
198
198
|
|
|
@@ -417,6 +417,22 @@ export default async function sendEmailRoute(req, res) {
|
|
|
417
417
|
}
|
|
418
418
|
```
|
|
419
419
|
|
|
420
|
+
The default `ttl` for such seals is 14 days. To specify a `ttl`, provide it in seconds like so:
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
const fifteenMinutesInSeconds = 15 * 60;
|
|
424
|
+
|
|
425
|
+
const seal = await sealData(
|
|
426
|
+
{
|
|
427
|
+
userId: user.id,
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
password: "complex_password_at_least_32_characters_long",
|
|
431
|
+
ttl: fifteenMinutesInSeconds,
|
|
432
|
+
},
|
|
433
|
+
);
|
|
434
|
+
```
|
|
435
|
+
|
|
420
436
|
**Login the user automatically and redirect:**
|
|
421
437
|
|
|
422
438
|
```ts
|
|
@@ -570,7 +586,7 @@ Only two options are required: `password` and `cookieName`. Everything else is a
|
|
|
570
586
|
}
|
|
571
587
|
```
|
|
572
588
|
|
|
573
|
-
### Next.js: withIronSessionApiRoute(handler, ironOptions)
|
|
589
|
+
### Next.js: withIronSessionApiRoute(handler, ironOptions | (req: NextApiRequest, res: NextApiResponse) => IronOptions | Promise\<IronOptions\>)
|
|
574
590
|
|
|
575
591
|
Wraps a [Next.js API Route](https://nextjs.org/docs/api-routes/dynamic-api-routes) and adds a `session` object to the request.
|
|
576
592
|
|
|
@@ -590,9 +606,30 @@ export default withIronSessionApiRoute(
|
|
|
590
606
|
},
|
|
591
607
|
},
|
|
592
608
|
);
|
|
609
|
+
|
|
610
|
+
// You can also pass an async or sync function which takes request and response object and return IronSessionOptions
|
|
611
|
+
export default withIronSessionApiRoute(
|
|
612
|
+
function userRoute(req, res) {
|
|
613
|
+
res.send({ user: req.session.user });
|
|
614
|
+
},
|
|
615
|
+
(req, res) => {
|
|
616
|
+
// Infer max cookie from request
|
|
617
|
+
const maxCookieAge = getMaxCookieAge(req);
|
|
618
|
+
return {
|
|
619
|
+
cookieName: "myapp_cookiename",
|
|
620
|
+
password: "complex_password_at_least_32_characters_long",
|
|
621
|
+
// secure: true should be used in production (HTTPS) but can't be used in development (HTTP)
|
|
622
|
+
cookieOptions: {
|
|
623
|
+
// setMaxCookie age here.
|
|
624
|
+
maxCookieAge,
|
|
625
|
+
secure: process.env.NODE_ENV === "production",
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
},
|
|
629
|
+
);
|
|
593
630
|
```
|
|
594
631
|
|
|
595
|
-
### Next.js: withIronSessionSsr(handler, ironOptions)
|
|
632
|
+
### Next.js: withIronSessionSsr(handler, ironOptions | (req: IncomingMessage, res: ServerResponse) => IronOptions | Promise\<IronOptions\>)
|
|
596
633
|
|
|
597
634
|
Wraps a [Next.js getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) and adds a `session` object to the request of the context.
|
|
598
635
|
|
|
@@ -616,6 +653,27 @@ export const getServerSideProps = withIronSessionSsr(
|
|
|
616
653
|
},
|
|
617
654
|
},
|
|
618
655
|
);
|
|
656
|
+
|
|
657
|
+
// You can also pass an async or sync function which takes request and response object and return IronSessionOptions
|
|
658
|
+
export const getServerSideProps = withIronSessionSsr(
|
|
659
|
+
async function getServerSideProps({ req }) {
|
|
660
|
+
return {
|
|
661
|
+
props: {
|
|
662
|
+
user: req.session.user,
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
},
|
|
666
|
+
(req, res) => {
|
|
667
|
+
return {
|
|
668
|
+
cookieName: "myapp_cookiename",
|
|
669
|
+
password: "complex_password_at_least_32_characters_long",
|
|
670
|
+
// secure: true should be used in production (HTTPS) but can't be used in development (HTTP)
|
|
671
|
+
cookieOptions: {
|
|
672
|
+
secure: process.env.NODE_ENV === "production",
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
},
|
|
676
|
+
);
|
|
619
677
|
```
|
|
620
678
|
|
|
621
679
|
### Express: ironSession(ironOptions)
|
|
@@ -695,6 +753,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
|
695
753
|
<table>
|
|
696
754
|
<tr>
|
|
697
755
|
<td align="center"><a href="http://www.afterecon.com/"><img src="https://avatars.githubusercontent.com/u/5559355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Vandivier</b></sub></a><br /><a href="https://github.com/vvo/iron-session/commits?author=Vandivier" title="Code">💻</a> <a href="#ideas-Vandivier" title="Ideas, Planning, & Feedback">🤔</a> <a href="#example-Vandivier" title="Examples">💡</a></td>
|
|
756
|
+
<td align="center"><a href="https://searchableguy.com"><img src="https://avatars.githubusercontent.com/u/73341821?v=4?s=100" width="100px;" alt=""/><br /><sub><b>searchableguy</b></sub></a><br /><a href="https://github.com/vvo/iron-session/commits?author=searchableguy" title="Tests">⚠️</a> <a href="https://github.com/vvo/iron-session/commits?author=searchableguy" title="Documentation">📖</a> <a href="https://github.com/vvo/iron-session/commits?author=searchableguy" title="Code">💻</a></td>
|
|
698
757
|
</tr>
|
|
699
758
|
</table>
|
|
700
759
|
|
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
73
73
|
} else {
|
|
74
74
|
options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);
|
|
75
75
|
}
|
|
76
|
-
const sealFromCookies =
|
|
76
|
+
const sealFromCookies = import_cookie.default.parse(req.headers.cookie || "")[options.cookieName];
|
|
77
77
|
const session = sealFromCookies === void 0 ? {} : await unsealData(sealFromCookies, {
|
|
78
78
|
password: passwordsAsMap,
|
|
79
79
|
ttl: options.ttl
|
|
@@ -88,7 +88,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
88
88
|
password: passwordsAsMap,
|
|
89
89
|
ttl: options.ttl
|
|
90
90
|
});
|
|
91
|
-
const cookieValue =
|
|
91
|
+
const cookieValue = import_cookie.default.serialize(options.cookieName, seal, options.cookieOptions);
|
|
92
92
|
if (cookieValue.length > 4096) {
|
|
93
93
|
throw new Error(`iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`);
|
|
94
94
|
}
|
|
@@ -100,7 +100,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
100
100
|
Object.keys(session).forEach((key) => {
|
|
101
101
|
delete session[key];
|
|
102
102
|
});
|
|
103
|
-
const cookieValue =
|
|
103
|
+
const cookieValue = import_cookie.default.serialize(options.cookieName, "", {
|
|
104
104
|
...options.cookieOptions,
|
|
105
105
|
maxAge: 0
|
|
106
106
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import Iron from \"@hapi/iron\";\nimport type { CookieSerializeOptions } from \"cookie\";\nimport
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,
|
|
4
|
+
"sourcesContent": ["import Iron from \"@hapi/iron\";\nimport type { CookieSerializeOptions } from \"cookie\";\nimport cookie from \"cookie\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/family/iron/api/?v=6.0.0#options\nconst timestampSkewSec = 60;\n\ntype passwordsMap = { [id: string]: string };\ntype password = string | passwordsMap;\n\nconst fourteenDaysInSeconds = 15 * 24 * 3600;\n\n// We store a token major version to handle data format changes when any. So that when you upgrade the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: {\n ttl: number;\n cookieOptions: CookieSerializeOptions;\n} = {\n ttl: fourteenDaysInSeconds,\n cookieOptions: {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n },\n};\n\nexport interface IronSessionOptions {\n /**\n * This is the cookie name that will be used inside the browser. You should make sure it's unique given\n * your application. Example: vercel-session\n */\n cookieName: string;\n\n /**\n * This is the password(s) that will be used to encrypt the cookie. It can be either a string or an object\n * like {1: \"password\", 2: password}.\n *\n * When you provide multiple passwords then all of them will be used to decrypt the cookie and only the most\n * recent (= highest key, 2 in this example) password will be used to encrypt the cookie. This allow you\n * to use password rotation (security)\n */\n password: password;\n\n /**\n * This is the time in seconds that the session will be valid for. This also set the max-age attribute of\n * the cookie automatically (minus 60 seconds so that the cookie always expire before the session).\n */\n ttl?: number;\n\n /**\n * This is the options that will be passed to the cookie library.\n * You can see all of them here: https://github.com/jshttp/cookie#options-1.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser is closed) then you need\n * to pass cookieOptions: { maxAge: undefined }.\n */\n cookieOptions?: CookieSerializeOptions;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface IronSessionData {\n // If we allow for any keys, then there's no more type check on unknown properties\n // which is not good\n // If we allow for any keys, the later delete will work but I prefer to disable the\n // check at this stage and\n // provide good type checking instead\n // [key: string]: unknown;\n}\n\nexport type IronSession = IronSessionData & {\n /**\n * Destroys the session data and removes the cookie.\n */\n destroy: () => void;\n\n /**\n * Encrypts the session data and sets the cookie.\n */\n save: () => Promise<void>;\n};\n\ndeclare module \"http\" {\n interface IncomingMessage {\n session: IronSession;\n }\n}\n\nexport async function getIronSession(\n req: IncomingMessage,\n res: ServerResponse,\n userSessionOptions: IronSessionOptions,\n): Promise<IronSession> {\n if (\n !req ||\n !res ||\n !userSessionOptions ||\n !userSessionOptions.cookieName ||\n !userSessionOptions.password\n ) {\n throw new Error(\n `iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: \"...\", password: \"...\". Check the usage here: https://github.com/vvo/iron-session`,\n );\n }\n\n const passwordsAsMap = normalizeStringPasswordToMap(\n userSessionOptions.password,\n );\n\n Object.values(\n normalizeStringPasswordToMap(userSessionOptions.password),\n ).forEach((password) => {\n if (password.length < 32) {\n throw new Error(\n `iron-session: Bad usage. Password must be at least 32 characters long.`,\n );\n }\n });\n\n const options: Required<IronSessionOptions> = {\n ...defaultOptions,\n ...userSessionOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(userSessionOptions.cookieOptions || {}),\n },\n };\n\n if (options.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 options.ttl = 2147483647;\n }\n\n if (\n userSessionOptions.cookieOptions &&\n \"maxAge\" in userSessionOptions.cookieOptions\n ) {\n // session cookie, do not set maxAge, consider token as infinite\n if (userSessionOptions.cookieOptions.maxAge === undefined) {\n options.ttl = 0;\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(\n userSessionOptions.cookieOptions.maxAge,\n );\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n const sealFromCookies = cookie.parse(req.headers.cookie || \"\")[\n options.cookieName\n ];\n\n const session =\n sealFromCookies === undefined\n ? {}\n : await unsealData<IronSessionData>(sealFromCookies, {\n password: passwordsAsMap,\n ttl: options.ttl,\n });\n\n Object.defineProperties(session, {\n save: {\n value: async function save() {\n if (res.headersSent === true) {\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 const seal = await sealData(session, {\n password: passwordsAsMap,\n ttl: options.ttl,\n });\n const cookieValue = cookie.serialize(\n options.cookieName,\n seal,\n options.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`,\n );\n }\n\n addToCookies(cookieValue, res);\n },\n },\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n // @ts-ignore See comment on the IronSessionData interface\n delete session[key];\n });\n\n const cookieValue = cookie.serialize(options.cookieName, \"\", {\n ...options.cookieOptions,\n maxAge: 0,\n });\n addToCookies(cookieValue, res);\n },\n },\n });\n\n return session as IronSession;\n}\n\nfunction addToCookies(cookieValue: string, res: ServerResponse) {\n let existingSetCookie =\n (res.getHeader(\"set-cookie\") as string[] | string) ?? [];\n if (typeof existingSetCookie === \"string\") {\n existingSetCookie = [existingSetCookie];\n }\n res.setHeader(\"set-cookie\", [...existingSetCookie, cookieValue]);\n}\n\nfunction computeCookieMaxAge(ttl: number) {\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 maximum between server and clients.\n // It also makes sure to expire the cookie immediately when value is 0\n return ttl - timestampSkewSec;\n}\n\nexport async function unsealData<T = Record<string, unknown>>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: password; ttl?: number },\n): Promise<T> {\n const passwordsAsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data = await Iron.unseal(sealWithoutVersion, passwordsAsMap, {\n ...Iron.defaults,\n ttl: ttl * 1000,\n });\n\n if (tokenVersion === 2) {\n return data;\n }\n\n return {\n ...data.persistent,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message === \"Expired seal\" ||\n error.message === \"Bad hmac value\" ||\n error.message === \"Cannot find password: \" ||\n error.message === \"Incorrect number of sealed components\"\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\n throw error;\n }\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n if (seal[seal.length - 2] === versionDelimiter) {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n return {\n sealWithoutVersion,\n tokenVersion: parseInt(tokenVersionAsString, 10),\n };\n }\n\n return { sealWithoutVersion: seal, tokenVersion: null };\n}\n\nexport async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: password; ttl?: number },\n) {\n const passwordsAsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsAsMap).map((id) => parseInt(id, 10)),\n );\n\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n secret: passwordsAsMap[mostRecentPasswordId],\n };\n\n const seal = await Iron.seal(data, passwordForSeal, {\n ...Iron.defaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n}\n\nfunction normalizeStringPasswordToMap(password: password) {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import Iron from "@hapi/iron";
|
|
3
|
-
import
|
|
3
|
+
import cookie from "cookie";
|
|
4
4
|
var timestampSkewSec = 60;
|
|
5
5
|
var fourteenDaysInSeconds = 15 * 24 * 3600;
|
|
6
6
|
var currentMajorVersion = 2;
|
|
@@ -44,7 +44,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
44
44
|
} else {
|
|
45
45
|
options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);
|
|
46
46
|
}
|
|
47
|
-
const sealFromCookies =
|
|
47
|
+
const sealFromCookies = cookie.parse(req.headers.cookie || "")[options.cookieName];
|
|
48
48
|
const session = sealFromCookies === void 0 ? {} : await unsealData(sealFromCookies, {
|
|
49
49
|
password: passwordsAsMap,
|
|
50
50
|
ttl: options.ttl
|
|
@@ -59,7 +59,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
59
59
|
password: passwordsAsMap,
|
|
60
60
|
ttl: options.ttl
|
|
61
61
|
});
|
|
62
|
-
const cookieValue =
|
|
62
|
+
const cookieValue = cookie.serialize(options.cookieName, seal, options.cookieOptions);
|
|
63
63
|
if (cookieValue.length > 4096) {
|
|
64
64
|
throw new Error(`iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`);
|
|
65
65
|
}
|
|
@@ -71,7 +71,7 @@ async function getIronSession(req, res, userSessionOptions) {
|
|
|
71
71
|
Object.keys(session).forEach((key) => {
|
|
72
72
|
delete session[key];
|
|
73
73
|
});
|
|
74
|
-
const cookieValue =
|
|
74
|
+
const cookieValue = cookie.serialize(options.cookieName, "", {
|
|
75
75
|
...options.cookieOptions,
|
|
76
76
|
maxAge: 0
|
|
77
77
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import Iron from \"@hapi/iron\";\nimport type { CookieSerializeOptions } from \"cookie\";\nimport
|
|
5
|
-
"mappings": ";AAAA;AAEA;AAKA,IAAM,mBAAmB;AAKzB,IAAM,wBAAwB,KAAK,KAAK;AAIxC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAEzB,IAAM,iBAGF;AAAA,EACF,KAAK;AAAA,EACL,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM;AAAA;AAAA;AAiEV,8BACE,KACA,KACA,oBACsB;AACtB,MACE,CAAC,OACD,CAAC,OACD,CAAC,sBACD,CAAC,mBAAmB,cACpB,CAAC,mBAAmB,UACpB;AACA,UAAM,IAAI,MACR;AAAA;AAIJ,QAAM,iBAAiB,6BACrB,mBAAmB;AAGrB,SAAO,OACL,6BAA6B,mBAAmB,WAChD,QAAQ,CAAC,aAAa;AACtB,QAAI,SAAS,SAAS,IAAI;AACxB,YAAM,IAAI,MACR;AAAA;AAAA;AAKN,QAAM,UAAwC;AAAA,OACzC;AAAA,OACA;AAAA,IACH,eAAe;AAAA,SACV,eAAe;AAAA,SACd,mBAAmB,iBAAiB;AAAA;AAAA;AAI5C,MAAI,QAAQ,QAAQ,GAAG;AAKrB,YAAQ,MAAM;AAAA;AAGhB,MACE,mBAAmB,iBACnB,YAAY,mBAAmB,eAC/B;AAEA,QAAI,mBAAmB,cAAc,WAAW,QAAW;AACzD,cAAQ,MAAM;AAAA,WACT;AACL,cAAQ,cAAc,SAAS,oBAC7B,mBAAmB,cAAc;AAAA;AAAA,SAGhC;AACL,YAAQ,cAAc,SAAS,oBAAoB,QAAQ;AAAA;AAG7D,QAAM,kBAAkB,
|
|
4
|
+
"sourcesContent": ["import Iron from \"@hapi/iron\";\nimport type { CookieSerializeOptions } from \"cookie\";\nimport cookie from \"cookie\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/family/iron/api/?v=6.0.0#options\nconst timestampSkewSec = 60;\n\ntype passwordsMap = { [id: string]: string };\ntype password = string | passwordsMap;\n\nconst fourteenDaysInSeconds = 15 * 24 * 3600;\n\n// We store a token major version to handle data format changes when any. So that when you upgrade the cookies\n// can be kept alive between upgrades, no need to disconnect everyone.\nconst currentMajorVersion = 2;\nconst versionDelimiter = \"~\";\n\nconst defaultOptions: {\n ttl: number;\n cookieOptions: CookieSerializeOptions;\n} = {\n ttl: fourteenDaysInSeconds,\n cookieOptions: {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n },\n};\n\nexport interface IronSessionOptions {\n /**\n * This is the cookie name that will be used inside the browser. You should make sure it's unique given\n * your application. Example: vercel-session\n */\n cookieName: string;\n\n /**\n * This is the password(s) that will be used to encrypt the cookie. It can be either a string or an object\n * like {1: \"password\", 2: password}.\n *\n * When you provide multiple passwords then all of them will be used to decrypt the cookie and only the most\n * recent (= highest key, 2 in this example) password will be used to encrypt the cookie. This allow you\n * to use password rotation (security)\n */\n password: password;\n\n /**\n * This is the time in seconds that the session will be valid for. This also set the max-age attribute of\n * the cookie automatically (minus 60 seconds so that the cookie always expire before the session).\n */\n ttl?: number;\n\n /**\n * This is the options that will be passed to the cookie library.\n * You can see all of them here: https://github.com/jshttp/cookie#options-1.\n *\n * If you want to use \"session cookies\" (cookies that are deleted when the browser is closed) then you need\n * to pass cookieOptions: { maxAge: undefined }.\n */\n cookieOptions?: CookieSerializeOptions;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface IronSessionData {\n // If we allow for any keys, then there's no more type check on unknown properties\n // which is not good\n // If we allow for any keys, the later delete will work but I prefer to disable the\n // check at this stage and\n // provide good type checking instead\n // [key: string]: unknown;\n}\n\nexport type IronSession = IronSessionData & {\n /**\n * Destroys the session data and removes the cookie.\n */\n destroy: () => void;\n\n /**\n * Encrypts the session data and sets the cookie.\n */\n save: () => Promise<void>;\n};\n\ndeclare module \"http\" {\n interface IncomingMessage {\n session: IronSession;\n }\n}\n\nexport async function getIronSession(\n req: IncomingMessage,\n res: ServerResponse,\n userSessionOptions: IronSessionOptions,\n): Promise<IronSession> {\n if (\n !req ||\n !res ||\n !userSessionOptions ||\n !userSessionOptions.cookieName ||\n !userSessionOptions.password\n ) {\n throw new Error(\n `iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: \"...\", password: \"...\". Check the usage here: https://github.com/vvo/iron-session`,\n );\n }\n\n const passwordsAsMap = normalizeStringPasswordToMap(\n userSessionOptions.password,\n );\n\n Object.values(\n normalizeStringPasswordToMap(userSessionOptions.password),\n ).forEach((password) => {\n if (password.length < 32) {\n throw new Error(\n `iron-session: Bad usage. Password must be at least 32 characters long.`,\n );\n }\n });\n\n const options: Required<IronSessionOptions> = {\n ...defaultOptions,\n ...userSessionOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(userSessionOptions.cookieOptions || {}),\n },\n };\n\n if (options.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 options.ttl = 2147483647;\n }\n\n if (\n userSessionOptions.cookieOptions &&\n \"maxAge\" in userSessionOptions.cookieOptions\n ) {\n // session cookie, do not set maxAge, consider token as infinite\n if (userSessionOptions.cookieOptions.maxAge === undefined) {\n options.ttl = 0;\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(\n userSessionOptions.cookieOptions.maxAge,\n );\n }\n } else {\n options.cookieOptions.maxAge = computeCookieMaxAge(options.ttl);\n }\n\n const sealFromCookies = cookie.parse(req.headers.cookie || \"\")[\n options.cookieName\n ];\n\n const session =\n sealFromCookies === undefined\n ? {}\n : await unsealData<IronSessionData>(sealFromCookies, {\n password: passwordsAsMap,\n ttl: options.ttl,\n });\n\n Object.defineProperties(session, {\n save: {\n value: async function save() {\n if (res.headersSent === true) {\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 const seal = await sealData(session, {\n password: passwordsAsMap,\n ttl: options.ttl,\n });\n const cookieValue = cookie.serialize(\n options.cookieName,\n seal,\n options.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`,\n );\n }\n\n addToCookies(cookieValue, res);\n },\n },\n destroy: {\n value: function destroy() {\n Object.keys(session).forEach((key) => {\n // @ts-ignore See comment on the IronSessionData interface\n delete session[key];\n });\n\n const cookieValue = cookie.serialize(options.cookieName, \"\", {\n ...options.cookieOptions,\n maxAge: 0,\n });\n addToCookies(cookieValue, res);\n },\n },\n });\n\n return session as IronSession;\n}\n\nfunction addToCookies(cookieValue: string, res: ServerResponse) {\n let existingSetCookie =\n (res.getHeader(\"set-cookie\") as string[] | string) ?? [];\n if (typeof existingSetCookie === \"string\") {\n existingSetCookie = [existingSetCookie];\n }\n res.setHeader(\"set-cookie\", [...existingSetCookie, cookieValue]);\n}\n\nfunction computeCookieMaxAge(ttl: number) {\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 maximum between server and clients.\n // It also makes sure to expire the cookie immediately when value is 0\n return ttl - timestampSkewSec;\n}\n\nexport async function unsealData<T = Record<string, unknown>>(\n seal: string,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: password; ttl?: number },\n): Promise<T> {\n const passwordsAsMap = normalizeStringPasswordToMap(password);\n const { sealWithoutVersion, tokenVersion } = parseSeal(seal);\n\n try {\n const data = await Iron.unseal(sealWithoutVersion, passwordsAsMap, {\n ...Iron.defaults,\n ttl: ttl * 1000,\n });\n\n if (tokenVersion === 2) {\n return data;\n }\n\n return {\n ...data.persistent,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message === \"Expired seal\" ||\n error.message === \"Bad hmac value\" ||\n error.message === \"Cannot find password: \" ||\n error.message === \"Incorrect number of sealed components\"\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\n throw error;\n }\n}\n\nfunction parseSeal(seal: string): {\n sealWithoutVersion: string;\n tokenVersion: number | null;\n} {\n if (seal[seal.length - 2] === versionDelimiter) {\n const [sealWithoutVersion, tokenVersionAsString] =\n seal.split(versionDelimiter);\n return {\n sealWithoutVersion,\n tokenVersion: parseInt(tokenVersionAsString, 10),\n };\n }\n\n return { sealWithoutVersion: seal, tokenVersion: null };\n}\n\nexport async function sealData(\n data: unknown,\n {\n password,\n ttl = fourteenDaysInSeconds,\n }: { password: password; ttl?: number },\n) {\n const passwordsAsMap = normalizeStringPasswordToMap(password);\n\n const mostRecentPasswordId = Math.max(\n ...Object.keys(passwordsAsMap).map((id) => parseInt(id, 10)),\n );\n\n const passwordForSeal = {\n id: mostRecentPasswordId.toString(),\n secret: passwordsAsMap[mostRecentPasswordId],\n };\n\n const seal = await Iron.seal(data, passwordForSeal, {\n ...Iron.defaults,\n ttl: ttl * 1000,\n });\n\n return `${seal}${versionDelimiter}${currentMajorVersion}`;\n}\n\nfunction normalizeStringPasswordToMap(password: password) {\n return typeof password === \"string\" ? { 1: password } : password;\n}\n"],
|
|
5
|
+
"mappings": ";AAAA;AAEA;AAKA,IAAM,mBAAmB;AAKzB,IAAM,wBAAwB,KAAK,KAAK;AAIxC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAEzB,IAAM,iBAGF;AAAA,EACF,KAAK;AAAA,EACL,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM;AAAA;AAAA;AAiEV,8BACE,KACA,KACA,oBACsB;AACtB,MACE,CAAC,OACD,CAAC,OACD,CAAC,sBACD,CAAC,mBAAmB,cACpB,CAAC,mBAAmB,UACpB;AACA,UAAM,IAAI,MACR;AAAA;AAIJ,QAAM,iBAAiB,6BACrB,mBAAmB;AAGrB,SAAO,OACL,6BAA6B,mBAAmB,WAChD,QAAQ,CAAC,aAAa;AACtB,QAAI,SAAS,SAAS,IAAI;AACxB,YAAM,IAAI,MACR;AAAA;AAAA;AAKN,QAAM,UAAwC;AAAA,OACzC;AAAA,OACA;AAAA,IACH,eAAe;AAAA,SACV,eAAe;AAAA,SACd,mBAAmB,iBAAiB;AAAA;AAAA;AAI5C,MAAI,QAAQ,QAAQ,GAAG;AAKrB,YAAQ,MAAM;AAAA;AAGhB,MACE,mBAAmB,iBACnB,YAAY,mBAAmB,eAC/B;AAEA,QAAI,mBAAmB,cAAc,WAAW,QAAW;AACzD,cAAQ,MAAM;AAAA,WACT;AACL,cAAQ,cAAc,SAAS,oBAC7B,mBAAmB,cAAc;AAAA;AAAA,SAGhC;AACL,YAAQ,cAAc,SAAS,oBAAoB,QAAQ;AAAA;AAG7D,QAAM,kBAAkB,OAAO,MAAM,IAAI,QAAQ,UAAU,IACzD,QAAQ;AAGV,QAAM,UACJ,oBAAoB,SAChB,KACA,MAAM,WAA4B,iBAAiB;AAAA,IACjD,UAAU;AAAA,IACV,KAAK,QAAQ;AAAA;AAGrB,SAAO,iBAAiB,SAAS;AAAA,IAC/B,MAAM;AAAA,MACJ,OAAO,sBAAsB;AAC3B,YAAI,IAAI,gBAAgB,MAAM;AAC5B,gBAAM,IAAI,MACR;AAAA;AAGJ,cAAM,OAAO,MAAM,SAAS,SAAS;AAAA,UACnC,UAAU;AAAA,UACV,KAAK,QAAQ;AAAA;AAEf,cAAM,cAAc,OAAO,UACzB,QAAQ,YACR,MACA,QAAQ;AAGV,YAAI,YAAY,SAAS,MAAM;AAC7B,gBAAM,IAAI,MACR,0CAA0C,YAAY;AAAA;AAI1D,qBAAa,aAAa;AAAA;AAAA;AAAA,IAG9B,SAAS;AAAA,MACP,OAAO,mBAAmB;AACxB,eAAO,KAAK,SAAS,QAAQ,CAAC,QAAQ;AAEpC,iBAAO,QAAQ;AAAA;AAGjB,cAAM,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI;AAAA,aACxD,QAAQ;AAAA,UACX,QAAQ;AAAA;AAEV,qBAAa,aAAa;AAAA;AAAA;AAAA;AAKhC,SAAO;AAAA;AAGT,sBAAsB,aAAqB,KAAqB;AAvNhE;AAwNE,MAAI,oBACD,UAAI,UAAU,kBAAd,YAAqD;AACxD,MAAI,OAAO,sBAAsB,UAAU;AACzC,wBAAoB,CAAC;AAAA;AAEvB,MAAI,UAAU,cAAc,CAAC,GAAG,mBAAmB;AAAA;AAGrD,6BAA6B,KAAa;AAIxC,SAAO,MAAM;AAAA;AAGf,0BACE,MACA;AAAA,EACE;AAAA,EACA,MAAM;AAAA,GAEI;AACZ,QAAM,iBAAiB,6BAA6B;AACpD,QAAM,EAAE,oBAAoB,iBAAiB,UAAU;AAEvD,MAAI;AACF,UAAM,OAAO,MAAM,KAAK,OAAO,oBAAoB,gBAAgB;AAAA,SAC9D,KAAK;AAAA,MACR,KAAK,MAAM;AAAA;AAGb,QAAI,iBAAiB,GAAG;AACtB,aAAO;AAAA;AAGT,WAAO;AAAA,SACF,KAAK;AAAA;AAAA,WAEH,OAAP;AACA,QAAI,iBAAiB,OAAO;AAC1B,UACE,MAAM,YAAY,kBAClB,MAAM,YAAY,oBAClB,MAAM,YAAY,4BAClB,MAAM,YAAY,yCAClB;AAKA,eAAO;AAAA;AAAA;AAIX,UAAM;AAAA;AAAA;AAIV,mBAAmB,MAGjB;AACA,MAAI,KAAK,KAAK,SAAS,OAAO,kBAAkB;AAC9C,UAAM,CAAC,oBAAoB,wBACzB,KAAK,MAAM;AACb,WAAO;AAAA,MACL;AAAA,MACA,cAAc,SAAS,sBAAsB;AAAA;AAAA;AAIjD,SAAO,EAAE,oBAAoB,MAAM,cAAc;AAAA;AAGnD,wBACE,MACA;AAAA,EACE;AAAA,EACA,MAAM;AAAA,GAER;AACA,QAAM,iBAAiB,6BAA6B;AAEpD,QAAM,uBAAuB,KAAK,IAChC,GAAG,OAAO,KAAK,gBAAgB,IAAI,CAAC,OAAO,SAAS,IAAI;AAG1D,QAAM,kBAAkB;AAAA,IACtB,IAAI,qBAAqB;AAAA,IACzB,QAAQ,eAAe;AAAA;AAGzB,QAAM,OAAO,MAAM,KAAK,KAAK,MAAM,iBAAiB;AAAA,OAC/C,KAAK;AAAA,IACR,KAAK,MAAM;AAAA;AAGb,SAAO,GAAG,OAAO,mBAAmB;AAAA;AAGtC,sCAAsC,UAAoB;AACxD,SAAO,OAAO,aAAa,WAAW,EAAE,GAAG,aAAa;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/next/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { NextApiHandler, GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
|
|
1
|
+
import { NextApiHandler, GetServerSidePropsContext, GetServerSidePropsResult, NextApiRequest, NextApiResponse } from 'next';
|
|
2
2
|
import { IronSessionOptions } from 'iron-session';
|
|
3
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
4
|
|
|
4
|
-
declare
|
|
5
|
+
declare type GetIronSessionApiOptions = (request: NextApiRequest, response: NextApiResponse) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
6
|
+
declare function withIronSessionApiRoute(handler: NextApiHandler, options: IronSessionOptions | GetIronSessionApiOptions): NextApiHandler;
|
|
7
|
+
declare type GetIronSessionSSROptions = (request: IncomingMessage, response: ServerResponse) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
5
8
|
declare function withIronSessionSsr<P extends {
|
|
6
9
|
[key: string]: unknown;
|
|
7
10
|
} = {
|
|
8
11
|
[key: string]: unknown;
|
|
9
|
-
}>(handler: (context: GetServerSidePropsContext) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>, options: IronSessionOptions): (context: GetServerSidePropsContext) => Promise<GetServerSidePropsResult<P>>;
|
|
12
|
+
}>(handler: (context: GetServerSidePropsContext) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>, options: IronSessionOptions | GetIronSessionSSROptions): (context: GetServerSidePropsContext) => Promise<GetServerSidePropsResult<P>>;
|
|
10
13
|
|
|
11
14
|
export { withIronSessionApiRoute, withIronSessionSsr };
|
package/next/dist/index.js
CHANGED
|
@@ -54,14 +54,26 @@ function getPropertyDescriptorForReqSession(session) {
|
|
|
54
54
|
// next/index.ts
|
|
55
55
|
function withIronSessionApiRoute(handler, options) {
|
|
56
56
|
return async function nextApiHandlerWrappedWithIronSession(req, res) {
|
|
57
|
-
|
|
57
|
+
let sessionOptions;
|
|
58
|
+
if (options instanceof Function) {
|
|
59
|
+
sessionOptions = await options(req, res);
|
|
60
|
+
} else {
|
|
61
|
+
sessionOptions = options;
|
|
62
|
+
}
|
|
63
|
+
const session = await (0, import_iron_session.getIronSession)(req, res, sessionOptions);
|
|
58
64
|
Object.defineProperty(req, "session", getPropertyDescriptorForReqSession(session));
|
|
59
65
|
return handler(req, res);
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
68
|
function withIronSessionSsr(handler, options) {
|
|
63
69
|
return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
|
|
64
|
-
|
|
70
|
+
let sessionOptions;
|
|
71
|
+
if (options instanceof Function) {
|
|
72
|
+
sessionOptions = await options(context.req, context.res);
|
|
73
|
+
} else {
|
|
74
|
+
sessionOptions = options;
|
|
75
|
+
}
|
|
76
|
+
const session = await (0, import_iron_session.getIronSession)(context.req, context.res, sessionOptions);
|
|
65
77
|
Object.defineProperty(context.req, "session", getPropertyDescriptorForReqSession(session));
|
|
66
78
|
return handler(context);
|
|
67
79
|
};
|
package/next/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.ts", "../../src/getPropertyDescriptorForReqSession.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n const session = await getIronSession(req, res,
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\nimport { IncomingMessage, ServerResponse } from \"http\";\n\n// Argument types based on getIronSession function\ntype GetIronSessionApiOptions = (\n request: NextApiRequest,\n response: NextApiResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions | GetIronSessionApiOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(req, res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(req, res, sessionOptions);\n\n // we define req.session as being enumerable (so console.log(req) shows it)\n // and we also want to allow people to do:\n // req.session = { admin: true }; or req.session = {...req.session, admin: true};\n // req.session.save();\n Object.defineProperty(\n req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(req, res);\n };\n}\n\n// Argument type based on the SSR context\ntype GetIronSessionSSROptions = (\n request: IncomingMessage,\n response: ServerResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionSsr<\n P extends { [key: string]: unknown } = { [key: string]: unknown },\n>(\n handler: (\n context: GetServerSidePropsContext,\n ) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,\n options: IronSessionOptions | GetIronSessionSSROptions,\n) {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: GetServerSidePropsContext,\n ) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(context.req, context.res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(\n context.req,\n context.res,\n sessionOptions,\n );\n\n Object.defineProperty(\n context.req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(context);\n };\n}\n", "import type { IronSession } from \".\";\n\nexport default function getPropertyDescriptorForReqSession(\n session: IronSession,\n): PropertyDescriptor {\n return {\n enumerable: true,\n get() {\n return session;\n },\n set(value) {\n const keys = Object.keys(value);\n const currentKeys = Object.keys(session);\n\n currentKeys.forEach((key) => {\n if (!keys.includes(key)) {\n // @ts-ignore See comment in IronSessionData interface\n delete session[key];\n }\n });\n\n keys.forEach((key) => {\n // @ts-ignore See comment in IronSessionData interface\n session[key] = value[key];\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAQA,0BAA+B;;;ACNhB,4CACb,SACoB;AACpB,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,MAAM;AACJ,aAAO;AAAA;AAAA,IAET,IAAI,OAAO;AACT,YAAM,OAAO,OAAO,KAAK;AACzB,YAAM,cAAc,OAAO,KAAK;AAEhC,kBAAY,QAAQ,CAAC,QAAQ;AAC3B,YAAI,CAAC,KAAK,SAAS,MAAM;AAEvB,iBAAO,QAAQ;AAAA;AAAA;AAInB,WAAK,QAAQ,CAAC,QAAQ;AAEpB,gBAAQ,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;;;ADLtB,iCACL,SACA,SACgB;AAChB,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,KAAK;AAAA,WAC/B;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,wCAAe,KAAK,KAAK;AAM/C,WAAO,eACL,KACA,WACA,mCAAmC;AAErC,WAAO,QAAQ,KAAK;AAAA;AAAA;AAUjB,4BAGL,SAGA,SACA;AACA,SAAO,mEACL,SACA;AACA,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,WAC/C;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,wCACpB,QAAQ,KACR,QAAQ,KACR;AAGF,WAAO,eACL,QAAQ,KACR,WACA,mCAAmC;AAErC,WAAO,QAAQ;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/next/dist/index.mjs
CHANGED
|
@@ -26,14 +26,26 @@ function getPropertyDescriptorForReqSession(session) {
|
|
|
26
26
|
// next/index.ts
|
|
27
27
|
function withIronSessionApiRoute(handler, options) {
|
|
28
28
|
return async function nextApiHandlerWrappedWithIronSession(req, res) {
|
|
29
|
-
|
|
29
|
+
let sessionOptions;
|
|
30
|
+
if (options instanceof Function) {
|
|
31
|
+
sessionOptions = await options(req, res);
|
|
32
|
+
} else {
|
|
33
|
+
sessionOptions = options;
|
|
34
|
+
}
|
|
35
|
+
const session = await getIronSession(req, res, sessionOptions);
|
|
30
36
|
Object.defineProperty(req, "session", getPropertyDescriptorForReqSession(session));
|
|
31
37
|
return handler(req, res);
|
|
32
38
|
};
|
|
33
39
|
}
|
|
34
40
|
function withIronSessionSsr(handler, options) {
|
|
35
41
|
return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
|
|
36
|
-
|
|
42
|
+
let sessionOptions;
|
|
43
|
+
if (options instanceof Function) {
|
|
44
|
+
sessionOptions = await options(context.req, context.res);
|
|
45
|
+
} else {
|
|
46
|
+
sessionOptions = options;
|
|
47
|
+
}
|
|
48
|
+
const session = await getIronSession(context.req, context.res, sessionOptions);
|
|
37
49
|
Object.defineProperty(context.req, "session", getPropertyDescriptorForReqSession(session));
|
|
38
50
|
return handler(context);
|
|
39
51
|
};
|
package/next/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.ts", "../../src/getPropertyDescriptorForReqSession.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n const session = await getIronSession(req, res,
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\nimport { IncomingMessage, ServerResponse } from \"http\";\n\n// Argument types based on getIronSession function\ntype GetIronSessionApiOptions = (\n request: NextApiRequest,\n response: NextApiResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions | GetIronSessionApiOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(req, res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(req, res, sessionOptions);\n\n // we define req.session as being enumerable (so console.log(req) shows it)\n // and we also want to allow people to do:\n // req.session = { admin: true }; or req.session = {...req.session, admin: true};\n // req.session.save();\n Object.defineProperty(\n req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(req, res);\n };\n}\n\n// Argument type based on the SSR context\ntype GetIronSessionSSROptions = (\n request: IncomingMessage,\n response: ServerResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionSsr<\n P extends { [key: string]: unknown } = { [key: string]: unknown },\n>(\n handler: (\n context: GetServerSidePropsContext,\n ) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,\n options: IronSessionOptions | GetIronSessionSSROptions,\n) {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: GetServerSidePropsContext,\n ) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(context.req, context.res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(\n context.req,\n context.res,\n sessionOptions,\n );\n\n Object.defineProperty(\n context.req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(context);\n };\n}\n", "import type { IronSession } from \".\";\n\nexport default function getPropertyDescriptorForReqSession(\n session: IronSession,\n): PropertyDescriptor {\n return {\n enumerable: true,\n get() {\n return session;\n },\n set(value) {\n const keys = Object.keys(value);\n const currentKeys = Object.keys(session);\n\n currentKeys.forEach((key) => {\n if (!keys.includes(key)) {\n // @ts-ignore See comment in IronSessionData interface\n delete session[key];\n }\n });\n\n keys.forEach((key) => {\n // @ts-ignore See comment in IronSessionData interface\n session[key] = value[key];\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";AAQA;;;ACNe,4CACb,SACoB;AACpB,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,MAAM;AACJ,aAAO;AAAA;AAAA,IAET,IAAI,OAAO;AACT,YAAM,OAAO,OAAO,KAAK;AACzB,YAAM,cAAc,OAAO,KAAK;AAEhC,kBAAY,QAAQ,CAAC,QAAQ;AAC3B,YAAI,CAAC,KAAK,SAAS,MAAM;AAEvB,iBAAO,QAAQ;AAAA;AAAA;AAInB,WAAK,QAAQ,CAAC,QAAQ;AAEpB,gBAAQ,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;;;ADLtB,iCACL,SACA,SACgB;AAChB,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,KAAK;AAAA,WAC/B;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,eAAe,KAAK,KAAK;AAM/C,WAAO,eACL,KACA,WACA,mCAAmC;AAErC,WAAO,QAAQ,KAAK;AAAA;AAAA;AAUjB,4BAGL,SAGA,SACA;AACA,SAAO,mEACL,SACA;AACA,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,WAC/C;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,eACpB,QAAQ,KACR,QAAQ,KACR;AAGF,WAAO,eACL,QAAQ,KACR,WACA,mCAAmC;AAErC,WAAO,QAAQ;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/next/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { NextApiHandler, GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
|
|
1
|
+
import { NextApiHandler, GetServerSidePropsContext, GetServerSidePropsResult, NextApiRequest, NextApiResponse } from 'next';
|
|
2
2
|
import { IronSessionOptions } from 'iron-session';
|
|
3
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
4
|
|
|
4
|
-
declare
|
|
5
|
+
declare type GetIronSessionApiOptions = (request: NextApiRequest, response: NextApiResponse) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
6
|
+
declare function withIronSessionApiRoute(handler: NextApiHandler, options: IronSessionOptions | GetIronSessionApiOptions): NextApiHandler;
|
|
7
|
+
declare type GetIronSessionSSROptions = (request: IncomingMessage, response: ServerResponse) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
5
8
|
declare function withIronSessionSsr<P extends {
|
|
6
9
|
[key: string]: unknown;
|
|
7
10
|
} = {
|
|
8
11
|
[key: string]: unknown;
|
|
9
|
-
}>(handler: (context: GetServerSidePropsContext) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>, options: IronSessionOptions): (context: GetServerSidePropsContext) => Promise<GetServerSidePropsResult<P>>;
|
|
12
|
+
}>(handler: (context: GetServerSidePropsContext) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>, options: IronSessionOptions | GetIronSessionSSROptions): (context: GetServerSidePropsContext) => Promise<GetServerSidePropsResult<P>>;
|
|
10
13
|
|
|
11
14
|
export { withIronSessionApiRoute, withIronSessionSsr };
|
package/next/index.js
CHANGED
|
@@ -54,14 +54,26 @@ function getPropertyDescriptorForReqSession(session) {
|
|
|
54
54
|
// next/index.ts
|
|
55
55
|
function withIronSessionApiRoute(handler, options) {
|
|
56
56
|
return async function nextApiHandlerWrappedWithIronSession(req, res) {
|
|
57
|
-
|
|
57
|
+
let sessionOptions;
|
|
58
|
+
if (options instanceof Function) {
|
|
59
|
+
sessionOptions = await options(req, res);
|
|
60
|
+
} else {
|
|
61
|
+
sessionOptions = options;
|
|
62
|
+
}
|
|
63
|
+
const session = await (0, import_iron_session.getIronSession)(req, res, sessionOptions);
|
|
58
64
|
Object.defineProperty(req, "session", getPropertyDescriptorForReqSession(session));
|
|
59
65
|
return handler(req, res);
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
68
|
function withIronSessionSsr(handler, options) {
|
|
63
69
|
return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
|
|
64
|
-
|
|
70
|
+
let sessionOptions;
|
|
71
|
+
if (options instanceof Function) {
|
|
72
|
+
sessionOptions = await options(context.req, context.res);
|
|
73
|
+
} else {
|
|
74
|
+
sessionOptions = options;
|
|
75
|
+
}
|
|
76
|
+
const session = await (0, import_iron_session.getIronSession)(context.req, context.res, sessionOptions);
|
|
65
77
|
Object.defineProperty(context.req, "session", getPropertyDescriptorForReqSession(session));
|
|
66
78
|
return handler(context);
|
|
67
79
|
};
|
package/next/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.ts", "../../src/getPropertyDescriptorForReqSession.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n const session = await getIronSession(req, res,
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\nimport { IncomingMessage, ServerResponse } from \"http\";\n\n// Argument types based on getIronSession function\ntype GetIronSessionApiOptions = (\n request: NextApiRequest,\n response: NextApiResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions | GetIronSessionApiOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(req, res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(req, res, sessionOptions);\n\n // we define req.session as being enumerable (so console.log(req) shows it)\n // and we also want to allow people to do:\n // req.session = { admin: true }; or req.session = {...req.session, admin: true};\n // req.session.save();\n Object.defineProperty(\n req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(req, res);\n };\n}\n\n// Argument type based on the SSR context\ntype GetIronSessionSSROptions = (\n request: IncomingMessage,\n response: ServerResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionSsr<\n P extends { [key: string]: unknown } = { [key: string]: unknown },\n>(\n handler: (\n context: GetServerSidePropsContext,\n ) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,\n options: IronSessionOptions | GetIronSessionSSROptions,\n) {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: GetServerSidePropsContext,\n ) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(context.req, context.res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(\n context.req,\n context.res,\n sessionOptions,\n );\n\n Object.defineProperty(\n context.req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(context);\n };\n}\n", "import type { IronSession } from \".\";\n\nexport default function getPropertyDescriptorForReqSession(\n session: IronSession,\n): PropertyDescriptor {\n return {\n enumerable: true,\n get() {\n return session;\n },\n set(value) {\n const keys = Object.keys(value);\n const currentKeys = Object.keys(session);\n\n currentKeys.forEach((key) => {\n if (!keys.includes(key)) {\n // @ts-ignore See comment in IronSessionData interface\n delete session[key];\n }\n });\n\n keys.forEach((key) => {\n // @ts-ignore See comment in IronSessionData interface\n session[key] = value[key];\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAQA,0BAA+B;;;ACNhB,4CACb,SACoB;AACpB,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,MAAM;AACJ,aAAO;AAAA;AAAA,IAET,IAAI,OAAO;AACT,YAAM,OAAO,OAAO,KAAK;AACzB,YAAM,cAAc,OAAO,KAAK;AAEhC,kBAAY,QAAQ,CAAC,QAAQ;AAC3B,YAAI,CAAC,KAAK,SAAS,MAAM;AAEvB,iBAAO,QAAQ;AAAA;AAAA;AAInB,WAAK,QAAQ,CAAC,QAAQ;AAEpB,gBAAQ,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;;;ADLtB,iCACL,SACA,SACgB;AAChB,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,KAAK;AAAA,WAC/B;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,wCAAe,KAAK,KAAK;AAM/C,WAAO,eACL,KACA,WACA,mCAAmC;AAErC,WAAO,QAAQ,KAAK;AAAA;AAAA;AAUjB,4BAGL,SAGA,SACA;AACA,SAAO,mEACL,SACA;AACA,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,WAC/C;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,wCACpB,QAAQ,KACR,QAAQ,KACR;AAGF,WAAO,eACL,QAAQ,KACR,WACA,mCAAmC;AAErC,WAAO,QAAQ;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/next/index.mjs
CHANGED
|
@@ -26,14 +26,26 @@ function getPropertyDescriptorForReqSession(session) {
|
|
|
26
26
|
// next/index.ts
|
|
27
27
|
function withIronSessionApiRoute(handler, options) {
|
|
28
28
|
return async function nextApiHandlerWrappedWithIronSession(req, res) {
|
|
29
|
-
|
|
29
|
+
let sessionOptions;
|
|
30
|
+
if (options instanceof Function) {
|
|
31
|
+
sessionOptions = await options(req, res);
|
|
32
|
+
} else {
|
|
33
|
+
sessionOptions = options;
|
|
34
|
+
}
|
|
35
|
+
const session = await getIronSession(req, res, sessionOptions);
|
|
30
36
|
Object.defineProperty(req, "session", getPropertyDescriptorForReqSession(session));
|
|
31
37
|
return handler(req, res);
|
|
32
38
|
};
|
|
33
39
|
}
|
|
34
40
|
function withIronSessionSsr(handler, options) {
|
|
35
41
|
return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
|
|
36
|
-
|
|
42
|
+
let sessionOptions;
|
|
43
|
+
if (options instanceof Function) {
|
|
44
|
+
sessionOptions = await options(context.req, context.res);
|
|
45
|
+
} else {
|
|
46
|
+
sessionOptions = options;
|
|
47
|
+
}
|
|
48
|
+
const session = await getIronSession(context.req, context.res, sessionOptions);
|
|
37
49
|
Object.defineProperty(context.req, "session", getPropertyDescriptorForReqSession(session));
|
|
38
50
|
return handler(context);
|
|
39
51
|
};
|
package/next/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.ts", "../../src/getPropertyDescriptorForReqSession.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n const session = await getIronSession(req, res,
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import type {\n NextApiHandler,\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport getPropertyDescriptorForReqSession from \"../src/getPropertyDescriptorForReqSession\";\nimport { IncomingMessage, ServerResponse } from \"http\";\n\n// Argument types based on getIronSession function\ntype GetIronSessionApiOptions = (\n request: NextApiRequest,\n response: NextApiResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandler,\n options: IronSessionOptions | GetIronSessionApiOptions,\n): NextApiHandler {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(req, res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(req, res, sessionOptions);\n\n // we define req.session as being enumerable (so console.log(req) shows it)\n // and we also want to allow people to do:\n // req.session = { admin: true }; or req.session = {...req.session, admin: true};\n // req.session.save();\n Object.defineProperty(\n req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(req, res);\n };\n}\n\n// Argument type based on the SSR context\ntype GetIronSessionSSROptions = (\n request: IncomingMessage,\n response: ServerResponse,\n) => Promise<IronSessionOptions> | IronSessionOptions;\n\nexport function withIronSessionSsr<\n P extends { [key: string]: unknown } = { [key: string]: unknown },\n>(\n handler: (\n context: GetServerSidePropsContext,\n ) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,\n options: IronSessionOptions | GetIronSessionSSROptions,\n) {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: GetServerSidePropsContext,\n ) {\n let sessionOptions: IronSessionOptions;\n\n // If options is a function, call it and assign the results back.\n if (options instanceof Function) {\n sessionOptions = await options(context.req, context.res);\n } else {\n sessionOptions = options;\n }\n\n const session = await getIronSession(\n context.req,\n context.res,\n sessionOptions,\n );\n\n Object.defineProperty(\n context.req,\n \"session\",\n getPropertyDescriptorForReqSession(session),\n );\n return handler(context);\n };\n}\n", "import type { IronSession } from \".\";\n\nexport default function getPropertyDescriptorForReqSession(\n session: IronSession,\n): PropertyDescriptor {\n return {\n enumerable: true,\n get() {\n return session;\n },\n set(value) {\n const keys = Object.keys(value);\n const currentKeys = Object.keys(session);\n\n currentKeys.forEach((key) => {\n if (!keys.includes(key)) {\n // @ts-ignore See comment in IronSessionData interface\n delete session[key];\n }\n });\n\n keys.forEach((key) => {\n // @ts-ignore See comment in IronSessionData interface\n session[key] = value[key];\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";AAQA;;;ACNe,4CACb,SACoB;AACpB,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,MAAM;AACJ,aAAO;AAAA;AAAA,IAET,IAAI,OAAO;AACT,YAAM,OAAO,OAAO,KAAK;AACzB,YAAM,cAAc,OAAO,KAAK;AAEhC,kBAAY,QAAQ,CAAC,QAAQ;AAC3B,YAAI,CAAC,KAAK,SAAS,MAAM;AAEvB,iBAAO,QAAQ;AAAA;AAAA;AAInB,WAAK,QAAQ,CAAC,QAAQ;AAEpB,gBAAQ,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;;;ADLtB,iCACL,SACA,SACgB;AAChB,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,KAAK;AAAA,WAC/B;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,eAAe,KAAK,KAAK;AAM/C,WAAO,eACL,KACA,WACA,mCAAmC;AAErC,WAAO,QAAQ,KAAK;AAAA;AAAA;AAUjB,4BAGL,SAGA,SACA;AACA,SAAO,mEACL,SACA;AACA,QAAI;AAGJ,QAAI,mBAAmB,UAAU;AAC/B,uBAAiB,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,WAC/C;AACL,uBAAiB;AAAA;AAGnB,UAAM,UAAU,MAAM,eACpB,QAAQ,KACR,QAAQ,KACR;AAGF,WAAO,eACL,QAAQ,KACR,WACA,mCAAmC;AAErC,WAAO,QAAQ;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/next/index.test.ts
CHANGED
|
@@ -60,6 +60,34 @@ test("withIronSessionApiRoute: req.session.save creates a cookie", async () => {
|
|
|
60
60
|
await wrappedHandler(getDefaultReq(), getDefaultRes());
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
test("withIconSessionApiRoute: IronSessionOptions passed as a function works correctly", async () => {
|
|
64
|
+
const wrappedHandler = withIronSessionApiRoute(
|
|
65
|
+
async function handler(req, res) {
|
|
66
|
+
req.session.user = { id: 200 };
|
|
67
|
+
await req.session.save();
|
|
68
|
+
const headerValue = (res.setHeader as jest.Mock).mock.calls[0][1];
|
|
69
|
+
const cookie = headerValue[0];
|
|
70
|
+
const cookieParams = cookie.split(";").slice(1).join(";");
|
|
71
|
+
const cookieName = cookie.split("=")[0];
|
|
72
|
+
// When giving session, iron implementation substracts 60 seconds.
|
|
73
|
+
const maxAgeValue = Number(req.headers["value"]) - 60;
|
|
74
|
+
expect(cookieParams).toMatchInlineSnapshot(
|
|
75
|
+
`" Max-Age=${maxAgeValue}; Path=/; HttpOnly; Secure; SameSite=Lax"`,
|
|
76
|
+
);
|
|
77
|
+
expect(cookieName).toBe("dynamic-cookie-name");
|
|
78
|
+
},
|
|
79
|
+
(request) => ({
|
|
80
|
+
cookieName: "dynamic-cookie-name",
|
|
81
|
+
password,
|
|
82
|
+
ttl: Number(request.headers["value"]),
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Run it twice to make sure different value is assigned on computed session option from request
|
|
87
|
+
await wrappedHandler(getDefaultReq(), getDefaultRes());
|
|
88
|
+
await wrappedHandler(getDefaultReq(), getDefaultRes());
|
|
89
|
+
});
|
|
90
|
+
|
|
63
91
|
test("withIronSessionApiRoute: req.session.destroy removes the cookie", async () => {
|
|
64
92
|
const wrappedHandler = withIronSessionApiRoute(
|
|
65
93
|
async function handler(req, res) {
|
|
@@ -167,9 +195,50 @@ test("withIronSessionSsr: req.session exists", async () => {
|
|
|
167
195
|
} as unknown as GetServerSidePropsContext);
|
|
168
196
|
});
|
|
169
197
|
|
|
198
|
+
test("withIronSessionSsr: IronSessionOptions passed as a function to be computed on each request work correctly", async () => {
|
|
199
|
+
const wrappedHandler = withIronSessionSsr(
|
|
200
|
+
async function handler(context) {
|
|
201
|
+
context.req.session.user = { id: 200 };
|
|
202
|
+
await context.req.session.save();
|
|
203
|
+
const headerValue = (context.res.setHeader as jest.Mock).mock.calls[0][1];
|
|
204
|
+
const cookie = headerValue[0];
|
|
205
|
+
const cookieParams = cookie.split(";").slice(1).join(";");
|
|
206
|
+
const cookieName = cookie.split("=")[0];
|
|
207
|
+
// When giving session, iron implementation substracts 60 seconds.
|
|
208
|
+
const maxAgeValue = Number(context.req.headers["value"]) - 60;
|
|
209
|
+
expect(cookieParams).toMatchInlineSnapshot(
|
|
210
|
+
`" Max-Age=${maxAgeValue}; Path=/; HttpOnly; Secure; SameSite=Lax"`,
|
|
211
|
+
);
|
|
212
|
+
expect(cookieName).toBe("dynamic-cookie-name");
|
|
213
|
+
return {
|
|
214
|
+
props: {},
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
(request) => ({
|
|
218
|
+
cookieName: "dynamic-cookie-name",
|
|
219
|
+
password,
|
|
220
|
+
ttl: Number(request.headers["value"]),
|
|
221
|
+
}),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Run it twice to make sure different value is assigned on computed session option from request
|
|
225
|
+
await wrappedHandler({
|
|
226
|
+
req: getDefaultReq(),
|
|
227
|
+
res: getDefaultRes(),
|
|
228
|
+
} as unknown as GetServerSidePropsContext);
|
|
229
|
+
|
|
230
|
+
await wrappedHandler({
|
|
231
|
+
req: getDefaultReq(),
|
|
232
|
+
res: getDefaultRes(),
|
|
233
|
+
} as unknown as GetServerSidePropsContext);
|
|
234
|
+
});
|
|
235
|
+
|
|
170
236
|
function getDefaultReq() {
|
|
171
237
|
return {
|
|
172
|
-
headers: {
|
|
238
|
+
headers: {
|
|
239
|
+
// Random number between 100 to 1000
|
|
240
|
+
value: Math.floor(Math.random() * 900) + 100,
|
|
241
|
+
},
|
|
173
242
|
socket: {
|
|
174
243
|
encrypted: true,
|
|
175
244
|
},
|
package/next/index.ts
CHANGED
|
@@ -2,17 +2,35 @@ import type {
|
|
|
2
2
|
NextApiHandler,
|
|
3
3
|
GetServerSidePropsContext,
|
|
4
4
|
GetServerSidePropsResult,
|
|
5
|
+
NextApiRequest,
|
|
6
|
+
NextApiResponse,
|
|
5
7
|
} from "next";
|
|
6
8
|
import type { IronSessionOptions } from "iron-session";
|
|
7
9
|
import { getIronSession } from "iron-session";
|
|
8
10
|
import getPropertyDescriptorForReqSession from "../src/getPropertyDescriptorForReqSession";
|
|
11
|
+
import { IncomingMessage, ServerResponse } from "http";
|
|
12
|
+
|
|
13
|
+
// Argument types based on getIronSession function
|
|
14
|
+
type GetIronSessionApiOptions = (
|
|
15
|
+
request: NextApiRequest,
|
|
16
|
+
response: NextApiResponse,
|
|
17
|
+
) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
9
18
|
|
|
10
19
|
export function withIronSessionApiRoute(
|
|
11
20
|
handler: NextApiHandler,
|
|
12
|
-
options: IronSessionOptions,
|
|
21
|
+
options: IronSessionOptions | GetIronSessionApiOptions,
|
|
13
22
|
): NextApiHandler {
|
|
14
23
|
return async function nextApiHandlerWrappedWithIronSession(req, res) {
|
|
15
|
-
|
|
24
|
+
let sessionOptions: IronSessionOptions;
|
|
25
|
+
|
|
26
|
+
// If options is a function, call it and assign the results back.
|
|
27
|
+
if (options instanceof Function) {
|
|
28
|
+
sessionOptions = await options(req, res);
|
|
29
|
+
} else {
|
|
30
|
+
sessionOptions = options;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const session = await getIronSession(req, res, sessionOptions);
|
|
16
34
|
|
|
17
35
|
// we define req.session as being enumerable (so console.log(req) shows it)
|
|
18
36
|
// and we also want to allow people to do:
|
|
@@ -27,18 +45,38 @@ export function withIronSessionApiRoute(
|
|
|
27
45
|
};
|
|
28
46
|
}
|
|
29
47
|
|
|
48
|
+
// Argument type based on the SSR context
|
|
49
|
+
type GetIronSessionSSROptions = (
|
|
50
|
+
request: IncomingMessage,
|
|
51
|
+
response: ServerResponse,
|
|
52
|
+
) => Promise<IronSessionOptions> | IronSessionOptions;
|
|
53
|
+
|
|
30
54
|
export function withIronSessionSsr<
|
|
31
55
|
P extends { [key: string]: unknown } = { [key: string]: unknown },
|
|
32
56
|
>(
|
|
33
57
|
handler: (
|
|
34
58
|
context: GetServerSidePropsContext,
|
|
35
59
|
) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,
|
|
36
|
-
options: IronSessionOptions,
|
|
60
|
+
options: IronSessionOptions | GetIronSessionSSROptions,
|
|
37
61
|
) {
|
|
38
62
|
return async function nextGetServerSidePropsHandlerWrappedWithIronSession(
|
|
39
63
|
context: GetServerSidePropsContext,
|
|
40
64
|
) {
|
|
41
|
-
|
|
65
|
+
let sessionOptions: IronSessionOptions;
|
|
66
|
+
|
|
67
|
+
// If options is a function, call it and assign the results back.
|
|
68
|
+
if (options instanceof Function) {
|
|
69
|
+
sessionOptions = await options(context.req, context.res);
|
|
70
|
+
} else {
|
|
71
|
+
sessionOptions = options;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const session = await getIronSession(
|
|
75
|
+
context.req,
|
|
76
|
+
context.res,
|
|
77
|
+
sessionOptions,
|
|
78
|
+
);
|
|
79
|
+
|
|
42
80
|
Object.defineProperty(
|
|
43
81
|
context.req,
|
|
44
82
|
"session",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iron-session",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.1",
|
|
4
4
|
"description": "Node.js stateless session utility using signed and encrypted cookies to store data. Works with Next.js, Express, NestJs, Fastify, and any Node.js HTTP framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Next.js",
|
|
@@ -125,23 +125,23 @@
|
|
|
125
125
|
"@types/cookie": "^0.4.0",
|
|
126
126
|
"@types/express": "^4.17.13",
|
|
127
127
|
"@types/node": "^16.11.7",
|
|
128
|
-
"cookie": "^0.4.
|
|
128
|
+
"cookie": "^0.4.2"
|
|
129
129
|
},
|
|
130
130
|
"devDependencies": {
|
|
131
|
-
"@swc/core": "^1.2.
|
|
132
|
-
"@swc/jest": "0.2.
|
|
131
|
+
"@swc/core": "^1.2.156",
|
|
132
|
+
"@swc/jest": "^0.2.20",
|
|
133
133
|
"@tsconfig/node12": "1.0.9",
|
|
134
|
-
"@types/jest": "27.
|
|
135
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
136
|
-
"@typescript-eslint/parser": "^5.
|
|
137
|
-
"concurrently": "
|
|
138
|
-
"eslint": "^8.
|
|
139
|
-
"jest": "27.
|
|
140
|
-
"prettier": "2.
|
|
141
|
-
"prettier-plugin-packagejson": "2.2.
|
|
134
|
+
"@types/jest": "^27.4.1",
|
|
135
|
+
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
|
136
|
+
"@typescript-eslint/parser": "^5.15.0",
|
|
137
|
+
"concurrently": "^7.0.0",
|
|
138
|
+
"eslint": "^8.11.0",
|
|
139
|
+
"jest": "^27.5.1",
|
|
140
|
+
"prettier": "^2.6.0",
|
|
141
|
+
"prettier-plugin-packagejson": "^2.2.16",
|
|
142
142
|
"rimraf": "3.0.2",
|
|
143
143
|
"tsup": "5.6.0",
|
|
144
|
-
"typescript": "4.
|
|
144
|
+
"typescript": "^4.6.2"
|
|
145
145
|
},
|
|
146
146
|
"peerDependencies": {
|
|
147
147
|
"express": ">=4",
|