@alxia/react-router 0.38.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +97 -1
- package/dist/session/index.js.map +5 -4
- package/dist/session/throttle.d.ts +59 -0
- package/dist/session/throttle.d.ts.map +1 -0
- package/docs/README.md +1 -1
- package/docs/guide/session.md +61 -0
- package/docs/roadmap.md +7 -0
- package/docs/troubleshooting.md +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1034,6 +1034,27 @@ on the form. `stepUpSteps` asks for a code before a sensitive action, and
|
|
|
1034
1034
|
[session guide](https://github.com/softistx/alxia/blob/develop/packages/react-router/docs/guide/session.md)
|
|
1035
1035
|
has a complete sign-in route and the rest.
|
|
1036
1036
|
|
|
1037
|
+
A password sign-in of your own gets `createSignInThrottle` from the same
|
|
1038
|
+
subpath: failures per key within a window, a bounded number of keys, a global
|
|
1039
|
+
bucket that delays rather than locks, and a cap on concurrent password
|
|
1040
|
+
hashes. It is per process.
|
|
1041
|
+
|
|
1042
|
+
```ts
|
|
1043
|
+
import { createSignInThrottle } from '@alxia/react-router/session';
|
|
1044
|
+
|
|
1045
|
+
const throttle = createSignInThrottle({ max: 5, windowMs: 15 * 60_000 });
|
|
1046
|
+
|
|
1047
|
+
const seconds = throttle.wait(email); // 0 when allowed
|
|
1048
|
+
if (seconds > 0) return tooMany(seconds);
|
|
1049
|
+
const checked = await throttle.verify(() => Bun.password.verify(password, hash));
|
|
1050
|
+
if (checked.busy) return tryLater();
|
|
1051
|
+
if (!checked.value) {
|
|
1052
|
+
throttle.fail(email);
|
|
1053
|
+
return refused();
|
|
1054
|
+
}
|
|
1055
|
+
throttle.clear(email);
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1037
1058
|
## A GraphQL subscription for the browser
|
|
1038
1059
|
|
|
1039
1060
|
`@alxia/react-router/subscription` exposes subscriptions of your API to the
|
package/dist/session/index.d.ts
CHANGED
|
@@ -16,4 +16,5 @@ export { type SignedSession, type SignedSessionOptions, signedSession, } from '.
|
|
|
16
16
|
export { stepUpSteps } from './step-up';
|
|
17
17
|
export { STEP_UP_OVER, STEP_UP_REQUIRED } from './step-up-codes';
|
|
18
18
|
export type { StepUpCall, StepUpCodes, StepUpRun, StepUpSignIn, StepUpStayed, StepUpSteps, StepUpStepsOptions, } from './step-up-types';
|
|
19
|
+
export { createSignInThrottle, type SignInThrottle, type SignInThrottleOptions, type VerifyResult, } from './throttle';
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,cAAc,EACd,YAAY,EACZ,cAAc,EACd,eAAe,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qCAAqC,EAC1C,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,oCAAoC,EACpC,eAAe,EACf,YAAY,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EACX,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,KAAK,GACL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EACN,UAAU,EACV,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,YAAY,EACZ,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,kBAAkB,GAClB,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,cAAc,EACd,YAAY,EACZ,cAAc,EACd,eAAe,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qCAAqC,EAC1C,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,oCAAoC,EACpC,eAAe,EACf,YAAY,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EACX,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,KAAK,GACL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EACN,UAAU,EACV,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,YAAY,EACZ,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/session/index.js
CHANGED
|
@@ -850,6 +850,101 @@ function stepUpSteps(options) {
|
|
|
850
850
|
isStepUpRequired: (error) => isApiErrorLike2(error) && error.code === context.stepUpRequired
|
|
851
851
|
};
|
|
852
852
|
}
|
|
853
|
+
// src/session/throttle.ts
|
|
854
|
+
var DEFAULTS = {
|
|
855
|
+
max: 5,
|
|
856
|
+
windowMs: 15 * 60000,
|
|
857
|
+
maxKeys: 1e4,
|
|
858
|
+
globalMax: 100,
|
|
859
|
+
globalWindowMs: 60000,
|
|
860
|
+
maxConcurrentVerifies: 2,
|
|
861
|
+
maxQueuedVerifies: 4
|
|
862
|
+
};
|
|
863
|
+
function positive(name, value, allowZero = false) {
|
|
864
|
+
const ok = Number.isInteger(value) && (allowZero ? value >= 0 : value > 0);
|
|
865
|
+
if (!ok) {
|
|
866
|
+
throw new TypeError(`createSignInThrottle(): ${name} must be a positive integer${allowZero ? " or 0" : ""}; got ${String(value)}.`);
|
|
867
|
+
}
|
|
868
|
+
return value;
|
|
869
|
+
}
|
|
870
|
+
function createSignInThrottle(options = {}) {
|
|
871
|
+
const max = positive("max", options.max ?? DEFAULTS.max);
|
|
872
|
+
const windowMs = positive("windowMs", options.windowMs ?? DEFAULTS.windowMs);
|
|
873
|
+
const maxKeys = positive("maxKeys", options.maxKeys ?? DEFAULTS.maxKeys);
|
|
874
|
+
const globalMax = positive("globalMax", options.globalMax ?? DEFAULTS.globalMax);
|
|
875
|
+
const globalWindowMs = positive("globalWindowMs", options.globalWindowMs ?? DEFAULTS.globalWindowMs);
|
|
876
|
+
const slots = positive("maxConcurrentVerifies", options.maxConcurrentVerifies ?? DEFAULTS.maxConcurrentVerifies);
|
|
877
|
+
const queueLimit = positive("maxQueuedVerifies", options.maxQueuedVerifies ?? DEFAULTS.maxQueuedVerifies, true);
|
|
878
|
+
const now = options.now ?? Date.now;
|
|
879
|
+
const failures = new Map;
|
|
880
|
+
let global = [];
|
|
881
|
+
const recent = (key, at) => {
|
|
882
|
+
const kept = (failures.get(key) ?? []).filter((time) => at - time < windowMs);
|
|
883
|
+
if (kept.length === 0)
|
|
884
|
+
failures.delete(key);
|
|
885
|
+
return kept;
|
|
886
|
+
};
|
|
887
|
+
const seconds = (ms) => Math.ceil(ms / 1000);
|
|
888
|
+
let running = 0;
|
|
889
|
+
const queue = [];
|
|
890
|
+
const release = () => {
|
|
891
|
+
const next = queue.shift();
|
|
892
|
+
if (next)
|
|
893
|
+
next();
|
|
894
|
+
else
|
|
895
|
+
running--;
|
|
896
|
+
};
|
|
897
|
+
return {
|
|
898
|
+
wait(key) {
|
|
899
|
+
const at = now();
|
|
900
|
+
let wait = 0;
|
|
901
|
+
const kept = recent(key, at);
|
|
902
|
+
if (kept.length >= max) {
|
|
903
|
+
wait = seconds(windowMs - (at - kept[0]));
|
|
904
|
+
}
|
|
905
|
+
global = global.filter((time) => at - time < globalWindowMs);
|
|
906
|
+
if (global.length >= globalMax) {
|
|
907
|
+
wait = Math.max(wait, seconds(globalWindowMs - (at - global[0])));
|
|
908
|
+
}
|
|
909
|
+
return wait;
|
|
910
|
+
},
|
|
911
|
+
fail(key) {
|
|
912
|
+
const at = now();
|
|
913
|
+
const kept = [...recent(key, at), at].slice(-max);
|
|
914
|
+
failures.delete(key);
|
|
915
|
+
failures.set(key, kept);
|
|
916
|
+
if (failures.size > maxKeys) {
|
|
917
|
+
const oldest = failures.keys().next().value;
|
|
918
|
+
if (oldest !== undefined)
|
|
919
|
+
failures.delete(oldest);
|
|
920
|
+
}
|
|
921
|
+
global = [
|
|
922
|
+
...global.filter((time) => at - time < globalWindowMs),
|
|
923
|
+
at
|
|
924
|
+
].slice(-globalMax);
|
|
925
|
+
},
|
|
926
|
+
clear(key) {
|
|
927
|
+
failures.delete(key);
|
|
928
|
+
},
|
|
929
|
+
async verify(task) {
|
|
930
|
+
if (running >= slots) {
|
|
931
|
+
if (queue.length >= queueLimit)
|
|
932
|
+
return { busy: true };
|
|
933
|
+
await new Promise((resolve) => queue.push(resolve));
|
|
934
|
+
} else {
|
|
935
|
+
running++;
|
|
936
|
+
}
|
|
937
|
+
try {
|
|
938
|
+
return { busy: false, value: await task() };
|
|
939
|
+
} finally {
|
|
940
|
+
release();
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
get size() {
|
|
944
|
+
return failures.size;
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
}
|
|
853
948
|
export {
|
|
854
949
|
CHALLENGE_OVER,
|
|
855
950
|
INVALID_CODE,
|
|
@@ -859,6 +954,7 @@ export {
|
|
|
859
954
|
TOKEN_PAGE_HEADERS,
|
|
860
955
|
UNAUTHENTICATED,
|
|
861
956
|
authLinks,
|
|
957
|
+
createSignInThrottle,
|
|
862
958
|
readCookie,
|
|
863
959
|
secondsUntil,
|
|
864
960
|
serializeCookie,
|
|
@@ -868,5 +964,5 @@ export {
|
|
|
868
964
|
stepUpSteps
|
|
869
965
|
};
|
|
870
966
|
|
|
871
|
-
//# debugId=
|
|
967
|
+
//# debugId=30B84BDDE86DDE4164756E2164756E21
|
|
872
968
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/session/codes.ts", "../src/session/serialize.ts", "../src/session/cookies.ts", "../src/session/link-token.ts", "../src/session/guard.ts", "../src/session/links.ts", "../src/session/link-land.ts", "../src/session/land.ts", "../src/session/second-factor.ts", "../src/session/step.ts", "../src/session/viewer.ts", "../src/session/sign-in.ts", "../src/session/signed.ts", "../src/session/step-up.ts", "../src/session/step-up-codes.ts", "../src/session/step-up-signed-out.ts"],
|
|
3
|
+
"sources": ["../src/session/codes.ts", "../src/session/serialize.ts", "../src/session/cookies.ts", "../src/session/link-token.ts", "../src/session/guard.ts", "../src/session/links.ts", "../src/session/link-land.ts", "../src/session/land.ts", "../src/session/second-factor.ts", "../src/session/step.ts", "../src/session/viewer.ts", "../src/session/sign-in.ts", "../src/session/signed.ts", "../src/session/step-up.ts", "../src/session/step-up-codes.ts", "../src/session/step-up-signed-out.ts", "../src/session/throttle.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/** `@nxgt/janus`'s code for a wrong second-factor or step-up code. */\nexport const INVALID_CODE = 'CODE_INVALID';\n\n/** `@nxgt/janus`'s codes for a challenge that is gone: unknown, spent or expired. */\nexport const CHALLENGE_OVER = [\n\t'TOKEN_UNKNOWN',\n\t'TOKEN_SPENT',\n\t'TOKEN_EXPIRED',\n] as const;\n\n/** `@nxgt/janus`'s code for a mail the API holds back: a link or a code asked for too often. */\nexport const MAIL_THROTTLED = 'MAIL_THROTTLED';\n\n/** The code of an API answer for no session, or a dead one. */\nexport const UNAUTHENTICATED = 'UNAUTHENTICATED';\n",
|
|
6
6
|
"/**\n * The bytes of a cookie, and the reading of one: `Name=v; Max-Age=n; Path=/;\n * HttpOnly[; Secure]; SameSite=Lax`, in this order, so a session set by an\n * app before it adopted this package is still read after, and the other way\n * round.\n */\n\nexport interface SerializeOptions {\n\t/** Seconds; floored, and never below 0 (0 removes the cookie, and so does a value that is not finite). */\n\treadonly maxAge: number;\n\t/** `/` by default. */\n\treadonly path?: string | undefined;\n\t/** Adds `Secure`. Required: it is never read from the environment. */\n\treadonly secure: boolean;\n\t/** `'lax'` by default. `'none'` needs `secure`. */\n\treadonly sameSite?: SameSite | undefined;\n}\n\n/** The `SameSite` attribute of a cookie. */\nexport type SameSite = 'lax' | 'strict' | 'none';\n\nconst SAME_SITE = { lax: 'Lax', strict: 'Strict', none: 'None' } as const;\n\n/** Throws a `TypeError` for a `SameSite` the package does not write, or `none` without `Secure`. */\nexport function checkSameSite(\n\tcaller: string,\n\tsameSite: string,\n\tsecure: boolean,\n): asserts sameSite is SameSite {\n\tif (!Object.hasOwn(SAME_SITE, sameSite)) {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: sameSite must be \"lax\", \"strict\" or \"none\"; got ${JSON.stringify(sameSite)}.`,\n\t\t);\n\t}\n\tif (sameSite === 'none' && !secure) {\n\t\tthrow new TypeError(\n\t\t\t`${caller}: sameSite \"none\" needs secure: true, since a browser drops a SameSite=None cookie without Secure.`,\n\t\t);\n\t}\n}\n\n// RFC 6265 `token`: what a cookie name may be made of.\nconst TOKEN = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n// A path of the site: no `;` to open another attribute, no control character.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: that is the point\nconst PATH = /^\\/[^;\\x00-\\x1f\\x7f]*$/;\n\n/** Whether `name` can name a cookie (an RFC 6265 token). */\nexport const isCookieName = (name: string): boolean => TOKEN.test(name);\n/** Whether `path` can be a cookie's `Path`: absolute, no `;`, no control character. */\nexport const isCookiePath = (path: string): boolean => PATH.test(path);\n\n/**\n * A `Set-Cookie` value: always `HttpOnly`, `SameSite=Lax` unless `sameSite`\n * says otherwise, `Secure` when asked. A name or a path that could open another attribute throws a\n * `TypeError`; a `maxAge` that is not finite is 0.\n */\nexport function serializeCookie(\n\tname: string,\n\tvalue: string,\n\t{ maxAge, path = '/', secure, sameSite = 'lax' }: SerializeOptions,\n): string {\n\tif (!isCookieName(name)) {\n\t\tthrow new TypeError(\n\t\t\t`serializeCookie(): the name ${JSON.stringify(name)} is not a cookie name (an RFC 6265 token).`,\n\t\t);\n\t}\n\tif (!isCookiePath(path)) {\n\t\tthrow new TypeError(\n\t\t\t`serializeCookie(): the path ${JSON.stringify(path)} is not a cookie path: it must start with \"/\" and hold no \";\" or control character.`,\n\t\t);\n\t}\n\tcheckSameSite('serializeCookie():', sameSite, secure);\n\treturn [\n\t\t`${name}=${encodeURIComponent(value)}`,\n\t\t`Max-Age=${Number.isFinite(maxAge) ? Math.max(0, Math.floor(maxAge)) : 0}`,\n\t\t`Path=${path}`,\n\t\t'HttpOnly',\n\t\t...(secure ? ['Secure'] : []),\n\t\t`SameSite=${SAME_SITE[sameSite]}`,\n\t].join('; ');\n}\n\n/**\n * A cookie of the request: the first one of that name that is not empty,\n * decoded; `null` when there is none, or when it is not valid percent-encoding.\n */\nexport function readCookie(request: Request, name: string): string | null {\n\tfor (const pair of request.headers.get('cookie')?.split(';') ?? []) {\n\t\tconst index = pair.indexOf('=');\n\t\tif (index < 0 || pair.slice(0, index).trim() !== name) continue;\n\t\tconst raw = pair.slice(index + 1).trim();\n\t\tif (!raw) continue;\n\t\ttry {\n\t\t\treturn decodeURIComponent(raw);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** An instant as milliseconds; 0 when it is not a date. */\nexport function millisOf(at: string | Date): number {\n\tconst time = typeof at === 'string' ? Date.parse(at) : at.getTime();\n\treturn Number.isNaN(time) ? 0 : time;\n}\n\n/** Seconds from `now` until `expiresAt`: 0 when past or unreadable. */\nexport function secondsUntil(\n\texpiresAt: string | Date,\n\tnow: number = Date.now(),\n): number {\n\tconst end = millisOf(expiresAt);\n\treturn end === 0 ? 0 : Math.max(0, (end - now) / 1000);\n}\n",
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
"import {\n\tcheckSameSite,\n\tisCookieName,\n\treadCookie,\n\ttype SameSite,\n\tserializeCookie,\n} from './serialize';\n\n/** What `signedSession` takes. */\nexport interface SignedSessionOptions {\n\t/** The HMAC key: at least 32 characters, from the environment, never committed. Changing it signs everyone out. */\n\treadonly secret: string;\n\t/** The base name of the cookie, e.g. `'my-app_operator'`; `__Host-` is added when `secure`. */\n\treadonly name: string;\n\t/** How long a session lasts, in seconds: a positive integer. It is the cookie's `Max-Age` and, signed, its expiry. */\n\treadonly maxAge: number;\n\t/** The app is served over HTTPS. Required, never read from the environment: pass `!import.meta.env.DEV`. */\n\treadonly secure: boolean;\n\t/** `'lax'` by default. */\n\treadonly sameSite?: SameSite | undefined;\n}\n\n/** A signed, stateless session: no token, no store. */\nexport interface SignedSession {\n\t/** The cookie name as sent, prefix included. */\n\treadonly name: string;\n\t/** A `Set-Cookie` value starting a session of `maxAge` seconds from `now`. */\n\tcommit(now?: number): Promise<string>;\n\t/** A `Set-Cookie` value removing the cookie. */\n\tdestroy(): string;\n\t/** Whether the request carries an unexpired cookie this secret signed. */\n\tvalid(request: Request, now?: number): Promise<boolean>;\n}\n\nconst MIN_SECRET = 32;\nconst MAC_LENGTH = 43; // 32 bytes, base64url, unpadded\nconst DIGITS = /^\\d{1,16}$/;\n\nconst encoder = new TextEncoder();\n\nconst base64url = (bytes: Uint8Array): string =>\n\tbtoa(String.fromCharCode(...bytes))\n\t\t.replaceAll('+', '-')\n\t\t.replaceAll('/', '_')\n\t\t.replaceAll('=', '');\n\n// Web Crypto, not `node:crypto`: the subpath imports `react-router` alone.\nconst keyOf = (secret: string): Promise<CryptoKey> =>\n\tcrypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\nasync function sign(key: CryptoKey, payload: string): Promise<string> {\n\tconst mac = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));\n\treturn base64url(new Uint8Array(mac));\n}\n\n// Every byte is compared, whatever the first difference: the lengths are equal.\nfunction sameBytes(a: string, b: string): boolean {\n\tif (a.length !== b.length) return false;\n\tlet difference = 0;\n\tfor (let index = 0; index < a.length; index++) {\n\t\tdifference |= a.charCodeAt(index) ^ b.charCodeAt(index);\n\t}\n\treturn difference === 0;\n}\n\n/**\n * The session of a single local operator with no identity provider: the\n * cookie holds `<expiresAt ms>.<nonce>.<mac>`, the MAC an HMAC-SHA256 of\n * `<expiresAt>.<nonce>`, so the expiry cannot be moved without the secret.\n * `valid` checks it in constant time and never throws. Both are async (Web Crypto).\n *\n * @example\n * const operator = signedSession({\n * secret: process.env.SESSION_SECRET!,\n * name: 'my-app_operator',\n * maxAge: 8 * 3600,\n * secure: !import.meta.env.DEV,\n * sameSite: 'strict',\n * });\n * // after the password was checked: headers.append('Set-Cookie', await operator.commit())\n * // in a loader: if (!(await operator.valid(request))) throw redirect('/sign-in')\n */\nexport function signedSession(options: SignedSessionOptions): SignedSession {\n\tconst { secret, name: base, maxAge, secure, sameSite = 'lax' } = options;\n\tif (typeof secret !== 'string' || secret.length < MIN_SECRET) {\n\t\tthrow new TypeError(\n\t\t\t`signedSession(): secret must be a string of at least ${MIN_SECRET} characters.`,\n\t\t);\n\t}\n\tif (!isCookieName(base) || /^__(?:Host|Secure)-/.test(base)) {\n\t\tthrow new TypeError(\n\t\t\t`signedSession(): the name ${JSON.stringify(base)} must be an RFC 6265 token without a __Host- or __Secure- prefix; the package adds __Host- when secure is true.`,\n\t\t);\n\t}\n\tif (!Number.isInteger(maxAge) || maxAge <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`signedSession(): maxAge must be a positive integer of seconds; got ${String(maxAge)}.`,\n\t\t);\n\t}\n\tcheckSameSite('signedSession():', sameSite, secure);\n\t// `__Host-` holds with `Path=/` and no `Domain`, which the cookie sets.\n\tconst name = secure ? `__Host-${base}` : base;\n\tconst key = keyOf(secret);\n\n\treturn {\n\t\tname,\n\t\tasync commit(now = Date.now()) {\n\t\t\tconst nonce = base64url(crypto.getRandomValues(new Uint8Array(16)));\n\t\t\tconst payload = `${now + maxAge * 1000}.${nonce}`;\n\t\t\treturn serializeCookie(\n\t\t\t\tname,\n\t\t\t\t`${payload}.${await sign(await key, payload)}`,\n\t\t\t\t{\n\t\t\t\t\tmaxAge,\n\t\t\t\t\tsecure,\n\t\t\t\t\tsameSite,\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\tdestroy: () => serializeCookie(name, '', { maxAge: 0, secure, sameSite }),\n\t\tasync valid(request, now = Date.now()) {\n\t\t\tconst value = readCookie(request, name);\n\t\t\tconst parts = value?.split('.') ?? [];\n\t\t\tif (parts.length !== 3) return false;\n\t\t\tconst [digits, nonce, mac] = parts as [string, string, string];\n\t\t\tif (mac.length !== MAC_LENGTH || !nonce || !DIGITS.test(digits)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst expected = await sign(await key, `${digits}.${nonce}`);\n\t\t\tif (!sameBytes(mac, expected)) return false;\n\t\t\treturn Number(digits) > now;\n\t\t},\n\t};\n}\n",
|
|
18
18
|
"import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n\tretryAfterOf,\n} from '../errors/api-error';\nimport { INVALID_CODE, MAIL_THROTTLED, UNAUTHENTICATED } from './codes';\nimport type { CodeWording } from './flow-types';\nimport { samesitePost } from './guard';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n\tStepUpVia,\n} from './model';\nimport { codeRefusal } from './step';\nimport { STEP_UP_OVER, STEP_UP_REQUIRED } from './step-up-codes';\nimport { signingOut } from './step-up-signed-out';\nimport type {\n\tStepUpRun,\n\tStepUpStayed,\n\tStepUpSteps,\n\tStepUpStepsOptions,\n} from './step-up-types';\n\ntype Refused = Extract<StepUpConfirmAnswer, { ok: false }>;\n\ninterface StepUpContext<L extends string, C> extends CodeWording<L> {\n\treadonly steps: StepUpStepsOptions<L, C>;\n\t/** The sign-in's redirect, bound; `resolve` makes sure `onSignedOut` has one. */\n\treadonly signInRedirect: ((request: Request) => Response) | undefined;\n\treadonly stepUpRequired: string;\n\treadonly mailThrottled: string;\n\treadonly unauthenticated: string;\n}\n\nfunction resolve<L extends string, C>(\n\tsteps: StepUpStepsOptions<L, C>,\n): StepUpContext<L, C> {\n\tconst invalidCode = steps.codes?.invalidCode ?? INVALID_CODE;\n\tconst challengeOver = steps.codes?.challengeOver ?? STEP_UP_OVER;\n\tif (challengeOver.includes(invalidCode)) {\n\t\tthrow new TypeError(\n\t\t\t`stepUpSteps(): the code ${JSON.stringify(invalidCode)} is both the wrong-code code (codes.invalidCode) and in codes.challengeOver. A wrong code that leaves tries cannot end the challenge.`,\n\t\t);\n\t}\n\tif (steps.onSignedOut === 'sign-in' && !steps.signIn.signInRedirect) {\n\t\tthrow new TypeError(\n\t\t\t\"stepUpSteps(): onSignedOut: 'sign-in' needs signIn.signInRedirect, which the sign-in given has not.\",\n\t\t);\n\t}\n\tconst { signIn } = steps;\n\treturn {\n\t\toptions: signIn,\n\t\tsignInRedirect: signIn.signInRedirect?.bind(signIn),\n\t\tsteps,\n\t\tinvalidCode,\n\t\tchallengeOver,\n\t\tstepUpRequired: steps.codes?.stepUpRequired ?? STEP_UP_REQUIRED,\n\t\tmailThrottled: steps.codes?.mailThrottled ?? MAIL_THROTTLED,\n\t\tunauthenticated: steps.codes?.unauthenticated ?? UNAUTHENTICATED,\n\t};\n}\n\n/** The refusal's message: the app's own wording, else `errors`'. */\nfunction worded<L extends string, C>(\n\t{ steps }: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n): string {\n\treturn (\n\t\tsteps.wording?.(error, language) ??\n\t\tsteps.signIn.errors.apiErrorMessage(error, language)\n\t);\n}\n\n/** A code the API refused. With none left, a mailed one is over and an app's is locked. */\nfunction refusedCode<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tvia: StepUpVia | undefined,\n\tlanguage: L,\n): Omit<Refused, 'ok' | 'intent'> {\n\tconst { steps } = context;\n\tconst attemptsLeft = attemptsLeftOf(error);\n\tif (attemptsLeft === 0 && via !== 'secondFactor') {\n\t\treturn {\n\t\t\terror: 'expired',\n\t\t\tattemptsLeft,\n\t\t\tlocked: false,\n\t\t\tmessage: steps.spent(language),\n\t\t};\n\t}\n\tconst locked = attemptsLeft === 0;\n\tconst message =\n\t\tcodeRefusal(\n\t\t\tcontext,\n\t\t\terror,\n\t\t\tlanguage,\n\t\t\tlocked ? steps.locked?.(language) : undefined,\n\t\t) ?? steps.signIn.errors.apiErrorMessage(error, language);\n\treturn {\n\t\terror: 'invalid',\n\t\t...(attemptsLeft === undefined ? {} : { attemptsLeft }),\n\t\tlocked,\n\t\tmessage,\n\t};\n}\n\n/** The mail throttle's code, or any 429: a rate limit asks to wait, whatever its code. */\nfunction isThrottle<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n): boolean {\n\treturn error.status === 429 || error.code === context.mailThrottled;\n}\n\nasync function requestStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: Parameters<StepUpSteps<L>['request']>[0],\n\t{ request, language }: Parameters<StepUpSteps<L>['request']>[1],\n): Promise<StepUpRequestAnswer | StepUpStayed<StepUpRequestAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'request-step-up';\n\ttry {\n\t\tconst { challenge, via } = await run();\n\t\treturn { ok: true, intent, challenge, via };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst api = isApiErrorLike(error);\n\t\tconst message = api ? worded(context, error, language) : refusal.message;\n\t\tconst throttled = api && isThrottle(context, error);\n\t\tconst retryAfter = throttled ? retryAfterOf(error) : undefined;\n\t\treturn data<StepUpRequestAnswer>(\n\t\t\t{\n\t\t\t\tok: false,\n\t\t\t\tintent,\n\t\t\t\terror: throttled ? 'throttled' : 'failed',\n\t\t\t\tmessage,\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t},\n\t\t\t{ status: refusal.status },\n\t\t);\n\t}\n}\n\nasync function confirmStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: () => Promise<unknown>,\n\t{ request, language, via }: Parameters<StepUpSteps<L>['confirm']>[1],\n): Promise<StepUpConfirmAnswer | StepUpStayed<StepUpConfirmAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'confirm-step-up';\n\ttry {\n\t\tawait run();\n\t\treturn { ok: true, intent };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst stay = (\n\t\t\tfailure: Omit<Refused, 'ok' | 'intent'>,\n\t\t): StepUpStayed<StepUpConfirmAnswer> =>\n\t\t\tdata<StepUpConfirmAnswer>(\n\t\t\t\t{ ok: false, intent, ...failure },\n\t\t\t\t{ status: refusal.status },\n\t\t\t);\n\t\tconst failed = (message: string) =>\n\t\t\tstay({ error: 'failed' satisfies StepUpError, locked: false, message });\n\t\tif (!isApiErrorLike(error)) return failed(refusal.message);\n\t\tif (error.status === 429) {\n\t\t\tconst retryAfter = retryAfterOf(error);\n\t\t\treturn stay({\n\t\t\t\terror: 'throttled',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage: worded(context, error, language),\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t});\n\t\t}\n\t\tif (error.code === context.invalidCode) {\n\t\t\treturn stay(refusedCode(context, error, via, language));\n\t\t}\n\t\tif (error.code && context.challengeOver.includes(error.code)) {\n\t\t\treturn stay({\n\t\t\t\terror: 'expired',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage:\n\t\t\t\t\tcontext.steps.wording?.(error, language) ??\n\t\t\t\t\tcontext.steps.spent(language),\n\t\t\t});\n\t\t}\n\t\treturn failed(worded(context, error, language));\n\t}\n}\n\nasync function routeStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: StepUpRun,\n\tcall: Parameters<StepUpSteps<L>['request']>[1],\n) {\n\tconst { json } = context.steps.signIn;\n\tsamesitePost(json, call.request);\n\tif (context.steps.onSignedOut !== 'sign-in')\n\t\treturn routeIntent(context, run, call);\n\tconst redirect = context.signInRedirect;\n\tif (!redirect) return routeIntent(context, run, call);\n\treturn signingOut(\n\t\t{\n\t\t\tsignIn: { signInRedirect: redirect },\n\t\t\tunauthenticated: context.unauthenticated,\n\t\t\trun,\n\t\t\trequest: call.request,\n\t\t},\n\t\t(watched) => routeIntent(context, watched, call),\n\t);\n}\n\nasync function routeIntent<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: StepUpRun,\n\tcall: Parameters<StepUpSteps<L>['request']>[1],\n) {\n\tconst { json } = context.steps.signIn;\n\tconst body = (await json.readJson(call.request)) as {\n\t\tintent?: unknown;\n\t\tchallenge?: unknown;\n\t\tcode?: unknown;\n\t\tvia?: unknown;\n\t} | null;\n\tif (body?.intent === 'request-step-up') {\n\t\treturn requestStep(context, () => run.request(), call);\n\t}\n\tif (\n\t\tbody?.intent === 'confirm-step-up' &&\n\t\ttypeof body.challenge === 'string' &&\n\t\ttypeof body.code === 'string'\n\t) {\n\t\tconst { challenge, code } = body;\n\t\tconst via =\n\t\t\tbody.via === 'email' || body.via === 'secondFactor'\n\t\t\t\t? body.via\n\t\t\t\t: undefined;\n\t\treturn confirmStep(context, () => run.confirm({ challenge, code }), {\n\t\t\t...call,\n\t\t\tvia,\n\t\t});\n\t}\n\tthrow data('Not a step-up intent', { status: 400 });\n}\n\n/**\n * The server side of a BFF's step-up: `request` and `confirm` answer the\n * page's fetcher with `StepUpRequestAnswer` and `StepUpConfirmAnswer`, which\n * `stepUpReducer` takes as they are. It speaks `@nxgt/janus`'s words\n * (`CODE_INVALID`, `TOKEN_*`, `STEP_UP_REQUIRED`); the app maps the rest.\n *\n * @example\n * const stepUp = stepUpSteps({\n * \terrors,\n * \tattemptsLeft: (count, language) => t('code.attempts-left', { count }, language),\n * \tspent: (language) => t('step-up.spent', {}, language),\n * \tlocked: (language) => t('step-up.locked', {}, language),\n * });\n */\nexport function stepUpSteps<L extends string, C = undefined>(\n\toptions: StepUpStepsOptions<L, C>,\n): StepUpSteps<L> {\n\tconst context = resolve(options);\n\treturn {\n\t\trequest: (run, o) => requestStep(context, run, o),\n\t\tconfirm: (run, o) => confirmStep(context, run, o),\n\t\troute: (run, o) => routeStep(context, run, o),\n\t\tisStepUpRequired: (error) =>\n\t\t\tisApiErrorLike(error) && error.code === context.stepUpRequired,\n\t};\n}\n",
|
|
19
19
|
"import { CHALLENGE_OVER } from './codes';\n\n/** `@nxgt/janus`'s code for a mutation that needs a recent step-up. */\nexport const STEP_UP_REQUIRED = 'STEP_UP_REQUIRED';\n\n/**\n * The codes that end a step-up's challenge: unknown, spent, expired or stale,\n * and a second factor that changed since the request (`SECOND_FACTOR_ACTIVE`,\n * `SECOND_FACTOR_NOT_ENROLLED`). The user asks again.\n */\nexport const STEP_UP_OVER = [\n\t...CHALLENGE_OVER,\n\t'TOKEN_STALE',\n\t'SECOND_FACTOR_ACTIVE',\n\t'SECOND_FACTOR_NOT_ENROLLED',\n] as const;\n",
|
|
20
|
-
"import { isApiErrorLike } from '../errors/api-error';\nimport type { SignInFlow } from './flow-types';\nimport type { StepUpRun } from './step-up-types';\n\n/**\n * A signed-out user's failure. From `request`, the API's no-session code or a\n * bare 401 response; from `confirm`, the code only: a 401 there is also what a\n * wrong code answers, so a bare one stays a refusal.\n */\nfunction isSignedOut(\n\terror: unknown,\n\tunauthenticated: string,\n\tfrom: 'request' | 'confirm',\n): boolean {\n\tif (error instanceof Response)\n\t\treturn from === 'request' && error.status === 401;\n\treturn isApiErrorLike(error) && error.code === unauthenticated;\n}\n\n/**\n * The request the sign-in redirect comes back to: the same-site `Referer`'s\n * page (the step-up route has none of its own), else the request's own URL.\n * A `Referer` of another origin (port and protocol count), or one that is not\n * a URL, is ignored. Behind a TLS-terminating proxy an `http` `request.url`\n * never matches an `https` `Referer`, so `next` is the route's own path.\n */\nexport function cameFrom(request: Request): Request {\n\tconst referer = request.headers.get('referer');\n\tif (referer) {\n\t\ttry {\n\t\t\tconst from = new URL(referer);\n\t\t\tif (from.origin === new URL(request.url).origin) {\n\t\t\t\treturn new Request(from, { headers: request.headers });\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not a URL: the request's own path.\n\t\t}\n\t}\n\treturn request;\n}\n\n/**\n * Runs `route` over a `run` that notes a signed-out failure, then throws the\n * flow's sign-in redirect in place of whatever the step answered or threw.\n */\nexport async function signingOut<A>(\n\t{\n\t\tsignIn,\n\t\tunauthenticated,\n\t\trun,\n\t\trequest,\n\t}: {\n\t\treadonly signIn: Pick<SignInFlow<string, never>, 'signInRedirect'>;\n\t\treadonly unauthenticated: string;\n\t\treadonly run: StepUpRun;\n\t\treadonly request: Request;\n\t},\n\troute: (watched: StepUpRun) => Promise<A>,\n): Promise<A> {\n\tlet signedOut = false;\n\tconst watched: StepUpRun = {\n\t\trequest: async () => {\n\t\t\ttry {\n\t\t\t\treturn await run.request();\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'request');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tconfirm: async (input) => {\n\t\t\ttry {\n\t\t\t\treturn await run.confirm(input);\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'confirm');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n\tconst redirect = () => signIn.signInRedirect(cameFrom(request));\n\tlet answer: A;\n\ttry {\n\t\tanswer = await route(watched);\n\t} catch (error) {\n\t\tthrow signedOut ? redirect() : error;\n\t}\n\tif (signedOut) throw redirect();\n\treturn answer;\n}\n"
|
|
20
|
+
"import { isApiErrorLike } from '../errors/api-error';\nimport type { SignInFlow } from './flow-types';\nimport type { StepUpRun } from './step-up-types';\n\n/**\n * A signed-out user's failure. From `request`, the API's no-session code or a\n * bare 401 response; from `confirm`, the code only: a 401 there is also what a\n * wrong code answers, so a bare one stays a refusal.\n */\nfunction isSignedOut(\n\terror: unknown,\n\tunauthenticated: string,\n\tfrom: 'request' | 'confirm',\n): boolean {\n\tif (error instanceof Response)\n\t\treturn from === 'request' && error.status === 401;\n\treturn isApiErrorLike(error) && error.code === unauthenticated;\n}\n\n/**\n * The request the sign-in redirect comes back to: the same-site `Referer`'s\n * page (the step-up route has none of its own), else the request's own URL.\n * A `Referer` of another origin (port and protocol count), or one that is not\n * a URL, is ignored. Behind a TLS-terminating proxy an `http` `request.url`\n * never matches an `https` `Referer`, so `next` is the route's own path.\n */\nexport function cameFrom(request: Request): Request {\n\tconst referer = request.headers.get('referer');\n\tif (referer) {\n\t\ttry {\n\t\t\tconst from = new URL(referer);\n\t\t\tif (from.origin === new URL(request.url).origin) {\n\t\t\t\treturn new Request(from, { headers: request.headers });\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not a URL: the request's own path.\n\t\t}\n\t}\n\treturn request;\n}\n\n/**\n * Runs `route` over a `run` that notes a signed-out failure, then throws the\n * flow's sign-in redirect in place of whatever the step answered or threw.\n */\nexport async function signingOut<A>(\n\t{\n\t\tsignIn,\n\t\tunauthenticated,\n\t\trun,\n\t\trequest,\n\t}: {\n\t\treadonly signIn: Pick<SignInFlow<string, never>, 'signInRedirect'>;\n\t\treadonly unauthenticated: string;\n\t\treadonly run: StepUpRun;\n\t\treadonly request: Request;\n\t},\n\troute: (watched: StepUpRun) => Promise<A>,\n): Promise<A> {\n\tlet signedOut = false;\n\tconst watched: StepUpRun = {\n\t\trequest: async () => {\n\t\t\ttry {\n\t\t\t\treturn await run.request();\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'request');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tconfirm: async (input) => {\n\t\t\ttry {\n\t\t\t\treturn await run.confirm(input);\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'confirm');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n\tconst redirect = () => signIn.signInRedirect(cameFrom(request));\n\tlet answer: A;\n\ttry {\n\t\tanswer = await route(watched);\n\t} catch (error) {\n\t\tthrow signedOut ? redirect() : error;\n\t}\n\tif (signedOut) throw redirect();\n\treturn answer;\n}\n",
|
|
21
|
+
"/** What `createSignInThrottle` takes; every field has a default. */\nexport interface SignInThrottleOptions {\n\t/** Failures one key may make within `windowMs` before it waits. 5 by default. */\n\treadonly max?: number | undefined;\n\t/** The per-key window, in milliseconds. 15 minutes by default. */\n\treadonly windowMs?: number | undefined;\n\t/** How many keys are held; past it the oldest is dropped. 10 000 by default. */\n\treadonly maxKeys?: number | undefined;\n\t/** Failures, all keys together, within `globalWindowMs` before every sign-in is delayed. 100 by default. */\n\treadonly globalMax?: number | undefined;\n\t/** The global window, in milliseconds: also the longest the global delay lasts. 1 minute by default. */\n\treadonly globalWindowMs?: number | undefined;\n\t/** Password verifications that run at once. 2 by default. */\n\treadonly maxConcurrentVerifies?: number | undefined;\n\t/** Verifications that wait for a slot; past it `verify` answers `{ busy: true }`. 4 by default; 0 for none. */\n\treadonly maxQueuedVerifies?: number | undefined;\n\t/** The clock, in milliseconds. `Date.now` by default; inject one in a test. */\n\treadonly now?: (() => number) | undefined;\n}\n\n/** What `verify` answers: the task's value, or a refusal because the queue was full. */\nexport type VerifyResult<T> =\n\t| { readonly busy: false; readonly value: T }\n\t| { readonly busy: true };\n\n/** A per-process sign-in throttle. */\nexport interface SignInThrottle {\n\t/** Seconds to wait before this key may try again, 0 when it may. Records nothing. */\n\twait(key: string): number;\n\t/** Record a failed attempt for the key (and in the global bucket). */\n\tfail(key: string): void;\n\t/** Forget the key's failures after a successful sign-in. The global bucket is left alone. */\n\tclear(key: string): void;\n\t/** Run a password verification under the concurrency limit, or refuse when the wait queue is full. A rejection of `task` passes through and frees its slot. */\n\tverify<T>(task: () => Promise<T>): Promise<VerifyResult<T>>;\n\t/** How many keys are held now. */\n\treadonly size: number;\n}\n\nconst DEFAULTS = {\n\tmax: 5,\n\twindowMs: 15 * 60_000,\n\tmaxKeys: 10_000,\n\tglobalMax: 100,\n\tglobalWindowMs: 60_000,\n\tmaxConcurrentVerifies: 2,\n\tmaxQueuedVerifies: 4,\n} as const;\n\nfunction positive(name: string, value: number, allowZero = false): number {\n\tconst ok = Number.isInteger(value) && (allowZero ? value >= 0 : value > 0);\n\tif (!ok) {\n\t\tthrow new TypeError(\n\t\t\t`createSignInThrottle(): ${name} must be a positive integer${allowZero ? ' or 0' : ''}; got ${String(value)}.`,\n\t\t);\n\t}\n\treturn value;\n}\n\n/**\n * A failed-attempt throttle for a password sign-in, in this process's memory:\n * `max` failures per key within `windowMs`, a bounded number of keys, a global\n * bucket that delays every sign-in for a few seconds rather than locking an\n * account, and `verify`, which holds password hashing (argon2 at 64 MiB each)\n * to a small concurrency. Each process counts alone: behind several instances\n * the limits multiply. Pass the lower-cased address as the key.\n *\n * @example\n * const throttle = createSignInThrottle({ max: 5, windowMs: 15 * 60_000 });\n * // in the sign-in action\n * const seconds = throttle.wait(email);\n * if (seconds > 0) return tooMany(seconds);\n * const checked = await throttle.verify(() => Bun.password.verify(password, hash));\n * if (checked.busy) return tryLater();\n * if (!checked.value) { throttle.fail(email); return refused(); }\n * throttle.clear(email);\n */\nexport function createSignInThrottle(\n\toptions: SignInThrottleOptions = {},\n): SignInThrottle {\n\tconst max = positive('max', options.max ?? DEFAULTS.max);\n\tconst windowMs = positive('windowMs', options.windowMs ?? DEFAULTS.windowMs);\n\tconst maxKeys = positive('maxKeys', options.maxKeys ?? DEFAULTS.maxKeys);\n\tconst globalMax = positive(\n\t\t'globalMax',\n\t\toptions.globalMax ?? DEFAULTS.globalMax,\n\t);\n\tconst globalWindowMs = positive(\n\t\t'globalWindowMs',\n\t\toptions.globalWindowMs ?? DEFAULTS.globalWindowMs,\n\t);\n\tconst slots = positive(\n\t\t'maxConcurrentVerifies',\n\t\toptions.maxConcurrentVerifies ?? DEFAULTS.maxConcurrentVerifies,\n\t);\n\tconst queueLimit = positive(\n\t\t'maxQueuedVerifies',\n\t\toptions.maxQueuedVerifies ?? DEFAULTS.maxQueuedVerifies,\n\t\ttrue,\n\t);\n\tconst now = options.now ?? Date.now;\n\n\t// A Map keeps insertion order: the first key is the oldest.\n\tconst failures = new Map<string, number[]>();\n\tlet global: number[] = [];\n\n\tconst recent = (key: string, at: number): number[] => {\n\t\tconst kept = (failures.get(key) ?? []).filter(\n\t\t\t(time) => at - time < windowMs,\n\t\t);\n\t\tif (kept.length === 0) failures.delete(key);\n\t\treturn kept;\n\t};\n\tconst seconds = (ms: number): number => Math.ceil(ms / 1000);\n\n\tlet running = 0;\n\tconst queue: Array<() => void> = [];\n\tconst release = () => {\n\t\tconst next = queue.shift();\n\t\tif (next) next();\n\t\telse running--;\n\t};\n\n\treturn {\n\t\twait(key) {\n\t\t\tconst at = now();\n\t\t\tlet wait = 0;\n\t\t\tconst kept = recent(key, at);\n\t\t\tif (kept.length >= max) {\n\t\t\t\twait = seconds(windowMs - (at - (kept[0] as number)));\n\t\t\t}\n\t\t\tglobal = global.filter((time) => at - time < globalWindowMs);\n\t\t\tif (global.length >= globalMax) {\n\t\t\t\twait = Math.max(\n\t\t\t\t\twait,\n\t\t\t\t\tseconds(globalWindowMs - (at - (global[0] as number))),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn wait;\n\t\t},\n\t\tfail(key) {\n\t\t\tconst at = now();\n\t\t\tconst kept = [...recent(key, at), at].slice(-max);\n\t\t\tfailures.delete(key);\n\t\t\tfailures.set(key, kept);\n\t\t\tif (failures.size > maxKeys) {\n\t\t\t\tconst oldest = failures.keys().next().value;\n\t\t\t\tif (oldest !== undefined) failures.delete(oldest);\n\t\t\t}\n\t\t\tglobal = [\n\t\t\t\t...global.filter((time) => at - time < globalWindowMs),\n\t\t\t\tat,\n\t\t\t].slice(-globalMax);\n\t\t},\n\t\tclear(key) {\n\t\t\tfailures.delete(key);\n\t\t},\n\t\tasync verify(task) {\n\t\t\tif (running >= slots) {\n\t\t\t\tif (queue.length >= queueLimit) return { busy: true };\n\t\t\t\tawait new Promise<void>((resolve) => queue.push(resolve));\n\t\t\t} else {\n\t\t\t\trunning++;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn { busy: false, value: await task() };\n\t\t\t} finally {\n\t\t\t\trelease();\n\t\t\t}\n\t\t},\n\t\tget size() {\n\t\t\treturn failures.size;\n\t\t},\n\t};\n}\n"
|
|
21
22
|
],
|
|
22
|
-
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
23
|
+
"mappings": "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",
|
|
24
|
+
"debugId": "30B84BDDE86DDE4164756E2164756E21",
|
|
24
25
|
"names": []
|
|
25
26
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** What `createSignInThrottle` takes; every field has a default. */
|
|
2
|
+
export interface SignInThrottleOptions {
|
|
3
|
+
/** Failures one key may make within `windowMs` before it waits. 5 by default. */
|
|
4
|
+
readonly max?: number | undefined;
|
|
5
|
+
/** The per-key window, in milliseconds. 15 minutes by default. */
|
|
6
|
+
readonly windowMs?: number | undefined;
|
|
7
|
+
/** How many keys are held; past it the oldest is dropped. 10 000 by default. */
|
|
8
|
+
readonly maxKeys?: number | undefined;
|
|
9
|
+
/** Failures, all keys together, within `globalWindowMs` before every sign-in is delayed. 100 by default. */
|
|
10
|
+
readonly globalMax?: number | undefined;
|
|
11
|
+
/** The global window, in milliseconds: also the longest the global delay lasts. 1 minute by default. */
|
|
12
|
+
readonly globalWindowMs?: number | undefined;
|
|
13
|
+
/** Password verifications that run at once. 2 by default. */
|
|
14
|
+
readonly maxConcurrentVerifies?: number | undefined;
|
|
15
|
+
/** Verifications that wait for a slot; past it `verify` answers `{ busy: true }`. 4 by default; 0 for none. */
|
|
16
|
+
readonly maxQueuedVerifies?: number | undefined;
|
|
17
|
+
/** The clock, in milliseconds. `Date.now` by default; inject one in a test. */
|
|
18
|
+
readonly now?: (() => number) | undefined;
|
|
19
|
+
}
|
|
20
|
+
/** What `verify` answers: the task's value, or a refusal because the queue was full. */
|
|
21
|
+
export type VerifyResult<T> = {
|
|
22
|
+
readonly busy: false;
|
|
23
|
+
readonly value: T;
|
|
24
|
+
} | {
|
|
25
|
+
readonly busy: true;
|
|
26
|
+
};
|
|
27
|
+
/** A per-process sign-in throttle. */
|
|
28
|
+
export interface SignInThrottle {
|
|
29
|
+
/** Seconds to wait before this key may try again, 0 when it may. Records nothing. */
|
|
30
|
+
wait(key: string): number;
|
|
31
|
+
/** Record a failed attempt for the key (and in the global bucket). */
|
|
32
|
+
fail(key: string): void;
|
|
33
|
+
/** Forget the key's failures after a successful sign-in. The global bucket is left alone. */
|
|
34
|
+
clear(key: string): void;
|
|
35
|
+
/** Run a password verification under the concurrency limit, or refuse when the wait queue is full. A rejection of `task` passes through and frees its slot. */
|
|
36
|
+
verify<T>(task: () => Promise<T>): Promise<VerifyResult<T>>;
|
|
37
|
+
/** How many keys are held now. */
|
|
38
|
+
readonly size: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A failed-attempt throttle for a password sign-in, in this process's memory:
|
|
42
|
+
* `max` failures per key within `windowMs`, a bounded number of keys, a global
|
|
43
|
+
* bucket that delays every sign-in for a few seconds rather than locking an
|
|
44
|
+
* account, and `verify`, which holds password hashing (argon2 at 64 MiB each)
|
|
45
|
+
* to a small concurrency. Each process counts alone: behind several instances
|
|
46
|
+
* the limits multiply. Pass the lower-cased address as the key.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const throttle = createSignInThrottle({ max: 5, windowMs: 15 * 60_000 });
|
|
50
|
+
* // in the sign-in action
|
|
51
|
+
* const seconds = throttle.wait(email);
|
|
52
|
+
* if (seconds > 0) return tooMany(seconds);
|
|
53
|
+
* const checked = await throttle.verify(() => Bun.password.verify(password, hash));
|
|
54
|
+
* if (checked.busy) return tryLater();
|
|
55
|
+
* if (!checked.value) { throttle.fail(email); return refused(); }
|
|
56
|
+
* throttle.clear(email);
|
|
57
|
+
*/
|
|
58
|
+
export declare function createSignInThrottle(options?: SignInThrottleOptions): SignInThrottle;
|
|
59
|
+
//# sourceMappingURL=throttle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/session/throttle.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,WAAW,qBAAqB;IACrC,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,4GAA4G;IAC5G,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,wGAAwG;IACxG,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,6DAA6D;IAC7D,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,+GAA+G;IAC/G,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;CAC1C;AAED,wFAAwF;AACxF,MAAM,MAAM,YAAY,CAAC,CAAC,IACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC3C;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AAE3B,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC9B,qFAAqF;IACrF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,sEAAsE;IACtE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,6FAA6F;IAC7F,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,+JAA+J;IAC/J,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAsBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,GAAE,qBAA0B,GACjC,cAAc,CA+FhB"}
|
package/docs/README.md
CHANGED
|
@@ -19,7 +19,7 @@ installable and usable offline, wording an API's refusals, the BFF session, a Gr
|
|
|
19
19
|
| [Deploying](guide/deploying.md) | running the build with `bun build/server/index.js`, and the Docker image |
|
|
20
20
|
| [Installable and offline](guide/pwa.md) | making the app installable and usable offline: the subpaths of `@alxia/react-router/pwa`, the service worker (`startWorker`, `/pwa/worker`), its build by `alxia()` or `buildWorker` (`/pwa/build`), its contract and cache names, which requests the worker caches and which responses it stores, the precache list read from a build, or clearing the caches at sign-out |
|
|
21
21
|
| [An API's refusals](guide/errors.md) | wording a GraphQL API's refusals for the pages: recognising an `ApiError` or a REST API's `problemError`, the request id, the page a request is for, the catalogue store, the form checks in the API's words, the provider, and the loaders, the error page and the actions that answer with it, the JSON actions with their CSRF check and fetcher hook, calling the API from a loader (`apiCallFailure`), and keeping the catalogue fresh (`@alxia/react-router/errors`) |
|
|
22
|
-
| [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), the step-up route's signed-out handling (`onSignedOut`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
|
|
22
|
+
| [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, a signed session and a sign-in throttle (`signedSession`, `createSignInThrottle`), the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), the step-up route's signed-out handling (`onSignedOut`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
|
|
23
23
|
| [Links through React Router](guide/link.md) | `RouterLink`, React Router's `Link` as the link component of a UI library that hands `href` and spreads anchor props; `@alxia/react-router/link` |
|
|
24
24
|
| [A fetcher's fresh answer](guide/fetcher.md) | `useFetcherAnswer`, `useFetcherPromise` (one submission's answer as a Promise), a handler called once per new answer of a keyed fetcher, not for the data it held at mount; `useDebouncedFetcher`, a resource route loaded for what is typed (pause, minimum length, stale answer kept, retry); `@alxia/react-router/fetcher` |
|
|
25
25
|
| [Lists whose state is the URL](guide/lists.md) | a search and filters in the address bar that drop the cursor (`useSearchChange`), a skeleton while the same page reloads (`useSameRouteLoading`), and a load-more button that appends pages by cursor and keeps the rows when one fails (`usePagedRows`); `@alxia/react-router/lists` |
|
package/docs/guide/session.md
CHANGED
|
@@ -414,6 +414,67 @@ environment; changing it signs everyone out. The session is not revocable
|
|
|
414
414
|
before its expiry: keep `maxAge` short, and check the password again for
|
|
415
415
|
anything sensitive.
|
|
416
416
|
|
|
417
|
+
### A sign-in throttle
|
|
418
|
+
|
|
419
|
+
A password sign-in needs a failed-attempt throttle and a cap on concurrent
|
|
420
|
+
password hashes (argon2 at 64 MiB each is a memory spike when a hundred
|
|
421
|
+
requests arrive together). `createSignInThrottle` is both, next to
|
|
422
|
+
`signedSession`, and works with any sign-in, not only a signed session.
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
// app/throttle.server.ts
|
|
426
|
+
import { createSignInThrottle } from '@alxia/react-router/session';
|
|
427
|
+
|
|
428
|
+
export const throttle = createSignInThrottle({
|
|
429
|
+
max: 5, // failures per key...
|
|
430
|
+
windowMs: 15 * 60_000, // ...within this window
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
// in the sign-in action
|
|
436
|
+
const email = String(form.get('email')).trim().toLowerCase();
|
|
437
|
+
|
|
438
|
+
const seconds = throttle.wait(email);
|
|
439
|
+
if (seconds > 0) return tooMany(seconds); // e.g. a 429 with Retry-After: seconds
|
|
440
|
+
|
|
441
|
+
const checked = await throttle.verify(() => Bun.password.verify(password, hash));
|
|
442
|
+
if (checked.busy) return tryLater(); // e.g. a 503 with Retry-After: 2
|
|
443
|
+
if (!checked.value) {
|
|
444
|
+
throttle.fail(email);
|
|
445
|
+
return refused();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
throttle.clear(email);
|
|
449
|
+
headers.append('Set-Cookie', await operator.commit());
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
- `wait(key)` returns the seconds to wait, `0` when the key may try. It
|
|
453
|
+
records nothing, so call it before every attempt, also for an address that
|
|
454
|
+
does not exist: answer the same for a known and an unknown one.
|
|
455
|
+
- `fail(key)` records a failure; `clear(key)` forgets the key after a success.
|
|
456
|
+
A key is blocked at `max` failures within `windowMs`, until the oldest
|
|
457
|
+
leaves the window.
|
|
458
|
+
- `maxKeys` (10 000 by default) bounds the memory an attacker can make you
|
|
459
|
+
hold: past it the oldest key is dropped.
|
|
460
|
+
- The global bucket counts every failure, all keys together. Past `globalMax`
|
|
461
|
+
failures within `globalWindowMs` (100 and one minute by default), `wait`
|
|
462
|
+
answers the seconds until the oldest of them leaves that window, for every
|
|
463
|
+
key. It delays everyone briefly and lifts itself; it never locks an
|
|
464
|
+
account, so one attacker spraying addresses cannot lock the real owner out
|
|
465
|
+
for the per-key window. `clear` leaves it alone.
|
|
466
|
+
- `verify(task)` runs `task` (the password check) with at most
|
|
467
|
+
`maxConcurrentVerifies` (2) at once, and up to `maxQueuedVerifies` (4) more
|
|
468
|
+
waiting for a slot. Past that it answers `{ busy: true }` without running
|
|
469
|
+
the task. Otherwise `{ busy: false, value }`; a rejection of `task` passes
|
|
470
|
+
through and frees its slot.
|
|
471
|
+
- `now` replaces the clock (`() => number` in milliseconds), for a test.
|
|
472
|
+
|
|
473
|
+
It is per process, in memory: a restart forgets every failure, and behind
|
|
474
|
+
several instances (or workers) each counts alone, so the effective limits are
|
|
475
|
+
multiplied by the instance count. For a limit shared between instances, count
|
|
476
|
+
in a store they share (for example `@nxgt/redis`' rate limits).
|
|
477
|
+
|
|
417
478
|
### Safari and `http://localhost`
|
|
418
479
|
|
|
419
480
|
Safari (WebKit) drops a `Secure` cookie set over `http://localhost`, where
|
package/docs/roadmap.md
CHANGED
|
@@ -88,6 +88,13 @@ Nothing planned.
|
|
|
88
88
|
|
|
89
89
|
### Unreleased
|
|
90
90
|
|
|
91
|
+
- **`createSignInThrottle` on `/session`.** A failed-attempt throttle for a
|
|
92
|
+
password sign-in: `wait`, `fail` and `clear` per key within a window, a
|
|
93
|
+
bounded number of keys, a global bucket that delays rather than locks, and
|
|
94
|
+
`verify`, which holds password hashing to a small concurrency and refuses
|
|
95
|
+
past a short queue. Per process. See [A sign-in
|
|
96
|
+
throttle](guide/session.md#a-sign-in-throttle).
|
|
97
|
+
|
|
91
98
|
- **`useFetcherPromise` on `/fetcher`.** `run(submit)` returns a Promise
|
|
92
99
|
settled by the fetcher's next new answer, rejected with an `Error` when your
|
|
93
100
|
`refusal(answer)` returns a message. See [One submission's answer as a
|
package/docs/troubleshooting.md
CHANGED
|
@@ -86,6 +86,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
86
86
|
- [`TypeError: sessionCookies(): sameSite "none" needs secure: true, since a browser drops a SameSite=None cookie without Secure.`](#typeerror-sessioncookies-samesite-none-needs-secure-true-since-a-browser-drops-a-samesitenone-cookie-without-secure)
|
|
87
87
|
- [`TypeError: signedSession(): secret must be a string of at least 32 characters.`](#typeerror-signedsession-secret-must-be-a-string-of-at-least-32-characters)
|
|
88
88
|
- [`TypeError: signedSession(): the name "…" must be an RFC 6265 token without a __Host- or __Secure- prefix; …` or `maxAge must be a positive integer of seconds; got ….`](#typeerror-signedsession-the-name--must-be-an-rfc-6265-token-without-a-__host--or-__secure--prefix--or-maxage-must-be-a-positive-integer-of-seconds-got-)
|
|
89
|
+
- [`TypeError: createSignInThrottle(): … must be a positive integer; got ….` or `… must be a positive integer or 0; got ….`](#typeerror-createsigninthrottle--must-be-a-positive-integer-got--or--must-be-a-positive-integer-or-0-got-)
|
|
89
90
|
- [`TypeError: signInFlow(): paths.… must be a path of this site with no query or fragment, starting with a single "/"; got ….`](#typeerror-signinflow-paths-must-be-a-path-of-this-site-with-no-query-or-fragment-starting-with-a-single--got-)
|
|
90
91
|
- [`TypeError: signInPath(): options.path must be a path of this site with no query or fragment, starting with a single "/"; got ….`](#typeerror-signinpath-optionspath-must-be-a-path-of-this-site-with-no-query-or-fragment-starting-with-a-single--got-)
|
|
91
92
|
- [`TypeError: signInFlow(): json must come from jsonActions(), which carries the site check every step runs; this object has none (a hand-made double?). Pass the app's jsonActions({ origin }) instance, or a spread copy of it.`](#typeerror-signinflow-json-must-come-from-jsonactions-which-carries-the-site-check-every-step-runs-this-object-has-none-a-hand-made-double-pass-the-apps-jsonactions-origin--instance-or-a-spread-copy-of-it)
|
|
@@ -1881,6 +1882,14 @@ TypeError: sessionCookies(): sameSite must be "lax", "strict" or "none"; got "so
|
|
|
1881
1882
|
|
|
1882
1883
|
**Fix:** pass a base name such as `'my-app_operator'` and `maxAge: 8 * 60 * 60`.
|
|
1883
1884
|
|
|
1885
|
+
### `TypeError: createSignInThrottle(): … must be a positive integer; got ….` or `… must be a positive integer or 0; got ….`
|
|
1886
|
+
|
|
1887
|
+
**When:** the module that calls `createSignInThrottle` is imported (the message names the option: `max`, `windowMs`, `maxKeys`, `globalMax`, `globalWindowMs`, `maxConcurrentVerifies` or `maxQueuedVerifies`).
|
|
1888
|
+
|
|
1889
|
+
**Why:** the option is not a whole number above 0 (`maxQueuedVerifies` may be 0, and then the message ends `or 0`), often a value read from the environment as a string or `NaN`.
|
|
1890
|
+
|
|
1891
|
+
**Fix:** convert it first, `max: Number(process.env.SIGNIN_MAX ?? 5)`.
|
|
1892
|
+
|
|
1884
1893
|
### `TypeError: signInFlow(): paths.… must be a path of this site with no query or fragment, starting with a single "/"; got ….`
|
|
1885
1894
|
|
|
1886
1895
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), a GraphQL subscription relayed to the browser over SSE (`/subscription`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|