@hyperfixation/auth 0.1.0 → 0.1.2
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/policy.d.ts +2 -0
- package/dist/policy.js +16 -1
- package/dist/session.d.ts +5 -0
- package/package.json +4 -4
package/dist/policy.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export interface AccessRequest extends AccessPaths {
|
|
|
34
34
|
/** Raise the bar above what the route alone demands. Never lowers `/admin/*`. */
|
|
35
35
|
factor?: SessionFactor;
|
|
36
36
|
role?: string;
|
|
37
|
+
/** The clock the ban expiry is read against. Injectable so a test can sit on an instant. */
|
|
38
|
+
now?: () => number;
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* The first segment, with a leading `/api` stripped, so `/api/admin/users` is admin territory
|
package/dist/policy.js
CHANGED
|
@@ -7,6 +7,21 @@ export const DEFAULT_SIGN_IN_PATH = "/auth/sign-in";
|
|
|
7
7
|
export const DEFAULT_STEP_UP_PATH = "/auth/passkey";
|
|
8
8
|
/** The role `/admin/*` requires, and the one `bootstrapAdmin` grants. */
|
|
9
9
|
export const ADMIN_ROLE = "admin";
|
|
10
|
+
/**
|
|
11
|
+
* The same rule the notifier's SQL applies — `banned IS TRUE AND (ban_expires IS NULL OR
|
|
12
|
+
* ban_expires > now())`. A ban with a lapsed expiry is over even though the column still says
|
|
13
|
+
* `true`: nothing sweeps the row, so the expiry is what decides. An unreadable `ban_expires`
|
|
14
|
+
* keeps the ban, because the alternative is letting a bad value un-ban someone.
|
|
15
|
+
*/
|
|
16
|
+
function banIsActive(user, now) {
|
|
17
|
+
if (user.banned !== true)
|
|
18
|
+
return false;
|
|
19
|
+
const expires = user.banExpires;
|
|
20
|
+
if (expires === null || expires === undefined)
|
|
21
|
+
return true;
|
|
22
|
+
const at = expires instanceof Date ? expires.getTime() : Date.parse(expires);
|
|
23
|
+
return Number.isNaN(at) || at > now;
|
|
24
|
+
}
|
|
10
25
|
/**
|
|
11
26
|
* The first segment, with a leading `/api` stripped, so `/api/admin/users` is admin territory
|
|
12
27
|
* to a route handler exactly as `/admin/users` is to a layout. Stripping `/api` is also what
|
|
@@ -56,7 +71,7 @@ export function evaluateAccess(request) {
|
|
|
56
71
|
return refuse("no-session", signIn);
|
|
57
72
|
// A ban lands on the user row while their sessions are still live; it has to be read here or
|
|
58
73
|
// a banned admin keeps the tab they already had open.
|
|
59
|
-
if (session.user.
|
|
74
|
+
if (banIsActive(session.user, (request.now ?? Date.now)()))
|
|
60
75
|
return refuse("banned", signIn);
|
|
61
76
|
if (requiredRole !== undefined && !hasRole(session.user, requiredRole)) {
|
|
62
77
|
return { outcome: "not-found", refusal: "missing-role" };
|
package/dist/session.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export interface SessionUser {
|
|
|
13
13
|
email?: string;
|
|
14
14
|
role?: string | null;
|
|
15
15
|
banned?: boolean | null;
|
|
16
|
+
/**
|
|
17
|
+
* When the ban lapses. better-auth hands this back as a `Date` from the database and as an
|
|
18
|
+
* ISO string once it has been through JSON, so both shapes have to read the same here.
|
|
19
|
+
*/
|
|
20
|
+
banExpires?: Date | string | null;
|
|
16
21
|
}
|
|
17
22
|
/** What the guard needs of a session; better-auth's `session` is a superset. */
|
|
18
23
|
export interface AuthSession {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperfixation/auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "better-auth factory, session-factor policy, requireSession, and the bootstrap user",
|
|
6
6
|
"repository": {
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"!dist/**/*.test.*"
|
|
25
25
|
],
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@hyperfixation/eslint-config": "0.1.
|
|
28
|
-
"@hyperfixation/testing": "0.1.
|
|
27
|
+
"@hyperfixation/eslint-config": "0.1.2",
|
|
28
|
+
"@hyperfixation/testing": "0.1.2",
|
|
29
29
|
"@microsoft/api-extractor": "^7.59.1",
|
|
30
30
|
"@types/pg": "^8.23.1",
|
|
31
31
|
"eslint": "^10.10.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@better-auth/passkey": "1.7.5",
|
|
35
|
-
"@hyperfixation/db": "0.1.
|
|
35
|
+
"@hyperfixation/db": "0.1.2",
|
|
36
36
|
"@simplewebauthn/server": "13.3.3",
|
|
37
37
|
"better-auth": "1.7.5",
|
|
38
38
|
"drizzle-orm": "^0.45.2",
|