@stacksjs/auth 0.70.258 → 0.70.260
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/authentication.js +1 -415
- package/dist/authenticator.js +1 -14
- package/dist/authorizable.js +1 -28
- package/dist/client.js +1 -26
- package/dist/cookie-auth.js +1 -65
- package/dist/email-verification.js +2 -110
- package/dist/gate.js +1 -203
- package/dist/index.js +1 -28
- package/dist/internal-constants.js +1 -1
- package/dist/middleware.js +1 -28
- package/dist/passkey.js +1 -76
- package/dist/password/reset.js +2 -155
- package/dist/permissions.js +1 -4
- package/dist/policy.js +1 -91
- package/dist/rate-limiter.js +1 -91
- package/dist/rbac-seed.js +1 -30
- package/dist/rbac-store-bqb.js +1 -180
- package/dist/rbac.js +1 -326
- package/dist/register.js +1 -43
- package/dist/session-auth.js +1 -151
- package/dist/team.js +1 -88
- package/dist/token.js +1 -21
- package/dist/tokens.js +42 -373
- package/dist/two-factor.js +1 -113
- package/dist/user.js +1 -38
- package/package.json +13 -6
package/dist/two-factor.js
CHANGED
|
@@ -1,113 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { db, sqlDateTime, parseSqlDateTime } from "@stacksjs/database";
|
|
3
|
-
import { generateTwoFactorSecret, generateTwoFactorUri, verifyTwoFactorCode } from "./authenticator";
|
|
4
|
-
import { RateLimiter } from "./rate-limiter";
|
|
5
|
-
const DEFAULT_CHALLENGE_TTL_SECONDS = 300, TWO_FACTOR_RATE_LIMIT_PREFIX = "2fa:", TWO_FACTOR_STEP_SECONDS = 30;
|
|
6
|
-
function currentTotpStep() {
|
|
7
|
-
return Math.floor(Date.now() / 1000 / TWO_FACTOR_STEP_SECONDS);
|
|
8
|
-
}
|
|
9
|
-
async function getLastUsedTwoFactorStep(userId) {
|
|
10
|
-
try {
|
|
11
|
-
const value = (await db.selectFrom("users").where("id", "=", userId).selectAll().executeTakeFirst())?.two_factor_last_used_step;
|
|
12
|
-
return value == null ? null : Number(value);
|
|
13
|
-
} catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
async function setLastUsedTwoFactorStep(userId, step) {
|
|
18
|
-
try {
|
|
19
|
-
await db.updateTable("users").set({ two_factor_last_used_step: step }).where("id", "=", userId).executeTakeFirst();
|
|
20
|
-
} catch {}
|
|
21
|
-
}
|
|
22
|
-
export async function getTwoFactorState(userId) {
|
|
23
|
-
const row = await db.selectFrom("users").where("id", "=", userId).select(["two_factor_secret", "two_factor_enabled"]).executeTakeFirst();
|
|
24
|
-
return {
|
|
25
|
-
secret: row?.two_factor_secret ?? null,
|
|
26
|
-
enabled: Boolean(row?.two_factor_enabled)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export function isTwoFactorEnabled(user) {
|
|
30
|
-
return Boolean(user.two_factor_enabled);
|
|
31
|
-
}
|
|
32
|
-
export function generateTwoFactorSetup(email, serviceName) {
|
|
33
|
-
const secret = generateTwoFactorSecret(), uri = generateTwoFactorUri(email, serviceName, secret);
|
|
34
|
-
return { secret, uri };
|
|
35
|
-
}
|
|
36
|
-
const PENDING_SECRET_TTL_SECONDS = 600;
|
|
37
|
-
export async function stashPendingTwoFactorSecret(userId, secret, ttlSeconds = PENDING_SECRET_TTL_SECONDS) {
|
|
38
|
-
const expiresAt = sqlDateTime(new Date(Date.now() + ttlSeconds * 1000));
|
|
39
|
-
await db.deleteFrom("two_factor_pending_secrets").where("user_id", "=", userId).execute();
|
|
40
|
-
await db.insertInto("two_factor_pending_secrets").values({
|
|
41
|
-
user_id: userId,
|
|
42
|
-
secret,
|
|
43
|
-
expires_at: expiresAt
|
|
44
|
-
}).execute();
|
|
45
|
-
}
|
|
46
|
-
export async function consumePendingTwoFactorSecret(userId) {
|
|
47
|
-
const row = await db.selectFrom("two_factor_pending_secrets").where("user_id", "=", userId).selectAll().executeTakeFirst();
|
|
48
|
-
if (!row)
|
|
49
|
-
return null;
|
|
50
|
-
await db.deleteFrom("two_factor_pending_secrets").where("user_id", "=", userId).execute();
|
|
51
|
-
const expiresAt = parseSqlDateTime(row.expires_at)?.getTime() ?? 0;
|
|
52
|
-
if (Date.now() > expiresAt)
|
|
53
|
-
return null;
|
|
54
|
-
return String(row.secret);
|
|
55
|
-
}
|
|
56
|
-
export async function enableTwoFactor(userId, secret, code) {
|
|
57
|
-
if (!await verifyTwoFactorCode(code, secret))
|
|
58
|
-
return !1;
|
|
59
|
-
await db.updateTable("users").set({ two_factor_secret: secret, two_factor_enabled: !0 }).where("id", "=", userId).executeTakeFirst();
|
|
60
|
-
return !0;
|
|
61
|
-
}
|
|
62
|
-
export async function disableTwoFactor(userId) {
|
|
63
|
-
await db.updateTable("users").set({ two_factor_secret: null, two_factor_enabled: !1 }).where("id", "=", userId).executeTakeFirst();
|
|
64
|
-
}
|
|
65
|
-
export async function verifyTwoFactorLoginCode(userId, code) {
|
|
66
|
-
const rateKey = `${TWO_FACTOR_RATE_LIMIT_PREFIX}${userId}`;
|
|
67
|
-
await RateLimiter.validateAttempt(rateKey);
|
|
68
|
-
const { secret, enabled } = await getTwoFactorState(userId);
|
|
69
|
-
if (!enabled || !secret)
|
|
70
|
-
return !1;
|
|
71
|
-
if (!await verifyTwoFactorCode(code, secret)) {
|
|
72
|
-
await RateLimiter.recordFailedAttempt(rateKey);
|
|
73
|
-
return !1;
|
|
74
|
-
}
|
|
75
|
-
const step = currentTotpStep(), lastStep = await getLastUsedTwoFactorStep(userId);
|
|
76
|
-
if (lastStep !== null && step <= lastStep)
|
|
77
|
-
return !1;
|
|
78
|
-
await setLastUsedTwoFactorStep(userId, step);
|
|
79
|
-
await RateLimiter.resetAttempts(rateKey);
|
|
80
|
-
return !0;
|
|
81
|
-
}
|
|
82
|
-
export async function createTwoFactorChallenge(userId, ttlSeconds = DEFAULT_CHALLENGE_TTL_SECONDS) {
|
|
83
|
-
const id = randomBytes(32).toString("hex"), expiresAt = sqlDateTime(new Date(Date.now() + ttlSeconds * 1000));
|
|
84
|
-
await db.deleteFrom("two_factor_challenges").where("user_id", "=", userId).execute();
|
|
85
|
-
await db.insertInto("two_factor_challenges").values({
|
|
86
|
-
id,
|
|
87
|
-
user_id: userId,
|
|
88
|
-
expires_at: expiresAt
|
|
89
|
-
}).execute();
|
|
90
|
-
return id;
|
|
91
|
-
}
|
|
92
|
-
export async function consumeTwoFactorChallenge(challengeToken) {
|
|
93
|
-
const row = await db.selectFrom("two_factor_challenges").where("id", "=", challengeToken).selectAll().executeTakeFirst();
|
|
94
|
-
if (!row)
|
|
95
|
-
return null;
|
|
96
|
-
await db.deleteFrom("two_factor_challenges").where("id", "=", challengeToken).execute();
|
|
97
|
-
const expiresAt = parseSqlDateTime(row.expires_at)?.getTime() ?? 0;
|
|
98
|
-
if (Date.now() > expiresAt)
|
|
99
|
-
return null;
|
|
100
|
-
return Number(row.user_id);
|
|
101
|
-
}
|
|
102
|
-
export const TwoFactor = {
|
|
103
|
-
isEnabled: isTwoFactorEnabled,
|
|
104
|
-
getState: getTwoFactorState,
|
|
105
|
-
generateSetup: generateTwoFactorSetup,
|
|
106
|
-
stashPendingSecret: stashPendingTwoFactorSecret,
|
|
107
|
-
consumePendingSecret: consumePendingTwoFactorSecret,
|
|
108
|
-
enable: enableTwoFactor,
|
|
109
|
-
disable: disableTwoFactor,
|
|
110
|
-
verifyLoginCode: verifyTwoFactorLoginCode,
|
|
111
|
-
createChallenge: createTwoFactorChallenge,
|
|
112
|
-
consumeChallenge: consumeTwoFactorChallenge
|
|
113
|
-
};
|
|
1
|
+
import{randomBytes}from"node:crypto";import{db,sqlDateTime,parseSqlDateTime}from"@stacksjs/database";import{generateTwoFactorSecret,generateTwoFactorUri,verifyTwoFactorCode}from"./authenticator";import{RateLimiter}from"./rate-limiter";const DEFAULT_CHALLENGE_TTL_SECONDS=300,TWO_FACTOR_RATE_LIMIT_PREFIX="2fa:",TWO_FACTOR_STEP_SECONDS=30;function currentTotpStep(){return Math.floor(Date.now()/1000/TWO_FACTOR_STEP_SECONDS)}async function getLastUsedTwoFactorStep(userId){try{const value=(await db.selectFrom("users").where("id","=",userId).selectAll().executeTakeFirst())?.two_factor_last_used_step;return value==null?null:Number(value)}catch{return null}}async function setLastUsedTwoFactorStep(userId,step){try{await db.updateTable("users").set({two_factor_last_used_step:step}).where("id","=",userId).executeTakeFirst()}catch{}}export async function getTwoFactorState(userId){const row=await db.selectFrom("users").where("id","=",userId).select(["two_factor_secret","two_factor_enabled"]).executeTakeFirst();return{secret:row?.two_factor_secret??null,enabled:Boolean(row?.two_factor_enabled)}}export function isTwoFactorEnabled(user){return Boolean(user.two_factor_enabled)}export function generateTwoFactorSetup(email,serviceName){const secret=generateTwoFactorSecret(),uri=generateTwoFactorUri(email,serviceName,secret);return{secret,uri}}const PENDING_SECRET_TTL_SECONDS=600;export async function stashPendingTwoFactorSecret(userId,secret,ttlSeconds=PENDING_SECRET_TTL_SECONDS){const expiresAt=sqlDateTime(new Date(Date.now()+ttlSeconds*1000));await db.deleteFrom("two_factor_pending_secrets").where("user_id","=",userId).execute();await db.insertInto("two_factor_pending_secrets").values({user_id:userId,secret,expires_at:expiresAt}).execute()}export async function consumePendingTwoFactorSecret(userId){const row=await db.selectFrom("two_factor_pending_secrets").where("user_id","=",userId).selectAll().executeTakeFirst();if(!row)return null;await db.deleteFrom("two_factor_pending_secrets").where("user_id","=",userId).execute();const expiresAt=parseSqlDateTime(row.expires_at)?.getTime()??0;if(Date.now()>expiresAt)return null;return String(row.secret)}export async function enableTwoFactor(userId,secret,code){if(!await verifyTwoFactorCode(code,secret))return!1;await db.updateTable("users").set({two_factor_secret:secret,two_factor_enabled:!0}).where("id","=",userId).executeTakeFirst();return!0}export async function disableTwoFactor(userId){await db.updateTable("users").set({two_factor_secret:null,two_factor_enabled:!1}).where("id","=",userId).executeTakeFirst()}export async function verifyTwoFactorLoginCode(userId,code){const rateKey=`${TWO_FACTOR_RATE_LIMIT_PREFIX}${userId}`;await RateLimiter.validateAttempt(rateKey);const{secret,enabled}=await getTwoFactorState(userId);if(!enabled||!secret)return!1;if(!await verifyTwoFactorCode(code,secret)){await RateLimiter.recordFailedAttempt(rateKey);return!1}const step=currentTotpStep(),lastStep=await getLastUsedTwoFactorStep(userId);if(lastStep!==null&&step<=lastStep)return!1;await setLastUsedTwoFactorStep(userId,step);await RateLimiter.resetAttempts(rateKey);return!0}export async function createTwoFactorChallenge(userId,ttlSeconds=DEFAULT_CHALLENGE_TTL_SECONDS){const id=randomBytes(32).toString("hex"),expiresAt=sqlDateTime(new Date(Date.now()+ttlSeconds*1000));await db.deleteFrom("two_factor_challenges").where("user_id","=",userId).execute();await db.insertInto("two_factor_challenges").values({id,user_id:userId,expires_at:expiresAt}).execute();return id}export async function consumeTwoFactorChallenge(challengeToken){const row=await db.selectFrom("two_factor_challenges").where("id","=",challengeToken).selectAll().executeTakeFirst();if(!row)return null;await db.deleteFrom("two_factor_challenges").where("id","=",challengeToken).execute();const expiresAt=parseSqlDateTime(row.expires_at)?.getTime()??0;if(Date.now()>expiresAt)return null;return Number(row.user_id)}export const TwoFactor={isEnabled:isTwoFactorEnabled,getState:getTwoFactorState,generateSetup:generateTwoFactorSetup,stashPendingSecret:stashPendingTwoFactorSecret,consumePendingSecret:consumePendingTwoFactorSecret,enable:enableTwoFactor,disable:disableTwoFactor,verifyLoginCode:verifyTwoFactorLoginCode,createChallenge:createTwoFactorChallenge,consumeChallenge:consumeTwoFactorChallenge};
|
package/dist/user.js
CHANGED
|
@@ -1,38 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Auth } from "./authentication";
|
|
3
|
-
export async function authUser() {
|
|
4
|
-
const middlewareUser = request?._authenticatedUser;
|
|
5
|
-
if (middlewareUser)
|
|
6
|
-
return middlewareUser;
|
|
7
|
-
let token = request.bearerToken?.();
|
|
8
|
-
if (!token) {
|
|
9
|
-
const authHeader = request.headers?.get?.("authorization") || request.headers?.get?.("Authorization");
|
|
10
|
-
if (authHeader && authHeader.startsWith("Bearer "))
|
|
11
|
-
token = authHeader.substring(7);
|
|
12
|
-
}
|
|
13
|
-
if (!token)
|
|
14
|
-
return;
|
|
15
|
-
return await Auth.getUserFromToken(token);
|
|
16
|
-
}
|
|
17
|
-
export async function check() {
|
|
18
|
-
return !!await authUser();
|
|
19
|
-
}
|
|
20
|
-
export async function id() {
|
|
21
|
-
return (await authUser())?.id;
|
|
22
|
-
}
|
|
23
|
-
export async function email() {
|
|
24
|
-
return (await authUser())?.email;
|
|
25
|
-
}
|
|
26
|
-
export async function name() {
|
|
27
|
-
return (await authUser())?.name;
|
|
28
|
-
}
|
|
29
|
-
export async function isAuthenticated() {
|
|
30
|
-
return await check();
|
|
31
|
-
}
|
|
32
|
-
export async function logout() {
|
|
33
|
-
await Auth.logout();
|
|
34
|
-
}
|
|
35
|
-
export async function refresh() {
|
|
36
|
-
if (request?._authenticatedUser)
|
|
37
|
-
request._authenticatedUser = void 0;
|
|
38
|
-
}
|
|
1
|
+
import{request}from"@stacksjs/router";import{Auth}from"./authentication";export async function authUser(){const middlewareUser=request?._authenticatedUser;if(middlewareUser)return middlewareUser;let token=request.bearerToken?.();if(!token){const authHeader=request.headers?.get?.("authorization")||request.headers?.get?.("Authorization");if(authHeader&&authHeader.startsWith("Bearer "))token=authHeader.substring(7)}if(!token)return;return await Auth.getUserFromToken(token)}export async function check(){return!!await authUser()}export async function id(){return(await authUser())?.id}export async function email(){return(await authUser())?.email}export async function name(){return(await authUser())?.name}export async function isAuthenticated(){return await check()}export async function logout(){await Auth.logout()}export async function refresh(){if(request?._authenticatedUser)request._authenticatedUser=void 0}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/auth",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.260",
|
|
6
6
|
"description": "A more simplistic way to authenticate.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -32,9 +32,16 @@
|
|
|
32
32
|
"default": "./dist/index.js"
|
|
33
33
|
},
|
|
34
34
|
"./*": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
35
|
+
"types": "./dist/*.d.ts",
|
|
36
|
+
"bun": "./dist/*.js",
|
|
37
|
+
"import": "./dist/*.js",
|
|
38
|
+
"default": "./dist/*.js"
|
|
39
|
+
},
|
|
40
|
+
"./*.js": {
|
|
41
|
+
"types": "./dist/*.d.ts",
|
|
42
|
+
"bun": "./dist/*.js",
|
|
43
|
+
"import": "./dist/*.js",
|
|
44
|
+
"default": "./dist/*.js"
|
|
38
45
|
}
|
|
39
46
|
},
|
|
40
47
|
"module": "dist/index.js",
|
|
@@ -54,7 +61,7 @@
|
|
|
54
61
|
},
|
|
55
62
|
"devDependencies": {
|
|
56
63
|
"better-dx": "^0.2.17",
|
|
57
|
-
"@stacksjs/error-handling": "0.70.
|
|
58
|
-
"@stacksjs/router": "0.70.
|
|
64
|
+
"@stacksjs/error-handling": "0.70.260",
|
|
65
|
+
"@stacksjs/router": "0.70.260"
|
|
59
66
|
}
|
|
60
67
|
}
|