@arch-cadre/core 0.0.42 → 0.0.44
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/core/auth/augment.d.ts +18 -0
- package/dist/core/auth/augment.d.ts.map +1 -0
- package/dist/core/auth/augment.js +45 -0
- package/dist/core/auth/email-verification.d.ts +58 -0
- package/dist/core/auth/email-verification.d.ts.map +1 -0
- package/dist/core/auth/email-verification.js +105 -0
- package/dist/core/auth/events.d.ts +53 -0
- package/dist/core/auth/events.d.ts.map +1 -0
- package/dist/core/auth/events.js +1 -0
- package/dist/core/auth/logic.d.ts +106 -0
- package/dist/core/auth/logic.d.ts.map +1 -0
- package/dist/core/auth/logic.js +245 -0
- package/dist/core/auth/password-reset.d.ts +35 -0
- package/dist/core/auth/password-reset.d.ts.map +1 -0
- package/dist/core/auth/password-reset.js +122 -0
- package/dist/core/auth/rbac.d.ts +56 -0
- package/dist/core/auth/rbac.d.ts.map +1 -0
- package/dist/core/auth/rbac.js +134 -0
- package/dist/core/auth/session.d.ts +50 -0
- package/dist/core/auth/session.d.ts.map +1 -0
- package/dist/core/auth/session.js +152 -0
- package/dist/core/auth/types.d.ts +52 -0
- package/dist/core/auth/types.d.ts.map +1 -0
- package/dist/core/auth/types.js +1 -0
- package/dist/core/auth/utils/encode.d.ts +12 -0
- package/dist/core/auth/utils/encode.d.ts.map +1 -0
- package/dist/core/auth/utils/encode.js +20 -0
- package/dist/core/auth/utils/{encryption.d.mts → encryption.d.ts} +5 -8
- package/dist/core/auth/utils/encryption.d.ts.map +1 -0
- package/dist/core/auth/utils/encryption.js +62 -0
- package/dist/core/auth/validation.d.ts +44 -0
- package/dist/core/auth/validation.d.ts.map +1 -0
- package/dist/core/auth/validation.js +41 -0
- package/dist/core/bootstrap.d.ts +2 -0
- package/dist/core/bootstrap.d.ts.map +1 -0
- package/dist/core/bootstrap.js +51 -0
- package/dist/core/config.d.ts +9 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +3 -0
- package/dist/core/config.server.d.ts +12 -0
- package/dist/core/config.server.d.ts.map +1 -0
- package/dist/core/config.server.js +61 -0
- package/dist/core/event-bus.d.ts +14 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +51 -0
- package/dist/core/filesystem/index.d.ts +4 -0
- package/dist/core/filesystem/index.d.ts.map +1 -0
- package/dist/core/filesystem/index.js +10 -0
- package/dist/core/filesystem/providers/local.d.ts +8 -0
- package/dist/core/filesystem/providers/local.d.ts.map +1 -0
- package/dist/core/filesystem/providers/local.js +42 -0
- package/dist/core/filesystem/service.d.ts +16 -0
- package/dist/core/filesystem/service.d.ts.map +1 -0
- package/dist/core/filesystem/service.js +51 -0
- package/dist/core/filesystem/types.d.ts +19 -0
- package/dist/core/filesystem/types.d.ts.map +1 -0
- package/dist/core/filesystem/types.js +1 -0
- package/dist/core/notifications/actions.d.ts +54 -0
- package/dist/core/notifications/actions.d.ts.map +1 -0
- package/dist/core/notifications/actions.js +43 -0
- package/dist/core/notifications/index.d.ts +4 -0
- package/dist/core/notifications/index.d.ts.map +1 -0
- package/dist/core/notifications/index.js +3 -0
- package/dist/core/notifications/service.d.ts +7 -0
- package/dist/core/notifications/service.d.ts.map +1 -0
- package/dist/core/notifications/service.js +32 -0
- package/dist/core/notifications/types.d.ts +17 -0
- package/dist/core/notifications/types.d.ts.map +1 -0
- package/dist/core/notifications/types.js +1 -0
- package/dist/core/setup.d.ts +6 -0
- package/dist/core/setup.d.ts.map +1 -0
- package/dist/core/setup.js +25 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/server/auth/email.d.ts +10 -0
- package/dist/server/auth/email.d.ts.map +1 -0
- package/dist/server/auth/email.js +20 -0
- package/dist/server/auth/{password.d.mts → password.d.ts} +4 -7
- package/dist/server/auth/password.d.ts.map +1 -0
- package/dist/server/auth/password.js +30 -0
- package/dist/server/auth/types.d.ts +13 -0
- package/dist/server/auth/types.d.ts.map +1 -0
- package/dist/server/auth/types.js +1 -0
- package/dist/server/auth/user.d.ts +54 -0
- package/dist/server/auth/user.d.ts.map +1 -0
- package/dist/server/auth/user.js +222 -0
- package/dist/server/database/inject.d.ts +11 -0
- package/dist/server/database/inject.d.ts.map +1 -0
- package/dist/server/database/inject.js +29 -0
- package/dist/server/database/schema.d.ts +2953 -0
- package/dist/server/database/{schema.d.mts.map → schema.d.ts.map} +1 -1
- package/dist/server/database/schema.js +192 -0
- package/dist/server/database/types.d.ts +12 -0
- package/dist/server/database/types.d.ts.map +1 -0
- package/dist/server/database/types.js +1 -0
- package/dist/server/emails/index.d.ts +23 -0
- package/dist/server/emails/index.d.ts.map +1 -0
- package/dist/server/emails/index.js +67 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +32 -0
- package/package.json +5 -6
- package/dist/_virtual/_rolldown/runtime.mjs +0 -1
- package/dist/core/auth/augment.d.mts +0 -20
- package/dist/core/auth/augment.d.mts.map +0 -1
- package/dist/core/auth/augment.mjs +0 -2
- package/dist/core/auth/augment.mjs.map +0 -1
- package/dist/core/auth/email-verification.d.mts +0 -62
- package/dist/core/auth/email-verification.d.mts.map +0 -1
- package/dist/core/auth/email-verification.mjs +0 -2
- package/dist/core/auth/email-verification.mjs.map +0 -1
- package/dist/core/auth/logic.d.mts +0 -110
- package/dist/core/auth/logic.d.mts.map +0 -1
- package/dist/core/auth/logic.mjs +0 -2
- package/dist/core/auth/logic.mjs.map +0 -1
- package/dist/core/auth/password-reset.d.mts +0 -39
- package/dist/core/auth/password-reset.d.mts.map +0 -1
- package/dist/core/auth/password-reset.mjs +0 -2
- package/dist/core/auth/password-reset.mjs.map +0 -1
- package/dist/core/auth/rbac.d.mts +0 -61
- package/dist/core/auth/rbac.d.mts.map +0 -1
- package/dist/core/auth/rbac.mjs +0 -2
- package/dist/core/auth/rbac.mjs.map +0 -1
- package/dist/core/auth/session.d.mts +0 -54
- package/dist/core/auth/session.d.mts.map +0 -1
- package/dist/core/auth/session.mjs +0 -2
- package/dist/core/auth/session.mjs.map +0 -1
- package/dist/core/auth/types.d.mts +0 -55
- package/dist/core/auth/types.d.mts.map +0 -1
- package/dist/core/auth/utils/encode.d.mts +0 -15
- package/dist/core/auth/utils/encode.d.mts.map +0 -1
- package/dist/core/auth/utils/encode.mjs +0 -2
- package/dist/core/auth/utils/encode.mjs.map +0 -1
- package/dist/core/auth/utils/encryption.d.mts.map +0 -1
- package/dist/core/auth/utils/encryption.mjs +0 -2
- package/dist/core/auth/utils/encryption.mjs.map +0 -1
- package/dist/core/auth/validation.d.mts +0 -48
- package/dist/core/auth/validation.d.mts.map +0 -1
- package/dist/core/auth/validation.mjs +0 -2
- package/dist/core/auth/validation.mjs.map +0 -1
- package/dist/core/bootstrap.d.mts +0 -5
- package/dist/core/bootstrap.d.mts.map +0 -1
- package/dist/core/bootstrap.mjs +0 -2
- package/dist/core/bootstrap.mjs.map +0 -1
- package/dist/core/config.d.mts +0 -11
- package/dist/core/config.d.mts.map +0 -1
- package/dist/core/config.mjs +0 -2
- package/dist/core/config.mjs.map +0 -1
- package/dist/core/config.server.d.mts +0 -16
- package/dist/core/config.server.d.mts.map +0 -1
- package/dist/core/config.server.mjs +0 -2
- package/dist/core/config.server.mjs.map +0 -1
- package/dist/core/event-bus.d.mts +0 -17
- package/dist/core/event-bus.d.mts.map +0 -1
- package/dist/core/event-bus.mjs +0 -2
- package/dist/core/event-bus.mjs.map +0 -1
- package/dist/core/filesystem/index.mjs +0 -2
- package/dist/core/filesystem/index.mjs.map +0 -1
- package/dist/core/filesystem/providers/local.mjs +0 -2
- package/dist/core/filesystem/providers/local.mjs.map +0 -1
- package/dist/core/filesystem/service.d.mts +0 -19
- package/dist/core/filesystem/service.d.mts.map +0 -1
- package/dist/core/filesystem/service.mjs +0 -2
- package/dist/core/filesystem/service.mjs.map +0 -1
- package/dist/core/filesystem/types.d.mts +0 -22
- package/dist/core/filesystem/types.d.mts.map +0 -1
- package/dist/core/notifications/actions.d.mts +0 -58
- package/dist/core/notifications/actions.d.mts.map +0 -1
- package/dist/core/notifications/actions.mjs +0 -2
- package/dist/core/notifications/actions.mjs.map +0 -1
- package/dist/core/notifications/index.mjs +0 -1
- package/dist/core/notifications/service.d.mts +0 -9
- package/dist/core/notifications/service.d.mts.map +0 -1
- package/dist/core/notifications/service.mjs +0 -2
- package/dist/core/notifications/service.mjs.map +0 -1
- package/dist/core/notifications/types.d.mts +0 -21
- package/dist/core/notifications/types.d.mts.map +0 -1
- package/dist/core/setup.d.mts +0 -9
- package/dist/core/setup.d.mts.map +0 -1
- package/dist/core/setup.mjs +0 -2
- package/dist/core/setup.mjs.map +0 -1
- package/dist/core/types.d.mts +0 -13
- package/dist/core/types.d.mts.map +0 -1
- package/dist/index.d.mts +0 -8
- package/dist/index.mjs +0 -1
- package/dist/server/auth/email.d.mts +0 -13
- package/dist/server/auth/email.d.mts.map +0 -1
- package/dist/server/auth/email.mjs +0 -2
- package/dist/server/auth/email.mjs.map +0 -1
- package/dist/server/auth/password.d.mts.map +0 -1
- package/dist/server/auth/password.mjs +0 -2
- package/dist/server/auth/password.mjs.map +0 -1
- package/dist/server/auth/user.d.mts +0 -58
- package/dist/server/auth/user.d.mts.map +0 -1
- package/dist/server/auth/user.mjs +0 -2
- package/dist/server/auth/user.mjs.map +0 -1
- package/dist/server/database/inject.d.mts +0 -15
- package/dist/server/database/inject.d.mts.map +0 -1
- package/dist/server/database/inject.mjs +0 -2
- package/dist/server/database/inject.mjs.map +0 -1
- package/dist/server/database/schema.d.mts +0 -2962
- package/dist/server/database/schema.mjs +0 -2
- package/dist/server/database/schema.mjs.map +0 -1
- package/dist/server/emails/index.d.mts +0 -26
- package/dist/server/emails/index.d.mts.map +0 -1
- package/dist/server/emails/index.mjs +0 -2
- package/dist/server/emails/index.mjs.map +0 -1
- package/dist/server.d.mts +0 -26
- package/dist/server.mjs +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PasswordResetAuthSession, PasswordResetSession } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new password reset session.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createPasswordResetSession(token: string, userId: string, email: string): Promise<PasswordResetSession>;
|
|
6
|
+
/**
|
|
7
|
+
* Validates the password reset session token and retrieves user data.
|
|
8
|
+
* The user data is augmented by registered modules (e.g. 2FA).
|
|
9
|
+
*/
|
|
10
|
+
export declare function validatePasswordResetSessionToken(token: string): Promise<PasswordResetAuthSession>;
|
|
11
|
+
/**
|
|
12
|
+
* Marks the password reset session as email verified.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setPasswordResetSessionAsEmailVerified(sessionId: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Invalidates all password reset sessions for a user.
|
|
17
|
+
*/
|
|
18
|
+
export declare function invalidateUserPasswordResetSessions(userId: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Validates the current password reset session from cookies.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getCurrentPasswordResetSession(): Promise<PasswordResetAuthSession>;
|
|
23
|
+
/**
|
|
24
|
+
* Sets the password reset session token cookie.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setPasswordResetSessionTokenCookie(token: string, expiresAt: Date): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Deletes the password reset session token cookie.
|
|
29
|
+
*/
|
|
30
|
+
export declare function deletePasswordResetSessionTokenCookie(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Sends a password reset email with the OTP code.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sendPasswordResetEmail(email: string, code: string): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=password-reset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.d.ts","sourceRoot":"","sources":["../../../src/core/auth/password-reset.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAG9E;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,oBAAoB,CAAC,CAe/B;AAED;;;GAGG;AACH,wBAAsB,iCAAiC,CACrD,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,wBAAwB,CAAC,CAoCnC;AAED;;GAEG;AACH,wBAAsB,sCAAsC,CAC1D,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;GAEG;AACH,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAexF;AAED;;GAEG;AACH,wBAAsB,kCAAkC,CACtD,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAsB,qCAAqC,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3E;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { sha256 } from "@oslojs/crypto/sha2";
|
|
3
|
+
import { encodeHexLowerCase } from "@oslojs/encoding";
|
|
4
|
+
import { addHours } from "date-fns";
|
|
5
|
+
import { eq } from "drizzle-orm";
|
|
6
|
+
import { cookies } from "next/headers";
|
|
7
|
+
import { db } from "../../server/database/inject";
|
|
8
|
+
import { passwordResetSessionTable, userTable, } from "../../server/database/schema";
|
|
9
|
+
import { sendResetPassword } from "../../server/emails/index";
|
|
10
|
+
import { augmentPasswordResetSession } from "./augment";
|
|
11
|
+
import { performFullUserAugmentation } from "./logic";
|
|
12
|
+
import { generateRandomOTP } from "./utils/encode";
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new password reset session.
|
|
15
|
+
*/
|
|
16
|
+
export async function createPasswordResetSession(token, userId, email) {
|
|
17
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
18
|
+
const [session] = await db
|
|
19
|
+
.insert(passwordResetSessionTable)
|
|
20
|
+
.values({
|
|
21
|
+
id: sessionId,
|
|
22
|
+
email: email,
|
|
23
|
+
code: generateRandomOTP(),
|
|
24
|
+
expiresAt: new Date(addHours(new Date(), 1)),
|
|
25
|
+
userId: userId,
|
|
26
|
+
})
|
|
27
|
+
.returning();
|
|
28
|
+
return session;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validates the password reset session token and retrieves user data.
|
|
32
|
+
* The user data is augmented by registered modules (e.g. 2FA).
|
|
33
|
+
*/
|
|
34
|
+
export async function validatePasswordResetSessionToken(token) {
|
|
35
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
36
|
+
const [row] = await db
|
|
37
|
+
.select({
|
|
38
|
+
session: passwordResetSessionTable,
|
|
39
|
+
user: userTable,
|
|
40
|
+
})
|
|
41
|
+
.from(passwordResetSessionTable)
|
|
42
|
+
.innerJoin(userTable, eq(passwordResetSessionTable.userId, userTable.id))
|
|
43
|
+
.where(eq(passwordResetSessionTable.id, sessionId));
|
|
44
|
+
if (!row || !row.user) {
|
|
45
|
+
return { session: null, user: null };
|
|
46
|
+
}
|
|
47
|
+
const { session: baseSession, user: baseUser } = row;
|
|
48
|
+
// Check for expiration
|
|
49
|
+
if (new Date() > baseSession.expiresAt) {
|
|
50
|
+
await db
|
|
51
|
+
.delete(passwordResetSessionTable)
|
|
52
|
+
.where(eq(passwordResetSessionTable.id, baseSession.id));
|
|
53
|
+
return { session: null, user: null };
|
|
54
|
+
}
|
|
55
|
+
// STRICTLY remove non-serializable and sensitive fields
|
|
56
|
+
const { password, recovery_code, ...safeUser } = baseUser;
|
|
57
|
+
// AUGMENT (EXTENSIBILITY POINTS)
|
|
58
|
+
const user = await performFullUserAugmentation(safeUser);
|
|
59
|
+
const session = await augmentPasswordResetSession(baseSession);
|
|
60
|
+
return { session, user };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Marks the password reset session as email verified.
|
|
64
|
+
*/
|
|
65
|
+
export async function setPasswordResetSessionAsEmailVerified(sessionId) {
|
|
66
|
+
await db
|
|
67
|
+
.update(passwordResetSessionTable)
|
|
68
|
+
.set({
|
|
69
|
+
emailVerified: true,
|
|
70
|
+
})
|
|
71
|
+
.where(eq(passwordResetSessionTable.id, sessionId));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Invalidates all password reset sessions for a user.
|
|
75
|
+
*/
|
|
76
|
+
export async function invalidateUserPasswordResetSessions(userId) {
|
|
77
|
+
await db
|
|
78
|
+
.delete(passwordResetSessionTable)
|
|
79
|
+
.where(eq(passwordResetSessionTable.userId, userId));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validates the current password reset session from cookies.
|
|
83
|
+
*/
|
|
84
|
+
export async function getCurrentPasswordResetSession() {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
const cookieStore = await cookies();
|
|
87
|
+
const token = (_b = (_a = cookieStore.get("password_reset_session")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
|
|
88
|
+
if (token === null) {
|
|
89
|
+
return { session: null, user: null };
|
|
90
|
+
}
|
|
91
|
+
const result = await validatePasswordResetSessionToken(token);
|
|
92
|
+
if (result.session === null) {
|
|
93
|
+
await deletePasswordResetSessionTokenCookie();
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Sets the password reset session token cookie.
|
|
99
|
+
*/
|
|
100
|
+
export async function setPasswordResetSessionTokenCookie(token, expiresAt) {
|
|
101
|
+
const cookieStore = await cookies();
|
|
102
|
+
cookieStore.set("password_reset_session", token, {
|
|
103
|
+
expires: expiresAt,
|
|
104
|
+
sameSite: "lax",
|
|
105
|
+
httpOnly: true,
|
|
106
|
+
path: "/",
|
|
107
|
+
secure: process.env.NODE_ENV === "production",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Deletes the password reset session token cookie.
|
|
112
|
+
*/
|
|
113
|
+
export async function deletePasswordResetSessionTokenCookie() {
|
|
114
|
+
const cookieStore = await cookies();
|
|
115
|
+
cookieStore.delete("password_reset_session");
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Sends a password reset email with the OTP code.
|
|
119
|
+
*/
|
|
120
|
+
export async function sendPasswordResetEmail(email, code) {
|
|
121
|
+
await sendResetPassword(email, code);
|
|
122
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORE RBAC LOGIC
|
|
3
|
+
* This file handles all database operations for Roles and Permissions.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getRoles(): Promise<{
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
description: string | null;
|
|
9
|
+
}[]>;
|
|
10
|
+
export declare function getRoleById(roleId: string): Promise<{
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function createRole(name: string, description?: string): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string | null;
|
|
19
|
+
}[]>;
|
|
20
|
+
export declare function deleteRole(roleId: string): Promise<import("pg").QueryResult<never>>;
|
|
21
|
+
export declare function getPermissions(): Promise<{
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string | null;
|
|
25
|
+
}[]>;
|
|
26
|
+
export declare function createPermission(name: string, description?: string): Promise<{
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description: string | null;
|
|
30
|
+
}[]>;
|
|
31
|
+
export declare function deletePermission(permissionId: string): Promise<import("pg").QueryResult<never>>;
|
|
32
|
+
export declare function getRolePermissions(roleId: string): Promise<{
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
}[]>;
|
|
36
|
+
export declare function assignPermissionToRole(roleId: string, permissionId: string): Promise<import("pg").QueryResult<never>>;
|
|
37
|
+
export declare function revokePermissionFromRole(roleId: string, permissionId: string): Promise<import("pg").QueryResult<never>>;
|
|
38
|
+
export declare function assignRoleToUser(userId: string, roleId: string): Promise<import("pg").QueryResult<never>>;
|
|
39
|
+
export declare function revokeRoleFromUser(userId: string, roleId: string): Promise<import("pg").QueryResult<never>>;
|
|
40
|
+
export declare function assignPermissionToUser(userId: string, permissionId: string): Promise<import("pg").QueryResult<never>>;
|
|
41
|
+
export declare function revokePermissionFromUser(userId: string, permissionId: string): Promise<import("pg").QueryResult<never>>;
|
|
42
|
+
export declare function getUserRbacData(userId: string): Promise<{
|
|
43
|
+
roles: {
|
|
44
|
+
id: string;
|
|
45
|
+
name: string;
|
|
46
|
+
}[];
|
|
47
|
+
directPermissions: {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
}[];
|
|
51
|
+
effectivePermissions: {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
}[];
|
|
55
|
+
}>;
|
|
56
|
+
//# sourceMappingURL=rbac.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../../src/core/auth/rbac.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AAIH,wBAAsB,QAAQ;;;;KAE7B;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM;;;;GAM/C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;;;;KAElE;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,4CAE9C;AAID,wBAAsB,cAAc;;;;KAKnC;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;;;;KAKxE;AAED,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,4CAI1D;AAID,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM;;;KAYtD;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,4CAMrB;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,4CAUrB;AAID,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,4CAKpE;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,4CAStE;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,4CAMrB;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,4CAUrB;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;YAwCP,MAAM;cAAQ,MAAM;;GAUhE"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
3
|
+
import { db } from "../../server/database/inject";
|
|
4
|
+
import { permissionsTable, rolesTable, rolesToPermissionsTable, usersToPermissionsTable, usersToRolesTable, } from "../../server/database/schema";
|
|
5
|
+
import { notificationService } from "../notifications/index";
|
|
6
|
+
// Ensure notification service is loaded
|
|
7
|
+
if (typeof window === "undefined") {
|
|
8
|
+
notificationService.init();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* CORE RBAC LOGIC
|
|
12
|
+
* This file handles all database operations for Roles and Permissions.
|
|
13
|
+
*/
|
|
14
|
+
// --- Roles ---
|
|
15
|
+
export async function getRoles() {
|
|
16
|
+
return await db.select().from(rolesTable).orderBy(rolesTable.name);
|
|
17
|
+
}
|
|
18
|
+
export async function getRoleById(roleId) {
|
|
19
|
+
const [role] = await db
|
|
20
|
+
.select()
|
|
21
|
+
.from(rolesTable)
|
|
22
|
+
.where(eq(rolesTable.id, roleId));
|
|
23
|
+
return role;
|
|
24
|
+
}
|
|
25
|
+
export async function createRole(name, description) {
|
|
26
|
+
return await db.insert(rolesTable).values({ name, description }).returning();
|
|
27
|
+
}
|
|
28
|
+
export async function deleteRole(roleId) {
|
|
29
|
+
return await db.delete(rolesTable).where(eq(rolesTable.id, roleId));
|
|
30
|
+
}
|
|
31
|
+
// --- Permissions ---
|
|
32
|
+
export async function getPermissions() {
|
|
33
|
+
return await db
|
|
34
|
+
.select()
|
|
35
|
+
.from(permissionsTable)
|
|
36
|
+
.orderBy(permissionsTable.name);
|
|
37
|
+
}
|
|
38
|
+
export async function createPermission(name, description) {
|
|
39
|
+
return await db
|
|
40
|
+
.insert(permissionsTable)
|
|
41
|
+
.values({ name, description })
|
|
42
|
+
.returning();
|
|
43
|
+
}
|
|
44
|
+
export async function deletePermission(permissionId) {
|
|
45
|
+
return await db
|
|
46
|
+
.delete(permissionsTable)
|
|
47
|
+
.where(eq(permissionsTable.id, permissionId));
|
|
48
|
+
}
|
|
49
|
+
// --- Mappings ---
|
|
50
|
+
export async function getRolePermissions(roleId) {
|
|
51
|
+
return await db
|
|
52
|
+
.select({
|
|
53
|
+
id: permissionsTable.id,
|
|
54
|
+
name: permissionsTable.name,
|
|
55
|
+
})
|
|
56
|
+
.from(rolesToPermissionsTable)
|
|
57
|
+
.innerJoin(permissionsTable, eq(rolesToPermissionsTable.permissionId, permissionsTable.id))
|
|
58
|
+
.where(eq(rolesToPermissionsTable.roleId, roleId));
|
|
59
|
+
}
|
|
60
|
+
export async function assignPermissionToRole(roleId, permissionId) {
|
|
61
|
+
return await db
|
|
62
|
+
.insert(rolesToPermissionsTable)
|
|
63
|
+
.values({ roleId, permissionId })
|
|
64
|
+
.onConflictDoNothing();
|
|
65
|
+
}
|
|
66
|
+
export async function revokePermissionFromRole(roleId, permissionId) {
|
|
67
|
+
return await db
|
|
68
|
+
.delete(rolesToPermissionsTable)
|
|
69
|
+
.where(and(eq(rolesToPermissionsTable.roleId, roleId), eq(rolesToPermissionsTable.permissionId, permissionId)));
|
|
70
|
+
}
|
|
71
|
+
// --- User Assignment ---
|
|
72
|
+
export async function assignRoleToUser(userId, roleId) {
|
|
73
|
+
return await db
|
|
74
|
+
.insert(usersToRolesTable)
|
|
75
|
+
.values({ userId, roleId })
|
|
76
|
+
.onConflictDoNothing();
|
|
77
|
+
}
|
|
78
|
+
export async function revokeRoleFromUser(userId, roleId) {
|
|
79
|
+
return await db
|
|
80
|
+
.delete(usersToRolesTable)
|
|
81
|
+
.where(and(eq(usersToRolesTable.userId, userId), eq(usersToRolesTable.roleId, roleId)));
|
|
82
|
+
}
|
|
83
|
+
export async function assignPermissionToUser(userId, permissionId) {
|
|
84
|
+
return await db
|
|
85
|
+
.insert(usersToPermissionsTable)
|
|
86
|
+
.values({ userId, permissionId })
|
|
87
|
+
.onConflictDoNothing();
|
|
88
|
+
}
|
|
89
|
+
export async function revokePermissionFromUser(userId, permissionId) {
|
|
90
|
+
return await db
|
|
91
|
+
.delete(usersToPermissionsTable)
|
|
92
|
+
.where(and(eq(usersToPermissionsTable.userId, userId), eq(usersToPermissionsTable.permissionId, permissionId)));
|
|
93
|
+
}
|
|
94
|
+
export async function getUserRbacData(userId) {
|
|
95
|
+
const roles = await db
|
|
96
|
+
.select({
|
|
97
|
+
id: rolesTable.id,
|
|
98
|
+
name: rolesTable.name,
|
|
99
|
+
})
|
|
100
|
+
.from(usersToRolesTable)
|
|
101
|
+
.innerJoin(rolesTable, eq(usersToRolesTable.roleId, rolesTable.id))
|
|
102
|
+
.where(eq(usersToRolesTable.userId, userId));
|
|
103
|
+
const directPermissions = await db
|
|
104
|
+
.select({
|
|
105
|
+
id: permissionsTable.id,
|
|
106
|
+
name: permissionsTable.name,
|
|
107
|
+
})
|
|
108
|
+
.from(usersToPermissionsTable)
|
|
109
|
+
.innerJoin(permissionsTable, eq(usersToPermissionsTable.permissionId, permissionsTable.id))
|
|
110
|
+
.where(eq(usersToPermissionsTable.userId, userId));
|
|
111
|
+
// Fetch inherited permissions from roles
|
|
112
|
+
let rolePermissions = [];
|
|
113
|
+
if (roles.length > 0) {
|
|
114
|
+
const roleIds = roles.map((r) => r.id);
|
|
115
|
+
rolePermissions = await db
|
|
116
|
+
.select({
|
|
117
|
+
id: permissionsTable.id,
|
|
118
|
+
name: permissionsTable.name,
|
|
119
|
+
})
|
|
120
|
+
.from(rolesToPermissionsTable)
|
|
121
|
+
.innerJoin(permissionsTable, eq(rolesToPermissionsTable.permissionId, permissionsTable.id))
|
|
122
|
+
.where(inArray(rolesToPermissionsTable.roleId, roleIds));
|
|
123
|
+
}
|
|
124
|
+
// Combine for effective permissions
|
|
125
|
+
const effectiveMap = new Map();
|
|
126
|
+
for (const p of [...directPermissions, ...rolePermissions]) {
|
|
127
|
+
effectiveMap.set(p.id, p);
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
roles,
|
|
131
|
+
directPermissions,
|
|
132
|
+
effectivePermissions: Array.from(effectiveMap.values()),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { AuthSession, Session, SessionFlags, UserSession } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the user's IP address.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getIPAddress(): Promise<string | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Validates the session token.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateSessionToken(token: string): Promise<AuthSession>;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the current user session from cookies.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getCurrentSession: () => Promise<AuthSession>;
|
|
14
|
+
/**
|
|
15
|
+
* Invalidates a single session.
|
|
16
|
+
*/
|
|
17
|
+
export declare function invalidateSession(sessionId: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Invalidates all user sessions.
|
|
20
|
+
*/
|
|
21
|
+
export declare function invalidateUserSessions(userId: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Sets the session token in a cookie.
|
|
24
|
+
*/
|
|
25
|
+
export declare function setSessionTokenCookie(token: string, expiresAt: Date): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Removes the session token cookie.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deleteSessionTokenCookie(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Generates a new random session token.
|
|
32
|
+
*/
|
|
33
|
+
export declare function generateSessionToken(): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new session in the database.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createSession(token: string, userId: string, flags: SessionFlags): Promise<Session>;
|
|
38
|
+
/**
|
|
39
|
+
* Signs the user out and redirects to the sign-in page.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sessionSignOut(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Get all active sessions for a user.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getUserSessions(userId: string, currentSessionId: string): Promise<UserSession[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Invalidate all sessions for a user except the specified current one.
|
|
48
|
+
*/
|
|
49
|
+
export declare function invalidateOtherSessions(userId: string, currentSessionId: string): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/core/auth/session.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,WAAW,EACX,OAAO,EACP,YAAY,EAEZ,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE3D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC,CAoCtB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,WAAW,CAS7D,CAAC;AAEF;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAI5D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;GAEG;AACH,wBAAsB,cAAc,kBASnC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { sha256 } from "@oslojs/crypto/sha2";
|
|
3
|
+
import { encodeBase32LowerCaseNoPadding, encodeHexLowerCase, } from "@oslojs/encoding";
|
|
4
|
+
import { addDays } from "date-fns";
|
|
5
|
+
import { and, eq, ne } from "drizzle-orm";
|
|
6
|
+
import { cookies, headers } from "next/headers";
|
|
7
|
+
import { redirect } from "next/navigation";
|
|
8
|
+
import { db } from "../../server/database/inject";
|
|
9
|
+
import { sessionTable, userTable } from "../../server/database/schema";
|
|
10
|
+
import { augmentSession } from "./augment";
|
|
11
|
+
import { performFullUserAugmentation } from "./logic";
|
|
12
|
+
/**
|
|
13
|
+
* Returns the user's IP address.
|
|
14
|
+
*/
|
|
15
|
+
export async function getIPAddress() {
|
|
16
|
+
return (await headers()).get("x-forwarded-for");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validates the session token.
|
|
20
|
+
*/
|
|
21
|
+
export async function validateSessionToken(token) {
|
|
22
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
23
|
+
const [row] = await db
|
|
24
|
+
.select({
|
|
25
|
+
session: sessionTable,
|
|
26
|
+
user: userTable,
|
|
27
|
+
})
|
|
28
|
+
.from(sessionTable)
|
|
29
|
+
.innerJoin(userTable, eq(sessionTable.userId, userTable.id))
|
|
30
|
+
.where(eq(sessionTable.id, sessionId));
|
|
31
|
+
if (!row || !row.user) {
|
|
32
|
+
return { session: null, user: null };
|
|
33
|
+
}
|
|
34
|
+
const { session: baseSession, user: baseUser } = row;
|
|
35
|
+
// STRICTLY remove non-serializable and sensitive fields
|
|
36
|
+
const { password, recovery_code, ...safeUser } = baseUser;
|
|
37
|
+
// Check if session is expired
|
|
38
|
+
if (new Date() > baseSession.expiresAt) {
|
|
39
|
+
await db.delete(sessionTable).where(eq(sessionTable.id, baseSession.id));
|
|
40
|
+
return { session: null, user: null };
|
|
41
|
+
}
|
|
42
|
+
// AUGMENT (EXTENSIBILITY POINTS)
|
|
43
|
+
const augmentedUser = await performFullUserAugmentation(safeUser);
|
|
44
|
+
const augmentedSession = await augmentSession(baseSession);
|
|
45
|
+
// ENSURE PLAIN OBJECTS for Client Components
|
|
46
|
+
return {
|
|
47
|
+
session: augmentedSession ? { ...augmentedSession } : null,
|
|
48
|
+
user: augmentedUser ? { ...augmentedUser } : null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the current user session from cookies.
|
|
53
|
+
*/
|
|
54
|
+
export const getCurrentSession = async () => {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
const cookieStore = await cookies();
|
|
57
|
+
const token = (_b = (_a = cookieStore.get("session")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
|
|
58
|
+
if (token === null) {
|
|
59
|
+
return { session: null, user: null };
|
|
60
|
+
}
|
|
61
|
+
return await validateSessionToken(token);
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Invalidates a single session.
|
|
65
|
+
*/
|
|
66
|
+
export async function invalidateSession(sessionId) {
|
|
67
|
+
await db.delete(sessionTable).where(eq(sessionTable.id, sessionId));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Invalidates all user sessions.
|
|
71
|
+
*/
|
|
72
|
+
export async function invalidateUserSessions(userId) {
|
|
73
|
+
await db.delete(sessionTable).where(eq(sessionTable.userId, userId));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sets the session token in a cookie.
|
|
77
|
+
*/
|
|
78
|
+
export async function setSessionTokenCookie(token, expiresAt) {
|
|
79
|
+
const cookieStore = await cookies();
|
|
80
|
+
cookieStore.set("session", token, {
|
|
81
|
+
httpOnly: true,
|
|
82
|
+
path: "/",
|
|
83
|
+
secure: process.env.NODE_ENV === "production",
|
|
84
|
+
sameSite: "lax",
|
|
85
|
+
expires: expiresAt,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Removes the session token cookie.
|
|
90
|
+
*/
|
|
91
|
+
export async function deleteSessionTokenCookie() {
|
|
92
|
+
const cookieStore = await cookies();
|
|
93
|
+
cookieStore.delete("session");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Generates a new random session token.
|
|
97
|
+
*/
|
|
98
|
+
export async function generateSessionToken() {
|
|
99
|
+
const tokenBytes = new Uint8Array(20);
|
|
100
|
+
crypto.getRandomValues(tokenBytes);
|
|
101
|
+
return encodeBase32LowerCaseNoPadding(tokenBytes).toLowerCase();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new session in the database.
|
|
105
|
+
*/
|
|
106
|
+
export async function createSession(token, userId, flags) {
|
|
107
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
108
|
+
const [session] = await db
|
|
109
|
+
.insert(sessionTable)
|
|
110
|
+
.values({
|
|
111
|
+
id: sessionId,
|
|
112
|
+
expiresAt: new Date(addDays(new Date(), 7)),
|
|
113
|
+
active_organization_id: flags.activeOrganizationId,
|
|
114
|
+
userId: userId,
|
|
115
|
+
})
|
|
116
|
+
.returning();
|
|
117
|
+
return session;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Signs the user out and redirects to the sign-in page.
|
|
121
|
+
*/
|
|
122
|
+
export async function sessionSignOut() {
|
|
123
|
+
const { session } = await getCurrentSession();
|
|
124
|
+
if (session) {
|
|
125
|
+
await invalidateSession(session.id);
|
|
126
|
+
await deleteSessionTokenCookie();
|
|
127
|
+
}
|
|
128
|
+
redirect("/signin");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get all active sessions for a user.
|
|
132
|
+
*/
|
|
133
|
+
export async function getUserSessions(userId, currentSessionId) {
|
|
134
|
+
const sessions = await db
|
|
135
|
+
.select()
|
|
136
|
+
.from(sessionTable)
|
|
137
|
+
.where(eq(sessionTable.userId, userId));
|
|
138
|
+
return sessions.map((session) => ({
|
|
139
|
+
id: session.id,
|
|
140
|
+
createdAt: session.createdAt,
|
|
141
|
+
expiresAt: session.expiresAt,
|
|
142
|
+
isCurrent: session.id === currentSessionId,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Invalidate all sessions for a user except the specified current one.
|
|
147
|
+
*/
|
|
148
|
+
export async function invalidateOtherSessions(userId, currentSessionId) {
|
|
149
|
+
await db
|
|
150
|
+
.delete(sessionTable)
|
|
151
|
+
.where(and(eq(sessionTable.userId, userId), ne(sessionTable.id, currentSessionId)));
|
|
152
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { passwordResetSessionTable, sessionTable, userTable } from "../../server/database/schema";
|
|
2
|
+
import type { UserPermission, UserRole } from "../types";
|
|
3
|
+
export type { UserRole, UserPermission };
|
|
4
|
+
export type User = typeof userTable.$inferSelect;
|
|
5
|
+
export type Session = typeof sessionTable.$inferSelect & Record<string, any>;
|
|
6
|
+
export type PasswordResetSession = typeof passwordResetSessionTable.$inferSelect & Record<string, any>;
|
|
7
|
+
/**
|
|
8
|
+
* Represents a user with all potential extensions.
|
|
9
|
+
* Use this type in UI components that require data added by modules.
|
|
10
|
+
*/
|
|
11
|
+
export type FullUser = User & Record<string, any> & {
|
|
12
|
+
roles: UserRole[];
|
|
13
|
+
permissions: UserPermission[];
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Basic session context.
|
|
17
|
+
*/
|
|
18
|
+
export interface AuthSession {
|
|
19
|
+
session: Session | null;
|
|
20
|
+
user: FullUser | null;
|
|
21
|
+
}
|
|
22
|
+
export interface SessionFlags {
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
export type UserSession = {
|
|
26
|
+
id: string;
|
|
27
|
+
createdAt: Date;
|
|
28
|
+
expiresAt: Date;
|
|
29
|
+
isCurrent: boolean;
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
};
|
|
32
|
+
export type AuthResponse = {
|
|
33
|
+
status: "SUCCESS";
|
|
34
|
+
session: Session;
|
|
35
|
+
user: FullUser;
|
|
36
|
+
redirect?: string;
|
|
37
|
+
} | {
|
|
38
|
+
status: "CHALLENGE_REQUIRED";
|
|
39
|
+
type: string;
|
|
40
|
+
userId: string;
|
|
41
|
+
tempToken?: string;
|
|
42
|
+
redirect?: string;
|
|
43
|
+
} | {
|
|
44
|
+
status: "ERROR";
|
|
45
|
+
message: string;
|
|
46
|
+
redirect?: string;
|
|
47
|
+
};
|
|
48
|
+
export interface PasswordResetAuthSession {
|
|
49
|
+
session: PasswordResetSession | null;
|
|
50
|
+
user: FullUser | null;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,YAAY,EACZ,SAAS,EACV,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAEzC,MAAM,MAAM,IAAI,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,OAAO,YAAY,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC7E,MAAM,MAAM,oBAAoB,GAC9B,OAAO,yBAAyB,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAEtE;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,IAAI,GACzB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B,CAAC;AAEJ;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E;IACA,MAAM,EAAE,oBAAoB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a random one-time code (OTP).
|
|
3
|
+
* @param length Length of the generated code (default 6).
|
|
4
|
+
* @returns A random uppercase base32 string.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateRandomOTP(length?: number): string;
|
|
7
|
+
/**
|
|
8
|
+
* Generates a random recovery code.
|
|
9
|
+
* @returns A random uppercase base32 string.
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateRandomRecoveryCode(): string;
|
|
12
|
+
//# sourceMappingURL=encode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../../../src/core/auth/utils/encode.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAI,GAAG,MAAM,CAIpD;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAInD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { encodeBase32UpperCaseNoPadding } from "@oslojs/encoding";
|
|
2
|
+
/**
|
|
3
|
+
* Generates a random one-time code (OTP).
|
|
4
|
+
* @param length Length of the generated code (default 6).
|
|
5
|
+
* @returns A random uppercase base32 string.
|
|
6
|
+
*/
|
|
7
|
+
export function generateRandomOTP(length = 6) {
|
|
8
|
+
const bytes = new Uint8Array(5);
|
|
9
|
+
crypto.getRandomValues(bytes);
|
|
10
|
+
return encodeBase32UpperCaseNoPadding(bytes).substring(0, length);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generates a random recovery code.
|
|
14
|
+
* @returns A random uppercase base32 string.
|
|
15
|
+
*/
|
|
16
|
+
export function generateRandomRecoveryCode() {
|
|
17
|
+
const recoveryCodeBytes = new Uint8Array(10);
|
|
18
|
+
crypto.getRandomValues(recoveryCodeBytes);
|
|
19
|
+
return encodeBase32UpperCaseNoPadding(recoveryCodeBytes);
|
|
20
|
+
}
|