40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import 'dotenv/config';
|
||
import { hash } from '@node-rs/argon2';
|
||
import postgres from 'postgres';
|
||
import { createInterface } from 'node:readline/promises';
|
||
const username = process.argv[2]?.trim().toLowerCase();
|
||
if (!username || !/^[a-z0-9._-]{3,80}$/.test(username))
|
||
throw new Error('Aufruf: npm run admin:create -- BENUTZERNAME (3–80 Zeichen)');
|
||
async function passwordInput(): Promise<string> {
|
||
if (!process.stdin.isTTY) {
|
||
let input = '';
|
||
for await (const chunk of process.stdin) input += chunk;
|
||
return input.trimEnd();
|
||
}
|
||
process.stdout.write('Neues Passwort (mind. 12 Zeichen, Eingabe verborgen): ');
|
||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||
// Disable terminal echo while readline receives characters.
|
||
const output = rl as unknown as { _writeToOutput: (s: string) => void };
|
||
output._writeToOutput = () => {};
|
||
const value = await rl.question('');
|
||
rl.close();
|
||
process.stdout.write('\n');
|
||
return value;
|
||
}
|
||
const password = await passwordInput();
|
||
if (password.length < 12 || password.length > 200)
|
||
throw new Error('Passwort muss 12–200 Zeichen enthalten.');
|
||
const sql = postgres(process.env.DATABASE_URL!, { max: 1 });
|
||
try {
|
||
const hashed = await hash(password, {
|
||
algorithm: 2,
|
||
memoryCost: 65536,
|
||
timeCost: 3,
|
||
parallelism: 1,
|
||
});
|
||
await sql`INSERT INTO admins (username, password) VALUES (${username}, ${hashed})`;
|
||
console.log(`Administrator ${username} erstellt.`);
|
||
} finally {
|
||
await sql.end();
|
||
}
|