@arch-cadre/core 0.0.41 → 0.0.43
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.js +6 -14
- package/dist/core/auth/email-verification.js +33 -43
- package/dist/core/auth/events.js +1 -2
- package/dist/core/auth/logic.js +71 -90
- package/dist/core/auth/password-reset.js +46 -56
- package/dist/core/auth/rbac.js +73 -90
- package/dist/core/auth/session.js +51 -66
- package/dist/core/auth/types.js +1 -2
- package/dist/core/auth/utils/encode.js +5 -9
- package/dist/core/auth/utils/encryption.js +12 -18
- package/dist/core/auth/validation.js +25 -28
- package/dist/core/bootstrap.js +16 -19
- package/dist/core/config.js +1 -4
- package/dist/core/config.server.js +14 -54
- package/dist/core/event-bus.js +2 -5
- package/dist/core/filesystem/index.js +7 -24
- package/dist/core/filesystem/providers/local.js +7 -14
- package/dist/core/filesystem/service.js +2 -5
- package/dist/core/filesystem/types.js +1 -2
- package/dist/core/notifications/actions.js +22 -28
- package/dist/core/notifications/index.js +3 -19
- package/dist/core/notifications/service.js +6 -9
- package/dist/core/notifications/types.js +1 -2
- package/dist/core/setup.js +7 -10
- package/dist/core/types.js +1 -2
- package/dist/index.js +7 -23
- package/dist/server/auth/email.js +9 -13
- package/dist/server/auth/password.js +6 -14
- package/dist/server/auth/types.js +1 -17
- package/dist/server/auth/user.js +76 -91
- package/dist/server/database/inject.js +2 -6
- package/dist/server/database/schema.js +107 -110
- package/dist/server/database/types.js +1 -2
- package/dist/server/emails/index.js +4 -10
- package/dist/server.js +24 -40
- package/package.json +2 -4
package/dist/core/auth/rbac.js
CHANGED
|
@@ -1,142 +1,125 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
"use server";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.deleteRole = deleteRole;
|
|
8
|
-
exports.getPermissions = getPermissions;
|
|
9
|
-
exports.createPermission = createPermission;
|
|
10
|
-
exports.deletePermission = deletePermission;
|
|
11
|
-
exports.getRolePermissions = getRolePermissions;
|
|
12
|
-
exports.assignPermissionToRole = assignPermissionToRole;
|
|
13
|
-
exports.revokePermissionFromRole = revokePermissionFromRole;
|
|
14
|
-
exports.assignRoleToUser = assignRoleToUser;
|
|
15
|
-
exports.revokeRoleFromUser = revokeRoleFromUser;
|
|
16
|
-
exports.assignPermissionToUser = assignPermissionToUser;
|
|
17
|
-
exports.revokePermissionFromUser = revokePermissionFromUser;
|
|
18
|
-
exports.getUserRbacData = getUserRbacData;
|
|
19
|
-
const drizzle_orm_1 = require("drizzle-orm");
|
|
20
|
-
const inject_1 = require("../../server/database/inject");
|
|
21
|
-
const schema_1 = require("../../server/database/schema");
|
|
22
|
-
const index_1 = require("../notifications/index");
|
|
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";
|
|
23
6
|
// Ensure notification service is loaded
|
|
24
7
|
if (typeof window === "undefined") {
|
|
25
|
-
|
|
8
|
+
notificationService.init();
|
|
26
9
|
}
|
|
27
10
|
/**
|
|
28
11
|
* CORE RBAC LOGIC
|
|
29
12
|
* This file handles all database operations for Roles and Permissions.
|
|
30
13
|
*/
|
|
31
14
|
// --- Roles ---
|
|
32
|
-
async function getRoles() {
|
|
33
|
-
return await
|
|
15
|
+
export async function getRoles() {
|
|
16
|
+
return await db.select().from(rolesTable).orderBy(rolesTable.name);
|
|
34
17
|
}
|
|
35
|
-
async function getRoleById(roleId) {
|
|
36
|
-
const [role] = await
|
|
18
|
+
export async function getRoleById(roleId) {
|
|
19
|
+
const [role] = await db
|
|
37
20
|
.select()
|
|
38
|
-
.from(
|
|
39
|
-
.where(
|
|
21
|
+
.from(rolesTable)
|
|
22
|
+
.where(eq(rolesTable.id, roleId));
|
|
40
23
|
return role;
|
|
41
24
|
}
|
|
42
|
-
async function createRole(name, description) {
|
|
43
|
-
return await
|
|
25
|
+
export async function createRole(name, description) {
|
|
26
|
+
return await db.insert(rolesTable).values({ name, description }).returning();
|
|
44
27
|
}
|
|
45
|
-
async function deleteRole(roleId) {
|
|
46
|
-
return await
|
|
28
|
+
export async function deleteRole(roleId) {
|
|
29
|
+
return await db.delete(rolesTable).where(eq(rolesTable.id, roleId));
|
|
47
30
|
}
|
|
48
31
|
// --- Permissions ---
|
|
49
|
-
async function getPermissions() {
|
|
50
|
-
return await
|
|
32
|
+
export async function getPermissions() {
|
|
33
|
+
return await db
|
|
51
34
|
.select()
|
|
52
|
-
.from(
|
|
53
|
-
.orderBy(
|
|
35
|
+
.from(permissionsTable)
|
|
36
|
+
.orderBy(permissionsTable.name);
|
|
54
37
|
}
|
|
55
|
-
async function createPermission(name, description) {
|
|
56
|
-
return await
|
|
57
|
-
.insert(
|
|
38
|
+
export async function createPermission(name, description) {
|
|
39
|
+
return await db
|
|
40
|
+
.insert(permissionsTable)
|
|
58
41
|
.values({ name, description })
|
|
59
42
|
.returning();
|
|
60
43
|
}
|
|
61
|
-
async function deletePermission(permissionId) {
|
|
62
|
-
return await
|
|
63
|
-
.delete(
|
|
64
|
-
.where(
|
|
44
|
+
export async function deletePermission(permissionId) {
|
|
45
|
+
return await db
|
|
46
|
+
.delete(permissionsTable)
|
|
47
|
+
.where(eq(permissionsTable.id, permissionId));
|
|
65
48
|
}
|
|
66
49
|
// --- Mappings ---
|
|
67
|
-
async function getRolePermissions(roleId) {
|
|
68
|
-
return await
|
|
50
|
+
export async function getRolePermissions(roleId) {
|
|
51
|
+
return await db
|
|
69
52
|
.select({
|
|
70
|
-
id:
|
|
71
|
-
name:
|
|
53
|
+
id: permissionsTable.id,
|
|
54
|
+
name: permissionsTable.name,
|
|
72
55
|
})
|
|
73
|
-
.from(
|
|
74
|
-
.innerJoin(
|
|
75
|
-
.where(
|
|
56
|
+
.from(rolesToPermissionsTable)
|
|
57
|
+
.innerJoin(permissionsTable, eq(rolesToPermissionsTable.permissionId, permissionsTable.id))
|
|
58
|
+
.where(eq(rolesToPermissionsTable.roleId, roleId));
|
|
76
59
|
}
|
|
77
|
-
async function assignPermissionToRole(roleId, permissionId) {
|
|
78
|
-
return await
|
|
79
|
-
.insert(
|
|
60
|
+
export async function assignPermissionToRole(roleId, permissionId) {
|
|
61
|
+
return await db
|
|
62
|
+
.insert(rolesToPermissionsTable)
|
|
80
63
|
.values({ roleId, permissionId })
|
|
81
64
|
.onConflictDoNothing();
|
|
82
65
|
}
|
|
83
|
-
async function revokePermissionFromRole(roleId, permissionId) {
|
|
84
|
-
return await
|
|
85
|
-
.delete(
|
|
86
|
-
.where(
|
|
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)));
|
|
87
70
|
}
|
|
88
71
|
// --- User Assignment ---
|
|
89
|
-
async function assignRoleToUser(userId, roleId) {
|
|
90
|
-
return await
|
|
91
|
-
.insert(
|
|
72
|
+
export async function assignRoleToUser(userId, roleId) {
|
|
73
|
+
return await db
|
|
74
|
+
.insert(usersToRolesTable)
|
|
92
75
|
.values({ userId, roleId })
|
|
93
76
|
.onConflictDoNothing();
|
|
94
77
|
}
|
|
95
|
-
async function revokeRoleFromUser(userId, roleId) {
|
|
96
|
-
return await
|
|
97
|
-
.delete(
|
|
98
|
-
.where(
|
|
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)));
|
|
99
82
|
}
|
|
100
|
-
async function assignPermissionToUser(userId, permissionId) {
|
|
101
|
-
return await
|
|
102
|
-
.insert(
|
|
83
|
+
export async function assignPermissionToUser(userId, permissionId) {
|
|
84
|
+
return await db
|
|
85
|
+
.insert(usersToPermissionsTable)
|
|
103
86
|
.values({ userId, permissionId })
|
|
104
87
|
.onConflictDoNothing();
|
|
105
88
|
}
|
|
106
|
-
async function revokePermissionFromUser(userId, permissionId) {
|
|
107
|
-
return await
|
|
108
|
-
.delete(
|
|
109
|
-
.where(
|
|
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)));
|
|
110
93
|
}
|
|
111
|
-
async function getUserRbacData(userId) {
|
|
112
|
-
const roles = await
|
|
94
|
+
export async function getUserRbacData(userId) {
|
|
95
|
+
const roles = await db
|
|
113
96
|
.select({
|
|
114
|
-
id:
|
|
115
|
-
name:
|
|
97
|
+
id: rolesTable.id,
|
|
98
|
+
name: rolesTable.name,
|
|
116
99
|
})
|
|
117
|
-
.from(
|
|
118
|
-
.innerJoin(
|
|
119
|
-
.where(
|
|
120
|
-
const directPermissions = await
|
|
100
|
+
.from(usersToRolesTable)
|
|
101
|
+
.innerJoin(rolesTable, eq(usersToRolesTable.roleId, rolesTable.id))
|
|
102
|
+
.where(eq(usersToRolesTable.userId, userId));
|
|
103
|
+
const directPermissions = await db
|
|
121
104
|
.select({
|
|
122
|
-
id:
|
|
123
|
-
name:
|
|
105
|
+
id: permissionsTable.id,
|
|
106
|
+
name: permissionsTable.name,
|
|
124
107
|
})
|
|
125
|
-
.from(
|
|
126
|
-
.innerJoin(
|
|
127
|
-
.where(
|
|
108
|
+
.from(usersToPermissionsTable)
|
|
109
|
+
.innerJoin(permissionsTable, eq(usersToPermissionsTable.permissionId, permissionsTable.id))
|
|
110
|
+
.where(eq(usersToPermissionsTable.userId, userId));
|
|
128
111
|
// Fetch inherited permissions from roles
|
|
129
112
|
let rolePermissions = [];
|
|
130
113
|
if (roles.length > 0) {
|
|
131
114
|
const roleIds = roles.map((r) => r.id);
|
|
132
|
-
rolePermissions = await
|
|
115
|
+
rolePermissions = await db
|
|
133
116
|
.select({
|
|
134
|
-
id:
|
|
135
|
-
name:
|
|
117
|
+
id: permissionsTable.id,
|
|
118
|
+
name: permissionsTable.name,
|
|
136
119
|
})
|
|
137
|
-
.from(
|
|
138
|
-
.innerJoin(
|
|
139
|
-
.where(
|
|
120
|
+
.from(rolesToPermissionsTable)
|
|
121
|
+
.innerJoin(permissionsTable, eq(rolesToPermissionsTable.permissionId, permissionsTable.id))
|
|
122
|
+
.where(inArray(rolesToPermissionsTable.roleId, roleIds));
|
|
140
123
|
}
|
|
141
124
|
// Combine for effective permissions
|
|
142
125
|
const effectiveMap = new Map();
|
|
@@ -1,47 +1,33 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
"use server";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
exports.sessionSignOut = sessionSignOut;
|
|
14
|
-
exports.getUserSessions = getUserSessions;
|
|
15
|
-
exports.invalidateOtherSessions = invalidateOtherSessions;
|
|
16
|
-
const sha2_1 = require("@oslojs/crypto/sha2");
|
|
17
|
-
const encoding_1 = require("@oslojs/encoding");
|
|
18
|
-
const date_fns_1 = require("date-fns");
|
|
19
|
-
const drizzle_orm_1 = require("drizzle-orm");
|
|
20
|
-
const headers_1 = require("next/headers");
|
|
21
|
-
const navigation_1 = require("next/navigation");
|
|
22
|
-
const inject_1 = require("../../server/database/inject");
|
|
23
|
-
const schema_1 = require("../../server/database/schema");
|
|
24
|
-
const augment_1 = require("./augment");
|
|
25
|
-
const logic_1 = require("./logic");
|
|
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";
|
|
26
12
|
/**
|
|
27
13
|
* Returns the user's IP address.
|
|
28
14
|
*/
|
|
29
|
-
async function getIPAddress() {
|
|
30
|
-
return (await
|
|
15
|
+
export async function getIPAddress() {
|
|
16
|
+
return (await headers()).get("x-forwarded-for");
|
|
31
17
|
}
|
|
32
18
|
/**
|
|
33
19
|
* Validates the session token.
|
|
34
20
|
*/
|
|
35
|
-
async function validateSessionToken(token) {
|
|
36
|
-
const sessionId =
|
|
37
|
-
const [row] = await
|
|
21
|
+
export async function validateSessionToken(token) {
|
|
22
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
23
|
+
const [row] = await db
|
|
38
24
|
.select({
|
|
39
|
-
session:
|
|
40
|
-
user:
|
|
25
|
+
session: sessionTable,
|
|
26
|
+
user: userTable,
|
|
41
27
|
})
|
|
42
|
-
.from(
|
|
43
|
-
.innerJoin(
|
|
44
|
-
.where(
|
|
28
|
+
.from(sessionTable)
|
|
29
|
+
.innerJoin(userTable, eq(sessionTable.userId, userTable.id))
|
|
30
|
+
.where(eq(sessionTable.id, sessionId));
|
|
45
31
|
if (!row || !row.user) {
|
|
46
32
|
return { session: null, user: null };
|
|
47
33
|
}
|
|
@@ -50,12 +36,12 @@ async function validateSessionToken(token) {
|
|
|
50
36
|
const { password, recovery_code, ...safeUser } = baseUser;
|
|
51
37
|
// Check if session is expired
|
|
52
38
|
if (new Date() > baseSession.expiresAt) {
|
|
53
|
-
await
|
|
39
|
+
await db.delete(sessionTable).where(eq(sessionTable.id, baseSession.id));
|
|
54
40
|
return { session: null, user: null };
|
|
55
41
|
}
|
|
56
42
|
// AUGMENT (EXTENSIBILITY POINTS)
|
|
57
|
-
const augmentedUser = await
|
|
58
|
-
const augmentedSession = await
|
|
43
|
+
const augmentedUser = await performFullUserAugmentation(safeUser);
|
|
44
|
+
const augmentedSession = await augmentSession(baseSession);
|
|
59
45
|
// ENSURE PLAIN OBJECTS for Client Components
|
|
60
46
|
return {
|
|
61
47
|
session: augmentedSession ? { ...augmentedSession } : null,
|
|
@@ -65,33 +51,32 @@ async function validateSessionToken(token) {
|
|
|
65
51
|
/**
|
|
66
52
|
* Returns the current user session from cookies.
|
|
67
53
|
*/
|
|
68
|
-
const getCurrentSession = async () => {
|
|
54
|
+
export const getCurrentSession = async () => {
|
|
69
55
|
var _a, _b;
|
|
70
|
-
const cookieStore = await
|
|
56
|
+
const cookieStore = await cookies();
|
|
71
57
|
const token = (_b = (_a = cookieStore.get("session")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
|
|
72
58
|
if (token === null) {
|
|
73
59
|
return { session: null, user: null };
|
|
74
60
|
}
|
|
75
61
|
return await validateSessionToken(token);
|
|
76
62
|
};
|
|
77
|
-
exports.getCurrentSession = getCurrentSession;
|
|
78
63
|
/**
|
|
79
64
|
* Invalidates a single session.
|
|
80
65
|
*/
|
|
81
|
-
async function invalidateSession(sessionId) {
|
|
82
|
-
await
|
|
66
|
+
export async function invalidateSession(sessionId) {
|
|
67
|
+
await db.delete(sessionTable).where(eq(sessionTable.id, sessionId));
|
|
83
68
|
}
|
|
84
69
|
/**
|
|
85
70
|
* Invalidates all user sessions.
|
|
86
71
|
*/
|
|
87
|
-
async function invalidateUserSessions(userId) {
|
|
88
|
-
await
|
|
72
|
+
export async function invalidateUserSessions(userId) {
|
|
73
|
+
await db.delete(sessionTable).where(eq(sessionTable.userId, userId));
|
|
89
74
|
}
|
|
90
75
|
/**
|
|
91
76
|
* Sets the session token in a cookie.
|
|
92
77
|
*/
|
|
93
|
-
async function setSessionTokenCookie(token, expiresAt) {
|
|
94
|
-
const cookieStore = await
|
|
78
|
+
export async function setSessionTokenCookie(token, expiresAt) {
|
|
79
|
+
const cookieStore = await cookies();
|
|
95
80
|
cookieStore.set("session", token, {
|
|
96
81
|
httpOnly: true,
|
|
97
82
|
path: "/",
|
|
@@ -103,28 +88,28 @@ async function setSessionTokenCookie(token, expiresAt) {
|
|
|
103
88
|
/**
|
|
104
89
|
* Removes the session token cookie.
|
|
105
90
|
*/
|
|
106
|
-
async function deleteSessionTokenCookie() {
|
|
107
|
-
const cookieStore = await
|
|
91
|
+
export async function deleteSessionTokenCookie() {
|
|
92
|
+
const cookieStore = await cookies();
|
|
108
93
|
cookieStore.delete("session");
|
|
109
94
|
}
|
|
110
95
|
/**
|
|
111
96
|
* Generates a new random session token.
|
|
112
97
|
*/
|
|
113
|
-
async function generateSessionToken() {
|
|
98
|
+
export async function generateSessionToken() {
|
|
114
99
|
const tokenBytes = new Uint8Array(20);
|
|
115
100
|
crypto.getRandomValues(tokenBytes);
|
|
116
|
-
return
|
|
101
|
+
return encodeBase32LowerCaseNoPadding(tokenBytes).toLowerCase();
|
|
117
102
|
}
|
|
118
103
|
/**
|
|
119
104
|
* Creates a new session in the database.
|
|
120
105
|
*/
|
|
121
|
-
async function createSession(token, userId, flags) {
|
|
122
|
-
const sessionId =
|
|
123
|
-
const [session] = await
|
|
124
|
-
.insert(
|
|
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)
|
|
125
110
|
.values({
|
|
126
111
|
id: sessionId,
|
|
127
|
-
expiresAt: new Date(
|
|
112
|
+
expiresAt: new Date(addDays(new Date(), 7)),
|
|
128
113
|
active_organization_id: flags.activeOrganizationId,
|
|
129
114
|
userId: userId,
|
|
130
115
|
})
|
|
@@ -134,22 +119,22 @@ async function createSession(token, userId, flags) {
|
|
|
134
119
|
/**
|
|
135
120
|
* Signs the user out and redirects to the sign-in page.
|
|
136
121
|
*/
|
|
137
|
-
async function sessionSignOut() {
|
|
138
|
-
const { session } = await
|
|
122
|
+
export async function sessionSignOut() {
|
|
123
|
+
const { session } = await getCurrentSession();
|
|
139
124
|
if (session) {
|
|
140
125
|
await invalidateSession(session.id);
|
|
141
126
|
await deleteSessionTokenCookie();
|
|
142
127
|
}
|
|
143
|
-
|
|
128
|
+
redirect("/signin");
|
|
144
129
|
}
|
|
145
130
|
/**
|
|
146
131
|
* Get all active sessions for a user.
|
|
147
132
|
*/
|
|
148
|
-
async function getUserSessions(userId, currentSessionId) {
|
|
149
|
-
const sessions = await
|
|
133
|
+
export async function getUserSessions(userId, currentSessionId) {
|
|
134
|
+
const sessions = await db
|
|
150
135
|
.select()
|
|
151
|
-
.from(
|
|
152
|
-
.where(
|
|
136
|
+
.from(sessionTable)
|
|
137
|
+
.where(eq(sessionTable.userId, userId));
|
|
153
138
|
return sessions.map((session) => ({
|
|
154
139
|
id: session.id,
|
|
155
140
|
createdAt: session.createdAt,
|
|
@@ -160,8 +145,8 @@ async function getUserSessions(userId, currentSessionId) {
|
|
|
160
145
|
/**
|
|
161
146
|
* Invalidate all sessions for a user except the specified current one.
|
|
162
147
|
*/
|
|
163
|
-
async function invalidateOtherSessions(userId, currentSessionId) {
|
|
164
|
-
await
|
|
165
|
-
.delete(
|
|
166
|
-
.where(
|
|
148
|
+
export async function invalidateOtherSessions(userId, currentSessionId) {
|
|
149
|
+
await db
|
|
150
|
+
.delete(sessionTable)
|
|
151
|
+
.where(and(eq(sessionTable.userId, userId), ne(sessionTable.id, currentSessionId)));
|
|
167
152
|
}
|
package/dist/core/auth/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateRandomOTP = generateRandomOTP;
|
|
4
|
-
exports.generateRandomRecoveryCode = generateRandomRecoveryCode;
|
|
5
|
-
const encoding_1 = require("@oslojs/encoding");
|
|
1
|
+
import { encodeBase32UpperCaseNoPadding } from "@oslojs/encoding";
|
|
6
2
|
/**
|
|
7
3
|
* Generates a random one-time code (OTP).
|
|
8
4
|
* @param length Length of the generated code (default 6).
|
|
9
5
|
* @returns A random uppercase base32 string.
|
|
10
6
|
*/
|
|
11
|
-
function generateRandomOTP(length = 6) {
|
|
7
|
+
export function generateRandomOTP(length = 6) {
|
|
12
8
|
const bytes = new Uint8Array(5);
|
|
13
9
|
crypto.getRandomValues(bytes);
|
|
14
|
-
return
|
|
10
|
+
return encodeBase32UpperCaseNoPadding(bytes).substring(0, length);
|
|
15
11
|
}
|
|
16
12
|
/**
|
|
17
13
|
* Generates a random recovery code.
|
|
18
14
|
* @returns A random uppercase base32 string.
|
|
19
15
|
*/
|
|
20
|
-
function generateRandomRecoveryCode() {
|
|
16
|
+
export function generateRandomRecoveryCode() {
|
|
21
17
|
const recoveryCodeBytes = new Uint8Array(10);
|
|
22
18
|
crypto.getRandomValues(recoveryCodeBytes);
|
|
23
|
-
return
|
|
19
|
+
return encodeBase32UpperCaseNoPadding(recoveryCodeBytes);
|
|
24
20
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.encryptString = encryptString;
|
|
5
|
-
exports.decrypt = decrypt;
|
|
6
|
-
exports.decryptToString = decryptToString;
|
|
7
|
-
const node_crypto_1 = require("node:crypto");
|
|
8
|
-
const binary_1 = require("@oslojs/binary");
|
|
9
|
-
const encoding_1 = require("@oslojs/encoding");
|
|
1
|
+
import { createCipheriv, createDecipheriv } from "node:crypto";
|
|
2
|
+
import { DynamicBuffer } from "@oslojs/binary";
|
|
3
|
+
import { decodeBase64 } from "@oslojs/encoding";
|
|
10
4
|
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY;
|
|
11
5
|
if (!ENCRYPTION_KEY) {
|
|
12
6
|
throw new Error("ENCRYPTION_KEY environment variable is not set");
|
|
@@ -14,17 +8,17 @@ if (!ENCRYPTION_KEY) {
|
|
|
14
8
|
/**
|
|
15
9
|
* The encryption key decoded from base64.
|
|
16
10
|
*/
|
|
17
|
-
const key =
|
|
11
|
+
const key = decodeBase64(ENCRYPTION_KEY);
|
|
18
12
|
/**
|
|
19
13
|
* Encrypts data using AES-128-GCM.
|
|
20
14
|
* @param data Data to be encrypted.
|
|
21
15
|
* @returns Encrypted data including IV and auth tag.
|
|
22
16
|
*/
|
|
23
|
-
function encrypt(data) {
|
|
17
|
+
export function encrypt(data) {
|
|
24
18
|
const iv = new Uint8Array(16);
|
|
25
19
|
crypto.getRandomValues(iv);
|
|
26
|
-
const cipher =
|
|
27
|
-
const encrypted = new
|
|
20
|
+
const cipher = createCipheriv("aes-128-gcm", key, iv);
|
|
21
|
+
const encrypted = new DynamicBuffer(0);
|
|
28
22
|
encrypted.write(iv);
|
|
29
23
|
encrypted.write(cipher.update(data));
|
|
30
24
|
encrypted.write(cipher.final());
|
|
@@ -36,7 +30,7 @@ function encrypt(data) {
|
|
|
36
30
|
* @param data String to be encrypted.
|
|
37
31
|
* @returns Encrypted data as Uint8Array.
|
|
38
32
|
*/
|
|
39
|
-
function encryptString(data) {
|
|
33
|
+
export function encryptString(data) {
|
|
40
34
|
return encrypt(new TextEncoder().encode(data));
|
|
41
35
|
}
|
|
42
36
|
/**
|
|
@@ -44,16 +38,16 @@ function encryptString(data) {
|
|
|
44
38
|
* @param encrypted Encrypted data (IV + content + auth tag).
|
|
45
39
|
* @returns Decrypted data.
|
|
46
40
|
*/
|
|
47
|
-
function decrypt(encrypted) {
|
|
41
|
+
export function decrypt(encrypted) {
|
|
48
42
|
if (encrypted.byteLength < 33) {
|
|
49
43
|
throw new Error("Invalid encrypted data length");
|
|
50
44
|
}
|
|
51
45
|
const iv = encrypted.slice(0, 16);
|
|
52
46
|
const authTag = encrypted.slice(encrypted.byteLength - 16);
|
|
53
47
|
const content = encrypted.slice(16, encrypted.byteLength - 16);
|
|
54
|
-
const decipher =
|
|
48
|
+
const decipher = createDecipheriv("aes-128-gcm", key, iv);
|
|
55
49
|
decipher.setAuthTag(authTag);
|
|
56
|
-
const decrypted = new
|
|
50
|
+
const decrypted = new DynamicBuffer(0);
|
|
57
51
|
decrypted.write(decipher.update(content));
|
|
58
52
|
decrypted.write(decipher.final());
|
|
59
53
|
return decrypted.bytes();
|
|
@@ -63,6 +57,6 @@ function decrypt(encrypted) {
|
|
|
63
57
|
* @param data Encrypted data.
|
|
64
58
|
* @returns Odszyfrowany ciąg znaków.
|
|
65
59
|
*/
|
|
66
|
-
function decryptToString(data) {
|
|
60
|
+
export function decryptToString(data) {
|
|
67
61
|
return new TextDecoder().decode(decrypt(data));
|
|
68
62
|
}
|
|
@@ -1,44 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.recoveryCodeVerifySchema = exports.passkeysSetupSchema = exports.totpVerifySchema = exports.totpSetupSchema = exports.verifyEmailSchema = exports.resetPasswordSchema = exports.forgotPasswordSchema = exports.registerSchema = exports.loginSchema = void 0;
|
|
4
|
-
const zod_1 = require("zod");
|
|
1
|
+
import { z } from "zod";
|
|
5
2
|
// Auth validation schemas - CLEAN (No DB dependencies for client-side)
|
|
6
|
-
|
|
7
|
-
email:
|
|
8
|
-
password:
|
|
9
|
-
remember:
|
|
3
|
+
export const loginSchema = z.object({
|
|
4
|
+
email: z.string().email("Invalid email address"),
|
|
5
|
+
password: z.string().min(8),
|
|
6
|
+
remember: z.boolean().optional(),
|
|
10
7
|
});
|
|
11
|
-
|
|
12
|
-
username:
|
|
13
|
-
email:
|
|
14
|
-
password:
|
|
15
|
-
terms:
|
|
8
|
+
export const registerSchema = z.object({
|
|
9
|
+
username: z.string().min(2, "Name must be at least 2 characters"),
|
|
10
|
+
email: z.string().email("Invalid email address"),
|
|
11
|
+
password: z.string().min(8, "Password must be at least 8 characters"),
|
|
12
|
+
terms: z.boolean().refine((val) => val === true, "You must accept the terms"),
|
|
16
13
|
});
|
|
17
|
-
|
|
18
|
-
email:
|
|
14
|
+
export const forgotPasswordSchema = z.object({
|
|
15
|
+
email: z.string().email("Invalid email address"),
|
|
19
16
|
});
|
|
20
|
-
|
|
17
|
+
export const resetPasswordSchema = z
|
|
21
18
|
.object({
|
|
22
|
-
password:
|
|
23
|
-
confirm:
|
|
19
|
+
password: z.string().min(8, "Password must be at least 8 characters"),
|
|
20
|
+
confirm: z.string(),
|
|
24
21
|
})
|
|
25
22
|
.refine((data) => data.password === data.confirm, {
|
|
26
23
|
message: "Passwords do not match",
|
|
27
24
|
path: ["confirm"],
|
|
28
25
|
});
|
|
29
|
-
|
|
30
|
-
code:
|
|
26
|
+
export const verifyEmailSchema = z.object({
|
|
27
|
+
code: z.string().min(6).max(6),
|
|
31
28
|
});
|
|
32
29
|
// mfa validation schemas
|
|
33
|
-
|
|
34
|
-
code:
|
|
30
|
+
export const totpSetupSchema = z.object({
|
|
31
|
+
code: z.string().regex(/^\d{6}$/, "Code must be 6 digits"),
|
|
35
32
|
});
|
|
36
|
-
|
|
37
|
-
code:
|
|
33
|
+
export const totpVerifySchema = z.object({
|
|
34
|
+
code: z.string().regex(/^\d{6}$/, "Code must be 6 digits"),
|
|
38
35
|
});
|
|
39
|
-
|
|
40
|
-
name:
|
|
36
|
+
export const passkeysSetupSchema = z.object({
|
|
37
|
+
name: z.string().min(1, "Passkey name is required"),
|
|
41
38
|
});
|
|
42
|
-
|
|
43
|
-
code:
|
|
39
|
+
export const recoveryCodeVerifySchema = z.object({
|
|
40
|
+
code: z.string().min(16, "Recovery code is required").max(16),
|
|
44
41
|
});
|