Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

admin.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

admin.tsBlame45 lines · 1 contributor
a4f3e24Claude1/**
2 * Admin middleware — blocks non-admin users.
3 * Must be used AFTER softAuth or requireAuth.
36cc17aClaude4 *
5 * "Admin" means EITHER:
6 * - the user is in the `site_admins` table (explicit grant), OR
7 * - the `site_admins` table is empty and this user is the oldest
8 * row in `users` (bootstrap rule from src/lib/admin.ts).
9 *
10 * The legacy `users.is_admin` column is ALSO honoured for backward
11 * compatibility with accounts that pre-date the site_admins table.
12 *
13 * Until 2026-05-14 this middleware only checked `users.is_admin`,
14 * which broke /import + every other requireAdmin-gated route for any
15 * user who only had bootstrap-rule admin status (which is the case
16 * after running scripts/reset-admin-password.ts).
a4f3e24Claude17 */
18
19import { createMiddleware } from "hono/factory";
20import type { AuthEnv } from "./auth";
36cc17aClaude21import { isSiteAdmin } from "../lib/admin";
a4f3e24Claude22
23export const requireAdmin = createMiddleware<AuthEnv>(async (c, next) => {
24 const user = c.get("user");
25
26 if (!user) {
27 return c.redirect(`/login?redirect=${encodeURIComponent(c.req.path)}`);
28 }
29
36cc17aClaude30 const admin = user.isAdmin === true || (await isSiteAdmin(user.id));
31 if (!admin) {
a4f3e24Claude32 return c.html(
33 `<html><body style="background:#0d1117;color:#e6edf3;font-family:sans-serif;display:flex;justify-content:center;align-items:center;height:100vh">
34 <div style="text-align:center">
35 <h1>403</h1>
36 <p>Admin access required.</p>
37 <a href="/" style="color:#58a6ff">Go home</a>
38 </div>
39 </body></html>`,
40 403
41 );
42 }
43
44 return next();
45});