Changeset 247988e in Klonkt for src/routes/account.js


Ignore:
Timestamp:
06/19/2026 09:55:26 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
f33b24a
Parents:
535f955
Message:

feat(auth): admin can link Google and use it to log in

  • Account → "Sign in with Google": link/unlink your Google account (/auth/google/link, requireAuth → stores google_sub on own account).
  • Google callback: link mode alongside login mode. An admin may log in with Google ONLY if their google_sub is linked and matches (otherwise "Google = never admin" rule holds). Unlinking requires a password (no lockout).
  • Admin notice on the login page explains the link route.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/account.js

    r535f955 r247988e  
    2424import { renderPage } from '../middleware/render.js';
    2525import { requireAuth } from '../middleware/auth.js';
     26import { googleConfigured } from '../config/google.js';
    2627
    2728const __dirname = path.dirname(fileURLToPath(import.meta.url));
     
    5859router.get('/', requireAuth, (req, res) => {
    5960  const account = db.prepare(`
    60     SELECT id, username, email, role, bio, avatar_url, created_at, password_hash
     61    SELECT id, username, email, role, bio, avatar_url, created_at, password_hash, google_sub
    6162    FROM users WHERE id = ?
    6263  `).get(req.session.user.id);
    6364  const hasPassword = !!(account && account.password_hash && account.password_hash !== '!google-oauth');
    64   if (account) delete account.password_hash; // niet naar de view lekken
     65  const googleLinked = !!(account && account.google_sub);
     66  if (account) { delete account.password_hash; delete account.google_sub; } // niet naar de view lekken
    6567
    6668  renderPage(req, res, 'pages/account', {
     
    6971    account,
    7072    hasPassword,
     73    googleLinked,
     74    googleAvailable: googleConfigured(),
    7175    editableSite: ownedSite(req.session.user),
    7276    success: req.query.success || null,
     
    144148});
    145149
     150// Google-account ontkoppelen. Alleen toegestaan als er nog een wachtwoord is,
     151// anders zou je jezelf buitensluiten (geen login-methode meer over).
     152router.post('/google/unlink', requireAuth, (req, res) => {
     153  const row = db.prepare('SELECT password_hash, google_sub FROM users WHERE id = ?').get(req.session.user.id);
     154  if (!row || !row.google_sub) {
     155    return res.redirect('/account?error=' + encodeURIComponent('Er is geen Google-account gekoppeld'));
     156  }
     157  if (!row.password_hash || row.password_hash === '!google-oauth') {
     158    return res.redirect('/account?error=' + encodeURIComponent('Stel eerst een wachtwoord in — anders kun je niet meer inloggen.'));
     159  }
     160  db.prepare('UPDATE users SET google_sub = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(req.session.user.id);
     161  res.redirect('/account?success=' + encodeURIComponent('Google-account ontkoppeld'));
     162});
     163
    146164// ==================== UPLOAD AVATAR ====================
    147165router.post('/avatar', requireAuth, (req, res) => {
Note: See TracChangeset for help on using the changeset viewer.