51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
/**
|
|
* Seed admin passphrase — run once to set up authentication.
|
|
*
|
|
* Usage:
|
|
* ADMIN_PASSPHRASE="your-secret" bun run src/seed-passphrase.ts
|
|
* bun run seed-passphrase (prompts interactively)
|
|
*/
|
|
|
|
import { initSchema, getDb } from './db';
|
|
import { hashPassphrase } from './auth';
|
|
import { logger } from './logger';
|
|
|
|
async function main(): Promise<void> {
|
|
initSchema();
|
|
|
|
let passphrase = process.env['ADMIN_PASSPHRASE'];
|
|
|
|
if (!passphrase) {
|
|
process.stdout.write('Enter admin passphrase: ');
|
|
passphrase = await new Promise<string>((resolve) => {
|
|
const chunks: Buffer[] = [];
|
|
process.stdin.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
process.stdin.once('end', () => resolve(Buffer.concat(chunks).toString().trim()));
|
|
process.stdin.resume();
|
|
});
|
|
}
|
|
|
|
if (!passphrase || passphrase.length < 8) {
|
|
logger.error('Passphrase must be at least 8 characters');
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
const hash = await hashPassphrase(passphrase);
|
|
const db = getDb();
|
|
|
|
const existing = db.prepare('SELECT id FROM admin_auth WHERE id = 1').get();
|
|
if (existing) {
|
|
db.prepare('UPDATE admin_auth SET passphrase_hash = ?, created_at = datetime(\'now\') WHERE id = 1').run(hash);
|
|
logger.info('Admin passphrase updated');
|
|
} else {
|
|
db.prepare('INSERT INTO admin_auth (id, passphrase_hash) VALUES (1, ?)').run(hash);
|
|
logger.info('Admin passphrase created');
|
|
}
|
|
} catch (err) {
|
|
logger.error('Failed to seed passphrase', { error: String(err) });
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|