Files

93 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* setup-admin.ts
*
* Ensures the initial admin user (username: "admin") exists.
* Called automatically on every container start.
*
* Behaviour:
* - ADMIN_PASSWORD set → create or update admin with that password
* - ADMIN_PASSWORD not set, admin exists → nothing to do, skip silently
* - ADMIN_PASSWORD not set, admin missing → generate a random password,
* create the user, print to logs
*
* Manual usage:
* ADMIN_PASSWORD=secret npx ts-node --compiler-options '{"module":"CommonJS"}' scripts/setup-admin.ts
* docker exec -e ADMIN_PASSWORD=secret annas_app node scripts/setup-admin.cjs
*/
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
import { randomBytes } from "crypto";
const prisma = new PrismaClient();
function generatePassword(length = 16): string {
// URL-safe characters only so the password is easy to copy from logs
return randomBytes(Math.ceil((length * 3) / 4))
.toString("base64url")
.slice(0, length);
}
async function main() {
const explicitPassword = process.env.ADMIN_PASSWORD ?? process.argv[2];
const existing = await prisma.user.findUnique({ where: { username: "admin" } });
// Admin exists and no explicit password override → nothing to do
if (existing && !explicitPassword) {
console.log("[setup-admin] Admin user already exists skipping.");
return;
}
let password: string;
let generated = false;
if (explicitPassword) {
if (explicitPassword.length < 8) {
console.error("[setup-admin] ERROR: ADMIN_PASSWORD must be at least 8 characters.");
process.exit(1);
}
password = explicitPassword;
} else {
// No admin user yet and no password given → auto-generate
password = generatePassword(16);
generated = true;
}
const passwordHash = await bcrypt.hash(password, 12);
await prisma.user.upsert({
where: { username: "admin" },
update: { passwordHash, role: "ADMIN" },
create: {
username: "admin",
email: "admin@localhost",
name: "Administrator",
passwordHash,
role: "ADMIN",
},
});
if (generated) {
console.log("");
console.log("╔══════════════════════════════════════════════════╗");
console.log("║ ADMIN-ZUGANGSDATEN (einmalig) ║");
console.log("╠══════════════════════════════════════════════════╣");
console.log(`║ Benutzername : admin ║`);
console.log(`║ Passwort : ${password.padEnd(32)}`);
console.log("╠══════════════════════════════════════════════════╣");
console.log("║ Bitte sofort nach dem ersten Login ändern! ║");
console.log("╚══════════════════════════════════════════════════╝");
console.log("");
} else {
console.log(`[setup-admin] ✅ Admin user ${existing ? "updated" : "created"} (username: admin).`);
}
}
main()
.catch((e) => {
console.error("[setup-admin] FATAL:", e);
process.exit(1);
})
.finally(() => prisma.$disconnect());