Add admin panel restricted to a single designated account
Adds a full admin view (users + projects, with view/delete) gated server-side by ADMIN_EMAIL in server/auth.js (defaults to the site owner's account, overridable via env var for other deployments). The gate is enforced on every /api/admin/* route, not just hidden in the UI — verified a non-admin session gets 403 even when it hits the endpoints directly. Deleting a user leaves their projects in place (not cascade-deleted) so admin cleanup can't accidentally destroy someone's study data. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { authenticator } from 'otplib';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { getUserById } from './db.js';
|
||||
|
||||
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
// The single admin account for this deployment. Override via env var if you
|
||||
// redeploy this app for someone else — don't hardcode your own email into a
|
||||
// fork without changing this.
|
||||
const ADMIN_EMAIL = (process.env.ADMIN_EMAIL || 'nmemmert@duck.com').toLowerCase();
|
||||
|
||||
export function isValidEmail(email) {
|
||||
return typeof email === 'string' && email.length <= 254 && EMAIL_RE.test(email);
|
||||
@@ -28,6 +33,19 @@ export function requireAuth(req, res, next) {
|
||||
next();
|
||||
}
|
||||
|
||||
export function isAdminEmail(email) {
|
||||
return typeof email === 'string' && email.toLowerCase() === ADMIN_EMAIL;
|
||||
}
|
||||
|
||||
/** Blocks the request unless the signed-in account is the designated admin. */
|
||||
export function requireAdmin(req, res, next) {
|
||||
const user = req.session?.userId ? getUserById(req.session.userId) : null;
|
||||
if (!user || !isAdminEmail(user.email)) {
|
||||
return res.status(403).json({ error: 'Admin access only.' });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Two-factor auth (TOTP, RFC 6238 — compatible with any authenticator app)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user