Role-based access: admin vs superadmin
- Credentials provider now resolves two distinct accounts from env:
SUPERADMIN_USERNAME / SUPERADMIN_PASSWORD → role "superadmin"
ADMIN_USERNAME / ADMIN_PASSWORD → role "admin"
The role is carried through the JWT and Session callbacks so the UI
and API can gate on it. Types extended via types/next-auth.d.ts.
- lib/auth.ts exports requireRole(minRole) and sessionRole(session).
- /api/players POST rejects "op" and "deop" with 403 unless the caller
is superadmin. All other player actions (whitelist add/remove, ban,
pardon) remain available to both roles.
- lib/use-role.ts (client hook) exposes role / isSuperadmin / authed
for UI gating without duplicating session typing.
- PlayerManager: Add-OP button and per-row Deop action are hidden or
disabled for non-superadmin; when a regular admin is viewing the
Ops tab, a banner explains the read-only state.
- PlayerDrawer: Make Op / Deop button disabled with tooltip for
non-superadmin; whitelist, ban, pardon unchanged.
- Navbar: subtle role pill next to the user name ("Super" for
superadmin amber-tinted, "Admin" for admin).
- Migration note: the existing ADMIN_* credentials now log in as the
restricted admin role. Set SUPERADMIN_USERNAME + SUPERADMIN_PASSWORD
in .env.local to retain operator-management ability. A placeholder
superadmin account was generated in .env.local; the password is in
the commit terminal output only, not the repo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3a69dc9243
commit
1ac5513d2c
7 changed files with 151 additions and 18 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { readFileSync } from "fs";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { auth, sessionRole } from "@/lib/auth";
|
||||
import { sendCommand } from "@/lib/rcon";
|
||||
import { memo, invalidate } from "@/lib/cache";
|
||||
|
||||
|
|
@ -76,6 +76,13 @@ export async function POST(req: NextRequest) {
|
|||
);
|
||||
}
|
||||
|
||||
if ((action === "op" || action === "deop") && sessionRole(session) !== "superadmin") {
|
||||
return NextResponse.json(
|
||||
{ error: "Only super admins can manage operators" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
let command = `${action} ${player}`;
|
||||
if (action === "ban" && reason) {
|
||||
command += ` ${reason}`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue