admin) manage local login users
Some checks failed
PR Checks / lint-test-and-docker-build (pull_request) Failing after 1m2s

This commit is contained in:
2026-02-22 19:36:11 +00:00
parent fc8e80186d
commit 5c7bae61b5
5 changed files with 478 additions and 4 deletions

View File

@@ -1,4 +1,6 @@
import { randomUUID } from 'crypto';
import { db } from './db/index.js';
import { setLocalCredentialPassword } from './local-credentials.js';
export interface AppUser {
id: string;
@@ -11,6 +13,7 @@ export interface AppUser {
}
const DEFAULT_AUTH_SOURCE = 'OIDC - Synology';
const LOCAL_AUTH_SOURCE = 'Local';
const normalizeOptional = (value?: string | null): string | undefined => {
const trimmed = value?.trim();
@@ -112,6 +115,56 @@ export function deleteUser(id: string): void {
db.run('DELETE FROM users WHERE id = ?', [id]);
}
export async function createLocalUser(input: {
username: string;
fullName: string;
email?: string | null;
password: string;
}): Promise<AppUser> {
const username = input.username?.trim() ?? '';
const fullName = input.fullName?.trim() ?? '';
if (!username || !fullName) {
throw new Error('Username and full name are required');
}
const email = normalizeEmail(input.email);
const existingUsername = db.get<{ id: string }>(
'SELECT id FROM users WHERE lower(username) = lower(?)',
[username]
);
if (existingUsername) {
throw new Error('Username already exists');
}
if (email) {
const existingEmail = db.get<{ id: string }>(
'SELECT id FROM users WHERE lower(email) = lower(?)',
[email]
);
if (existingEmail) {
throw new Error('Email already exists');
}
}
const id = randomUUID();
db.run(
`INSERT INTO users (id, username, full_name, email, auth_source)
VALUES (?, ?, ?, ?, ?)`,
[id, username, fullName, email ?? null, LOCAL_AUTH_SOURCE]
);
await setLocalCredentialPassword(id, input.password);
return db.get<AppUser>('SELECT * FROM users WHERE id = ?', [id])!;
}
export async function setLocalPasswordForUser(userId: string, password: string): Promise<void> {
const id = userId?.trim() ?? '';
if (!id) {
throw new Error('User id required');
}
const existing = db.get<{ id: string }>('SELECT id FROM users WHERE id = ?', [id]);
if (!existing) {
throw new Error('User not found');
}
await setLocalCredentialPassword(id, password);
}
function syncSelfProfile(userId: string, fullName: string, email?: string | null): void {
const profile = db.get<{ id: string; first_name: string; last_name: string; email: string | null }>(
`SELECT id, first_name, last_name, email FROM people WHERE user_id = ? AND is_self = 1 LIMIT 1`,