source: Klonkt/scripts/reset-admin.mjs@ 9e27d64

main
Last change on this file since 9e27d64 was 9e27d64, checked in by roboburr <roboburr@…>, 3 months ago

auth: password admin + per-instance Google for listeners (no broker)

Robin's choice: every self-hoster has their own password admin account,
and can optionally let listeners log in to comment using their OWN Google
client. No central broker (that would tie every customer site to Robin's
Google Cloud -> systemic risk on abuse).

  • Admin = username/password (bcrypt). First-time setup via /auth/register (only when there are 0 users); closed afterwards. No public registration.
  • Forgot password: /auth/reset-request -> email (if SMTP configured) with reset link; CLI break-glass npm run reset-admin always works (no email needed).
  • Change password (logged in) restored in /account.
  • Google = per-instance own credentials, OPTIONAL, listeners only -> always role member, never admin (god/admin email is rejected; google_sub mismatch too).
  • config/google.js back to direct Google OAuth; config/mailer.js new (nodemailer).
  • jose removed from deps; nodemailer added.

Security review (workflow) incorporated:

  • Reset token no longer in production logs (dev only).
  • Reset link from PUBLIC_BASE_URL instead of X-Forwarded-Host (host poisoning).
  • Reset tokens stored SHA-256-hashed in the DB.
  • Same-origin check on all state-modifying POSTs (CSRF layer on top of sameSite-lax).
  • Login always runs one bcrypt comparison (no timing enumeration).

Co-Authored-By: Claude <noreply@…>

  • Property mode set to 100644
File size: 1.8 KB
Line 
1#!/usr/bin/env node
2// Break-glass: reset (of zet) het wachtwoord van een beheerder. Werkt altijd,
3// zonder e-mail — de self-hoster heeft immers shell-/servertoegang.
4//
5// Gebruik:
6// npm run reset-admin # reset de (eerste) god-user, print nieuw wachtwoord
7// npm run reset-admin -- <user|email> # reset specifieke user, print nieuw wachtwoord
8// npm run reset-admin -- <user|email> <pw> # zet een gekozen wachtwoord
9//
10// Draai dit vanuit de projectroot zodat DATABASE_PATH/.env correct geladen wordt.
11
12import 'dotenv/config';
13import crypto from 'crypto';
14import bcrypt from 'bcryptjs';
15import db from '../src/config/database.js';
16
17const arg = process.argv[2];
18const pwArg = process.argv[3];
19
20let user;
21if (arg) {
22 user = db.prepare('SELECT * FROM users WHERE username = ? OR LOWER(email) = LOWER(?)').get(arg, arg);
23} else {
24 // Geen arg: pak de beheerder (god of admin), anders de allereerste user.
25 user =
26 db.prepare("SELECT * FROM users WHERE role IN ('god','admin') ORDER BY created_at LIMIT 1").get() ||
27 db.prepare('SELECT * FROM users ORDER BY created_at LIMIT 1').get();
28}
29
30if (!user) {
31 console.error(arg ? `Geen user gevonden voor "${arg}".` : 'Geen god-user gevonden.');
32 process.exit(1);
33}
34
35if (pwArg && pwArg.length < 8) {
36 console.error('Wachtwoord moet minstens 8 tekens zijn.');
37 process.exit(1);
38}
39
40const newPw = pwArg || crypto.randomBytes(9).toString('base64url');
41db.prepare(`
42 UPDATE users SET password_hash = ?, reset_token = NULL, reset_token_expires = NULL,
43 updated_at = CURRENT_TIMESTAMP WHERE id = ?
44`).run(bcrypt.hashSync(newPw, 10), user.id);
45
46console.log(`Wachtwoord gereset voor ${user.username} <${user.email}> (rol: ${user.role}).`);
47if (!pwArg) console.log(`Nieuw wachtwoord: ${newPw}`);
48console.log('Log nu in via /auth/login en wijzig het eventueel in je account.');
49process.exit(0);
Note: See TracBrowser for help on using the repository browser.