feat(core): add secure recipe APIs, precise scaling and versioned imports
This commit is contained in:
commit
5d71d32e20
31 files changed
+6293
No files matched your search
@@ -0,0 +1,39 @@
|
||||
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();
|
||||
}
|
||||
Reference in new issue
Block a user