File size: 1,234 Bytes
3bbe317
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { getDb, pruneExpiredSessions } from './db';

export interface AuthUser {
  id: string;
  email: string;
  isAdmin: boolean;
}

export function authenticateRequest(req: Request): AuthUser | null {
  const h = req.headers.get('authorization');
  const token = h && h.startsWith('Bearer ') ? h.slice(7).trim() : null;
  if (!token) return null;

  const db = getDb();
  pruneExpiredSessions();

  // Deactivated accounts (is_active = 0) must not authenticate even if
  // they still have a valid session token. The WHERE clause uses
  // `COALESCE(..., 1)` so that on DBs where the v3 column has not yet
  // been added the session still resolves — belt + braces for upgrades.
  const row = db
    .prepare(
      `SELECT u.id, u.email, u.is_admin
       FROM sessions s JOIN users u ON u.id = s.user_id
       WHERE s.token = ?
         AND s.expires_at > datetime('now')
         AND COALESCE(u.is_active, 1) = 1`,
    )
    .get(token) as any;

  return row ? { id: row.id, email: row.email, isAdmin: !!row.is_admin } : null;
}

/** Require admin — returns null if not admin. */
export function requireAdmin(req: Request): AuthUser | null {
  const user = authenticateRequest(req);
  return user?.isAdmin ? user : null;
}