feat: ruoli admin/editor in auth e create-user

This commit is contained in:
2026-07-05 15:31:53 +02:00
parent c7d9d4ba5d
commit 77041f9d5a
4 changed files with 62 additions and 14 deletions
+1 -1
View File
@@ -2,6 +2,6 @@
declare namespace App {
interface Locals {
user?: { id: number; username: string };
user?: { id: number; username: string; role: string };
}
}
+17 -7
View File
@@ -5,6 +5,8 @@ import { randomBytes } from 'node:crypto';
export const SESSION_COOKIE = 'session';
const SESSION_DAYS = 7;
export type Role = 'admin' | 'editor';
export function hashPassword(plain: string): string {
return bcrypt.hashSync(plain, 12);
}
@@ -13,9 +15,9 @@ export function verifyPassword(plain: string, hash: string): boolean {
return bcrypt.compareSync(plain, hash);
}
export function createUser(db: Database.Database, username: string, password: string): number {
const res = db.prepare('INSERT INTO users (username, password_hash) VALUES (?, ?)')
.run(username, hashPassword(password));
export function createUser(db: Database.Database, username: string, password: string, role: Role = 'admin'): number {
const res = db.prepare('INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)')
.run(username, hashPassword(password), role);
return Number(res.lastInsertRowid);
}
@@ -30,19 +32,27 @@ export function login(db: Database.Database, username: string, password: string)
return token;
}
export function getSessionUser(db: Database.Database, token: string): { id: number; username: string } | null {
export function getSessionUser(db: Database.Database, token: string): { id: number; username: string; role: string } | null {
const row = db.prepare(
`SELECT s.token, s.expires_at, u.id, u.username
`SELECT s.token, s.expires_at, u.id, u.username, u.role
FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.token = ?`
).get(token) as { token: string; expires_at: string; id: number; username: string } | undefined;
).get(token) as { token: string; expires_at: string; id: number; username: string; role: string } | undefined;
if (!row) return null;
if (row.expires_at <= new Date().toISOString().slice(0, 19).replace('T', ' ')) {
db.prepare('DELETE FROM sessions WHERE token = ?').run(token);
return null;
}
return { id: row.id, username: row.username };
return { id: row.id, username: row.username, role: row.role };
}
export function logout(db: Database.Database, token: string): void {
db.prepare('DELETE FROM sessions WHERE token = ?').run(token);
}
// Percorsi admin consentiti anche al ruolo editor.
const EDITOR_ALLOWED = [/^\/admin\/content(\/|$)?/, /^\/api\/admin\/content(\/|$)/, /^\/admin\/logout$/];
export function canAccessAdminPath(role: string, pathname: string): boolean {
if (role === 'admin') return true;
return EDITOR_ALLOWED.some((re) => re.test(pathname));
}