Files
CC-Manager/server/src/bootstrap.ts
T
Harlekin a7228e63d1 HTTP-Endpunkte und Anwendungsaufbau
Eingaben werden mit zod validiert, jede aendernde Aktion schreibt ins
Audit-Log. Beim ersten Start entsteht ein Administrator samt Startwerten fuer
die Produkterkennung; solange ein Erstpasswort gilt, bleiben schreibende Wege
bis auf den Passwortwechsel gesperrt.

Nicht-API-Pfade fallen auf die SPA zurueck, damit Deep-Links funktionieren.
2026-09-18 11:37:31 +02:00

64 lines
2.2 KiB
TypeScript

import { randomBytes } from 'node:crypto';
import { ProductTarget } from '@prisma/client';
import { prisma } from './db.js';
import { env } from './env.js';
import { hashPassword } from './auth/password.js';
// Startpunkte fuer die Produkterkennung beim Import. Jederzeit im Admin-Bereich
// anpassbar, sobald die echten Produktnamen bekannt sind.
const DEFAULT_MAPPINGS = [
{ matchPattern: 'cc-paket', target: ProductTarget.CC_PACKAGE, priority: 10 },
{ matchPattern: 'cc paket', target: ProductTarget.CC_PACKAGE, priority: 11 },
{ matchPattern: 'custom character', target: ProductTarget.CC_PACKAGE, priority: 12 },
{ matchPattern: 'redesign', target: ProductTarget.REDESIGN_PACKAGE, priority: 20 },
];
export interface BootstrapResult {
createdAdmin: { username: string; password: string } | null;
createdMappings: number;
}
/**
* Legt beim allerersten Start einen Administrator an. Ohne gesetztes
* Bootstrap-Passwort wird eines erzeugt und einmalig ins Log geschrieben.
*/
export async function bootstrap(log: {
info: (msg: string) => void;
warn: (msg: string) => void;
}): Promise<BootstrapResult> {
const result: BootstrapResult = { createdAdmin: null, createdMappings: 0 };
const userCount = await prisma.user.count();
if (userCount === 0) {
const password = env.BOOTSTRAP_ADMIN_PASSWORD ?? randomBytes(12).toString('base64url');
await prisma.user.create({
data: {
username: env.BOOTSTRAP_ADMIN_USER,
passwordHash: await hashPassword(password),
role: 'ADMIN',
mustChangePassword: true,
},
});
result.createdAdmin = { username: env.BOOTSTRAP_ADMIN_USER, password };
log.warn('─'.repeat(60));
log.warn(`Administrator angelegt: ${env.BOOTSTRAP_ADMIN_USER}`);
if (!env.BOOTSTRAP_ADMIN_PASSWORD) {
log.warn(`Einmal-Passwort: ${password}`);
}
log.warn('Das Passwort muss bei der ersten Anmeldung geaendert werden.');
log.warn('─'.repeat(60));
}
const mappingCount = await prisma.productMapping.count();
if (mappingCount === 0) {
const created = await prisma.productMapping.createMany({ data: DEFAULT_MAPPINGS });
result.createdMappings = created.count;
log.info(`${created.count} Produkt-Mappings als Startwerte angelegt`);
}
return result;
}