@nifrajs/auth 4.0.2 → 5.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/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +4 -0
- package/dist/csrf.js.map +1 -1
- package/dist/guards.d.ts +12 -2
- package/dist/guards.d.ts.map +1 -1
- package/dist/guards.js +25 -1
- package/dist/guards.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +17 -4
- package/dist/session.js.map +1 -1
- package/package.json +2 -2
- package/src/csrf.ts +4 -0
- package/src/guards.ts +44 -3
- package/src/index.ts +6 -1
- package/src/session.ts +18 -8
package/dist/csrf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAQ3E,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAKD,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAQ3E,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAKD,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CAmC1D"}
|
package/dist/csrf.js
CHANGED
|
@@ -22,6 +22,10 @@ export function csrf(options = {}) {
|
|
|
22
22
|
// request URL on the same host - what every TLS-terminating proxy looks like from here.
|
|
23
23
|
const allowed = (candidate) => configured !== undefined ? configured.has(candidate) : isSameOriginRequest(candidate, req);
|
|
24
24
|
const origin = req.headers.get("origin");
|
|
25
|
+
// Under `Referrer-Policy: no-referrer` a browser sends a same-origin form POST with
|
|
26
|
+
// `Origin: null`; its own `Sec-Fetch-Site` still says same-origin, and script can set neither.
|
|
27
|
+
if (origin === "null" && configured === undefined)
|
|
28
|
+
return req.headers.get("sec-fetch-site") === "same-origin" ? undefined : forbidden();
|
|
25
29
|
if (origin !== null)
|
|
26
30
|
return allowed(origin) ? undefined : forbidden();
|
|
27
31
|
// Some same-origin requests omit `Origin` - fall back to the `Referer`'s origin.
|
package/dist/csrf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,mBAAmB,EAAmB,MAAM,sBAAsB,CAAA;AAE3E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AAExD,oGAAoG;AACpG,+BAA+B;AAC/B,IAAI,SAAS,GAAG,CAAC,CAAA;AAWjB,MAAM,SAAS,GAAG,GAAa,EAAE,CAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;AAErE,MAAM,UAAU,IAAI,CAAC,UAAuB,EAAE;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACvF,SAAS,IAAI,CAAC,CAAA;IACd,OAAO;QACL,IAAI,EAAE,QAAQ,SAAS,EAAE;QACzB,SAAS,CAAC,GAAG;YACX,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAA;YAClD,gGAAgG;YAChG,wFAAwF;YACxF,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAW,EAAE,CAC7C,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;YAE5F,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACxC,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;YAErE,iFAAiF;YACjF,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAC1C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,IAAI,aAAqB,CAAA;gBACzB,IAAI,CAAC;oBACH,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;gBACzC,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,EAAE,CAAA,CAAC,oBAAoB;gBACzC,CAAC;gBACD,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;YACzD,CAAC;YAED,mGAAmG;YACnG,OAAO,SAAS,EAAE,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,mBAAmB,EAAmB,MAAM,sBAAsB,CAAA;AAE3E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AAExD,oGAAoG;AACpG,+BAA+B;AAC/B,IAAI,SAAS,GAAG,CAAC,CAAA;AAWjB,MAAM,SAAS,GAAG,GAAa,EAAE,CAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;AAErE,MAAM,UAAU,IAAI,CAAC,UAAuB,EAAE;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACvF,SAAS,IAAI,CAAC,CAAA;IACd,OAAO;QACL,IAAI,EAAE,QAAQ,SAAS,EAAE;QACzB,SAAS,CAAC,GAAG;YACX,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAA;YAClD,gGAAgG;YAChG,wFAAwF;YACxF,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAW,EAAE,CAC7C,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;YAE5F,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACxC,oFAAoF;YACpF,+FAA+F;YAC/F,IAAI,MAAM,KAAK,MAAM,IAAI,UAAU,KAAK,SAAS;gBAC/C,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;YACtF,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;YAErE,iFAAiF;YACjF,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAC1C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,IAAI,aAAqB,CAAA;gBACzB,IAAI,CAAC;oBACH,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;gBACzC,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,EAAE,CAAA,CAAC,oBAAoB;gBACzC,CAAC;gBACD,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;YACzD,CAAC;YAED,mGAAmG;YACnG,OAAO,SAAS,EAAE,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/dist/guards.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { Session } from "./session.js";
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/** The response a guard denies a missing session with, in place of the default `401` JSON. */
|
|
3
|
+
export interface UnauthenticatedResponse {
|
|
4
|
+
/** An error status, 400-599. Default `401`. */
|
|
5
|
+
readonly status?: number;
|
|
6
|
+
/** The body; present but `undefined` sends none. Default `{ ok: false, error: "unauthorized" }`. */
|
|
7
|
+
readonly body?: unknown;
|
|
8
|
+
/** Response headers, such as a `www-authenticate` challenge. */
|
|
9
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
10
|
+
}
|
|
11
|
+
/** What a guard does when the check fails: 302 to `redirectTo` (a same-origin path), or - omitted - the
|
|
12
|
+
* `unauthenticated` response, by default a 401 JSON (`{ ok: false, error: "unauthorized" }`). */
|
|
4
13
|
export interface GuardOptions {
|
|
5
14
|
readonly redirectTo?: string;
|
|
15
|
+
readonly unauthenticated?: UnauthenticatedResponse;
|
|
6
16
|
}
|
|
7
17
|
/**
|
|
8
18
|
* Require a non-empty session. Returns it when present; otherwise throws a `status(...)` render
|
package/dist/guards.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,8FAA8F;AAC9F,MAAM,WAAW,uBAAuB;IACtC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,oGAAoG;IACpG,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,gEAAgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACpD;AAED;iGACiG;AACjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,uBAAuB,CAAA;CACnD;AA4CD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,EACpF,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,GAAG,EAAE,CAAC,EACN,OAAO,GAAE,YAAiB,GACzB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAMtB"}
|
package/dist/guards.js
CHANGED
|
@@ -13,10 +13,32 @@
|
|
|
13
13
|
* Pairs with `@nifrajs/auth` sessions but only needs the `Session` shape, so it's framework-agnostic.
|
|
14
14
|
*/
|
|
15
15
|
import { isSameOriginPath, status } from "@nifrajs/core/server";
|
|
16
|
+
const UNAUTHORIZED = { ok: false, error: "unauthorized" };
|
|
17
|
+
/** A dev-authored denial that is not an error status, or that competes with a redirect, fails loud. */
|
|
18
|
+
function assertUnauthenticated(options) {
|
|
19
|
+
const custom = options.unauthenticated;
|
|
20
|
+
if (custom === undefined)
|
|
21
|
+
return;
|
|
22
|
+
if (options.redirectTo !== undefined) {
|
|
23
|
+
throw new Error("[nifra/auth] a guard takes redirectTo or unauthenticated, not both");
|
|
24
|
+
}
|
|
25
|
+
const code = custom.status;
|
|
26
|
+
if (code !== undefined && (!Number.isInteger(code) || code < 400 || code > 599)) {
|
|
27
|
+
throw new RangeError(`[nifra/auth] guard unauthenticated.status must be an integer 400-599 (got ${String(code)})`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const unauthenticatedResult = (custom) => {
|
|
31
|
+
if (custom === undefined)
|
|
32
|
+
return status(401, UNAUTHORIZED);
|
|
33
|
+
const body = "body" in custom ? custom.body : UNAUTHORIZED;
|
|
34
|
+
return custom.headers === undefined
|
|
35
|
+
? status(custom.status ?? 401, body)
|
|
36
|
+
: status(custom.status ?? 401, body, { headers: custom.headers });
|
|
37
|
+
};
|
|
16
38
|
const rejection = (options) => {
|
|
17
39
|
const to = options.redirectTo;
|
|
18
40
|
if (to === undefined)
|
|
19
|
-
return
|
|
41
|
+
return unauthenticatedResult(options.unauthenticated);
|
|
20
42
|
// The kernel's same-origin predicate, the one `@nifrajs/web`'s `redirect` uses: a single leading
|
|
21
43
|
// "/", never "//host", an absolute URL, or a form a URL parser resolves off-origin. `redirectTo`
|
|
22
44
|
// is dev-authored, so a bad value is a config bug - fail loud here.
|
|
@@ -32,6 +54,7 @@ const rejection = (options) => {
|
|
|
32
54
|
* `const session = requireSession(await sessions.get(c), { redirectTo: "/login" })`.
|
|
33
55
|
*/
|
|
34
56
|
export function requireSession(session, options = {}) {
|
|
57
|
+
assertUnauthenticated(options);
|
|
35
58
|
if (!session.isEmpty)
|
|
36
59
|
return session;
|
|
37
60
|
throw rejection(options);
|
|
@@ -42,6 +65,7 @@ export function requireSession(session, options = {}) {
|
|
|
42
65
|
* guard: `const userId = requireUser(await sessions.get(c), "userId", { redirectTo: "/login" })`.
|
|
43
66
|
*/
|
|
44
67
|
export function requireUser(session, key, options = {}) {
|
|
68
|
+
assertUnauthenticated(options);
|
|
45
69
|
const value = session.get(key);
|
|
46
70
|
// Narrowed by the runtime check; the generic `Data[K] | undefined` doesn't auto-narrow to NonNullable.
|
|
47
71
|
if (value !== undefined && value !== null)
|
package/dist/guards.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAuB,MAAM,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAuB,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAoBpF,MAAM,YAAY,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAW,CAAA;AAElE,uGAAuG;AACvG,SAAS,qBAAqB,CAAC,OAG9B;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAA;IACtC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAM;IAChC,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAA;IACvF,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAA;IAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,UAAU,CAClB,6EAA6E,MAAM,CAAC,IAAI,CAAC,GAAG,CAC7F,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,qBAAqB,GAAG,CAAC,MAA2C,EAAkB,EAAE;IAC5F,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;IAC1D,MAAM,IAAI,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAA;IAC1D,OAAO,MAAM,CAAC,OAAO,KAAK,SAAS;QACjC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,IAAI,CAAC;QACpC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;AACrE,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,OAAqB,EAAkB,EAAE;IAC1D,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAA;IAC7B,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,qBAAqB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IAC3E,iGAAiG;IACjG,iGAAiG;IACjG,oEAAoE;IACpE,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,sIAAsI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAC5J,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AAC9D,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAsB,EACtB,UAAwB,EAAE;IAE1B,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9B,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,OAAO,OAAO,CAAA;IACpC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,OAAsB,EACtB,GAAM,EACN,UAAwB,EAAE;IAE1B,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,uGAAuG;IACvG,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAA6B,CAAA;IAC/E,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { type AuthorizationRequest, type Authorizer, isAuthorized, requireAuthorization, } from "./authorization.js";
|
|
7
7
|
export { type CsrfOptions, csrf } from "./csrf.js";
|
|
8
|
-
export { type GuardOptions, requireSession, requireUser } from "./guards.js";
|
|
8
|
+
export { type GuardOptions, requireSession, requireUser, type UnauthenticatedResponse, } from "./guards.js";
|
|
9
9
|
export { createSessions, type Session, type SessionContext, type SessionCookieOptions, type SessionManager, type SessionOptions, } from "./session.js";
|
|
10
10
|
export { type KVNamespaceLike, KVSessionStore, MemorySessionStore, type MemorySessionStoreOptions, type SessionRecord, type SessionStore, } from "./store.js";
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,YAAY,EACZ,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,KAAK,WAAW,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,YAAY,EACZ,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,KAAK,WAAW,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACL,KAAK,YAAY,EACjB,cAAc,EACd,WAAW,EACX,KAAK,uBAAuB,GAC7B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,cAAc,EACd,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,eAAe,EACpB,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { isAuthorized, requireAuthorization, } from "./authorization.js";
|
|
7
7
|
export { csrf } from "./csrf.js";
|
|
8
|
-
export { requireSession, requireUser } from "./guards.js";
|
|
8
|
+
export { requireSession, requireUser, } from "./guards.js";
|
|
9
9
|
export { createSessions, } from "./session.js";
|
|
10
10
|
export { KVSessionStore, MemorySessionStore, } from "./store.js";
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,YAAY,EACZ,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAoB,IAAI,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,YAAY,EACZ,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAoB,IAAI,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAEL,cAAc,EACd,WAAW,GAEZ,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,cAAc,GAMf,MAAM,cAAc,CAAA;AACrB,OAAO,EAEL,cAAc,EACd,kBAAkB,GAInB,MAAM,YAAY,CAAA"}
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/session.js
CHANGED
|
@@ -103,10 +103,23 @@ export function createSessions(options) {
|
|
|
103
103
|
}
|
|
104
104
|
return state;
|
|
105
105
|
};
|
|
106
|
+
// The cookie name is signed with the value, so when two managers share a secret one's cookie does
|
|
107
|
+
// not verify as the other's. On the wire the cookie keeps its `value.signature` shape.
|
|
108
|
+
const bound = `${cookieName}\n`;
|
|
109
|
+
const sign = async (value) => (await signValue(`${bound}${value}`, secret)).slice(bound.length);
|
|
110
|
+
const unsign = async (raw) => {
|
|
111
|
+
const named = await unsignValue(`${bound}${raw}`, secret);
|
|
112
|
+
if (named !== null)
|
|
113
|
+
return named.slice(bound.length);
|
|
114
|
+
// Signed before names were bound: still accepted, so upgrading signs no one out, and re-signed
|
|
115
|
+
// bound on its next commit. Such a cookie lives at most `maxAge` past the upgrade.
|
|
116
|
+
const legacy = await unsignValue(raw, secret);
|
|
117
|
+
return legacy === null || legacy.includes("\n") ? null : legacy;
|
|
118
|
+
};
|
|
106
119
|
const loadFromRaw = async (raw) => {
|
|
107
120
|
if (raw === undefined || raw === "")
|
|
108
121
|
return make({});
|
|
109
|
-
const unsigned = await
|
|
122
|
+
const unsigned = await unsign(raw);
|
|
110
123
|
if (unsigned === null)
|
|
111
124
|
return make({}); // tampered / wrong secret → fail closed (anonymous)
|
|
112
125
|
if (store !== undefined) {
|
|
@@ -153,11 +166,11 @@ export function createSessions(options) {
|
|
|
153
166
|
if (state.id === undefined)
|
|
154
167
|
state.id = randomId();
|
|
155
168
|
await store.set(state.id, { data, expiresAt });
|
|
156
|
-
writeCookie(c, await
|
|
169
|
+
writeCookie(c, await sign(state.id), expiresAt);
|
|
157
170
|
return;
|
|
158
171
|
}
|
|
159
172
|
// Cookie mode: the (signed) payload IS the cookie. serializeCookie enforces the 4 KB cap.
|
|
160
|
-
writeCookie(c, await
|
|
173
|
+
writeCookie(c, await sign(JSON.stringify({ data, expiresAt })), expiresAt);
|
|
161
174
|
};
|
|
162
175
|
const destroy = async (c, session) => {
|
|
163
176
|
if (store !== undefined) {
|
|
@@ -170,7 +183,7 @@ export function createSessions(options) {
|
|
|
170
183
|
// first load a Session object. The signature check prevents deleting attacker-chosen IDs.
|
|
171
184
|
const raw = sessionCookie(c);
|
|
172
185
|
if (raw !== undefined)
|
|
173
|
-
id = (await
|
|
186
|
+
id = (await unsign(raw)) ?? undefined;
|
|
174
187
|
}
|
|
175
188
|
if (id !== undefined)
|
|
176
189
|
await store.delete(id);
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nifrajs/auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Session primitives for nifra - signed-cookie + server-store sessions, CSRF, and route guards. Bring your own identity (Better Auth / Lucia / OAuth); nifra owns the session.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@nifrajs/core": "^
|
|
43
|
+
"@nifrajs/core": "^5.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@nifrajs/core": "workspace:*"
|
package/src/csrf.ts
CHANGED
|
@@ -37,6 +37,10 @@ export function csrf(options: CsrfOptions = {}): Middleware {
|
|
|
37
37
|
configured !== undefined ? configured.has(candidate) : isSameOriginRequest(candidate, req)
|
|
38
38
|
|
|
39
39
|
const origin = req.headers.get("origin")
|
|
40
|
+
// Under `Referrer-Policy: no-referrer` a browser sends a same-origin form POST with
|
|
41
|
+
// `Origin: null`; its own `Sec-Fetch-Site` still says same-origin, and script can set neither.
|
|
42
|
+
if (origin === "null" && configured === undefined)
|
|
43
|
+
return req.headers.get("sec-fetch-site") === "same-origin" ? undefined : forbidden()
|
|
40
44
|
if (origin !== null) return allowed(origin) ? undefined : forbidden()
|
|
41
45
|
|
|
42
46
|
// Some same-origin requests omit `Origin` - fall back to the `Referer`'s origin.
|
package/src/guards.ts
CHANGED
|
@@ -15,15 +15,54 @@
|
|
|
15
15
|
import { isSameOriginPath, type ResponseResult, status } from "@nifrajs/core/server"
|
|
16
16
|
import type { Session } from "./session.ts"
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/** The response a guard denies a missing session with, in place of the default `401` JSON. */
|
|
19
|
+
export interface UnauthenticatedResponse {
|
|
20
|
+
/** An error status, 400-599. Default `401`. */
|
|
21
|
+
readonly status?: number
|
|
22
|
+
/** The body; present but `undefined` sends none. Default `{ ok: false, error: "unauthorized" }`. */
|
|
23
|
+
readonly body?: unknown
|
|
24
|
+
/** Response headers, such as a `www-authenticate` challenge. */
|
|
25
|
+
readonly headers?: Readonly<Record<string, string>>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** What a guard does when the check fails: 302 to `redirectTo` (a same-origin path), or - omitted - the
|
|
29
|
+
* `unauthenticated` response, by default a 401 JSON (`{ ok: false, error: "unauthorized" }`). */
|
|
20
30
|
export interface GuardOptions {
|
|
21
31
|
readonly redirectTo?: string
|
|
32
|
+
readonly unauthenticated?: UnauthenticatedResponse
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const UNAUTHORIZED = { ok: false, error: "unauthorized" } as const
|
|
36
|
+
|
|
37
|
+
/** A dev-authored denial that is not an error status, or that competes with a redirect, fails loud. */
|
|
38
|
+
function assertUnauthenticated(options: {
|
|
39
|
+
readonly redirectTo?: string
|
|
40
|
+
readonly unauthenticated?: UnauthenticatedResponse
|
|
41
|
+
}): void {
|
|
42
|
+
const custom = options.unauthenticated
|
|
43
|
+
if (custom === undefined) return
|
|
44
|
+
if (options.redirectTo !== undefined) {
|
|
45
|
+
throw new Error("[nifra/auth] a guard takes redirectTo or unauthenticated, not both")
|
|
46
|
+
}
|
|
47
|
+
const code = custom.status
|
|
48
|
+
if (code !== undefined && (!Number.isInteger(code) || code < 400 || code > 599)) {
|
|
49
|
+
throw new RangeError(
|
|
50
|
+
`[nifra/auth] guard unauthenticated.status must be an integer 400-599 (got ${String(code)})`,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const unauthenticatedResult = (custom: UnauthenticatedResponse | undefined): ResponseResult => {
|
|
56
|
+
if (custom === undefined) return status(401, UNAUTHORIZED)
|
|
57
|
+
const body = "body" in custom ? custom.body : UNAUTHORIZED
|
|
58
|
+
return custom.headers === undefined
|
|
59
|
+
? status(custom.status ?? 401, body)
|
|
60
|
+
: status(custom.status ?? 401, body, { headers: custom.headers })
|
|
22
61
|
}
|
|
23
62
|
|
|
24
63
|
const rejection = (options: GuardOptions): ResponseResult => {
|
|
25
64
|
const to = options.redirectTo
|
|
26
|
-
if (to === undefined) return
|
|
65
|
+
if (to === undefined) return unauthenticatedResult(options.unauthenticated)
|
|
27
66
|
// The kernel's same-origin predicate, the one `@nifrajs/web`'s `redirect` uses: a single leading
|
|
28
67
|
// "/", never "//host", an absolute URL, or a form a URL parser resolves off-origin. `redirectTo`
|
|
29
68
|
// is dev-authored, so a bad value is a config bug - fail loud here.
|
|
@@ -45,6 +84,7 @@ export function requireSession<Data extends Record<string, unknown>>(
|
|
|
45
84
|
session: Session<Data>,
|
|
46
85
|
options: GuardOptions = {},
|
|
47
86
|
): Session<Data> {
|
|
87
|
+
assertUnauthenticated(options)
|
|
48
88
|
if (!session.isEmpty) return session
|
|
49
89
|
throw rejection(options)
|
|
50
90
|
}
|
|
@@ -59,6 +99,7 @@ export function requireUser<Data extends Record<string, unknown>, K extends keyo
|
|
|
59
99
|
key: K,
|
|
60
100
|
options: GuardOptions = {},
|
|
61
101
|
): NonNullable<Data[K]> {
|
|
102
|
+
assertUnauthenticated(options)
|
|
62
103
|
const value = session.get(key)
|
|
63
104
|
// Narrowed by the runtime check; the generic `Data[K] | undefined` doesn't auto-narrow to NonNullable.
|
|
64
105
|
if (value !== undefined && value !== null) return value as NonNullable<Data[K]>
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,12 @@ export {
|
|
|
11
11
|
requireAuthorization,
|
|
12
12
|
} from "./authorization.ts"
|
|
13
13
|
export { type CsrfOptions, csrf } from "./csrf.ts"
|
|
14
|
-
export {
|
|
14
|
+
export {
|
|
15
|
+
type GuardOptions,
|
|
16
|
+
requireSession,
|
|
17
|
+
requireUser,
|
|
18
|
+
type UnauthenticatedResponse,
|
|
19
|
+
} from "./guards.ts"
|
|
15
20
|
export {
|
|
16
21
|
createSessions,
|
|
17
22
|
type Session,
|
package/src/session.ts
CHANGED
|
@@ -198,9 +198,23 @@ export function createSessions<Data extends Record<string, unknown> = Record<str
|
|
|
198
198
|
return state
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
// The cookie name is signed with the value, so when two managers share a secret one's cookie does
|
|
202
|
+
// not verify as the other's. On the wire the cookie keeps its `value.signature` shape.
|
|
203
|
+
const bound = `${cookieName}\n`
|
|
204
|
+
const sign = async (value: string): Promise<string> =>
|
|
205
|
+
(await signValue(`${bound}${value}`, secret)).slice(bound.length)
|
|
206
|
+
const unsign = async (raw: string): Promise<string | null> => {
|
|
207
|
+
const named = await unsignValue(`${bound}${raw}`, secret)
|
|
208
|
+
if (named !== null) return named.slice(bound.length)
|
|
209
|
+
// Signed before names were bound: still accepted, so upgrading signs no one out, and re-signed
|
|
210
|
+
// bound on its next commit. Such a cookie lives at most `maxAge` past the upgrade.
|
|
211
|
+
const legacy = await unsignValue(raw, secret)
|
|
212
|
+
return legacy === null || legacy.includes("\n") ? null : legacy
|
|
213
|
+
}
|
|
214
|
+
|
|
201
215
|
const loadFromRaw = async (raw: string | undefined): Promise<Session<Data>> => {
|
|
202
216
|
if (raw === undefined || raw === "") return make({})
|
|
203
|
-
const unsigned = await
|
|
217
|
+
const unsigned = await unsign(raw)
|
|
204
218
|
if (unsigned === null) return make({}) // tampered / wrong secret → fail closed (anonymous)
|
|
205
219
|
|
|
206
220
|
if (store !== undefined) {
|
|
@@ -253,15 +267,11 @@ export function createSessions<Data extends Record<string, unknown> = Record<str
|
|
|
253
267
|
}
|
|
254
268
|
if (state.id === undefined) state.id = randomId()
|
|
255
269
|
await store.set(state.id, { data, expiresAt } satisfies SessionRecord)
|
|
256
|
-
writeCookie(c, await
|
|
270
|
+
writeCookie(c, await sign(state.id), expiresAt)
|
|
257
271
|
return
|
|
258
272
|
}
|
|
259
273
|
// Cookie mode: the (signed) payload IS the cookie. serializeCookie enforces the 4 KB cap.
|
|
260
|
-
writeCookie(
|
|
261
|
-
c,
|
|
262
|
-
await signValue(JSON.stringify({ data, expiresAt } satisfies Payload), secret),
|
|
263
|
-
expiresAt,
|
|
264
|
-
)
|
|
274
|
+
writeCookie(c, await sign(JSON.stringify({ data, expiresAt } satisfies Payload)), expiresAt)
|
|
265
275
|
}
|
|
266
276
|
|
|
267
277
|
const destroy = async (c: SessionContext, session?: Session<Data>): Promise<void> => {
|
|
@@ -273,7 +283,7 @@ export function createSessions<Data extends Record<string, unknown> = Record<str
|
|
|
273
283
|
// Revoke the record addressed by the signed request cookie even when the caller did not
|
|
274
284
|
// first load a Session object. The signature check prevents deleting attacker-chosen IDs.
|
|
275
285
|
const raw = sessionCookie(c)
|
|
276
|
-
if (raw !== undefined) id = (await
|
|
286
|
+
if (raw !== undefined) id = (await unsign(raw)) ?? undefined
|
|
277
287
|
}
|
|
278
288
|
if (id !== undefined) await store.delete(id)
|
|
279
289
|
}
|