auth: sessions, login/logout/me/change-password, CSRF, guards, audit
argon2id passwords with a min length and a common-password list (SecLists, MIT). Login failures are limited per IP and per email; must_change_password blocks everything outside /api/auth/*. The first admin is created from env on startup. pnpm dev derives DATABASE_URL from .env. Task: M1-T3
This commit is contained in:
1 parent
15b8a20751
commit
13733ac262
20 files changed
+1937
-46
No files matched your search
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PASSWORD_MIN = 10;
|
||||
|
||||
export const LoginSchema = z.object({
|
||||
email: z.string().trim().min(3).max(254),
|
||||
password: z.string().min(1).max(200),
|
||||
totp: z
|
||||
.string()
|
||||
.regex(/^\d{6}$/)
|
||||
.optional(), // M11
|
||||
});
|
||||
|
||||
export const ChangePasswordSchema = z.object({
|
||||
currentPassword: z.string().min(1).max(200),
|
||||
newPassword: z.string().min(PASSWORD_MIN).max(200),
|
||||
});
|
||||
|
||||
export type Role = 'admin' | 'user';
|
||||
|
||||
/** What /api/auth/login and /api/auth/me return. */
|
||||
export type AuthUser = {
|
||||
id: string;
|
||||
email: string;
|
||||
displayName: string;
|
||||
role: Role;
|
||||
mustChangePassword: boolean;
|
||||
extension: { id: string; number: string; name: string } | null;
|
||||
};
|
||||
@@ -3,3 +3,4 @@ export const APP_NAME = 'SelfPhoneNG';
|
||||
export * from './phone.ts';
|
||||
export * from './destination.ts';
|
||||
export * from './settings.ts';
|
||||
export * from './auth.ts';
|
||||
Reference in new issue
Block a user