mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 21:12:49 +08:00
loadConfig now sanitizes guestMode the same way the write path does: bots is coerced to "all" | string[] (numbers/objects/missing fall back to the default "all"), and permissions are rebuilt from defaults with each known flag strict-coerced to a boolean so a hand-edited/legacy/corrupt config.json can no longer crash the gate or leak garbage index keys. The authorize guest gate now uses === true instead of a truthy check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
1.3 KiB
TypeScript
30 lines
1.3 KiB
TypeScript
import type { Request, Response, NextFunction, RequestHandler } from "express";
|
|
import type { GuestFlag } from "../../data/permissions.js";
|
|
|
|
/**
|
|
* Unified authorization gate.
|
|
* - admin → always allowed (unchanged from requirePermission)
|
|
* - member → allowed iff it holds `capability` (unchanged from requirePermission)
|
|
* - guest → allowed iff `guestFlag` is set AND that flag is enabled in the
|
|
* guest's resolved permissions; a route with no `guestFlag` is
|
|
* denied to guests by default.
|
|
* Generic over the route-param shape `P` for the same reason requirePermission is.
|
|
*/
|
|
export function authorize<P = Record<string, string>>(opts: {
|
|
capability?: string;
|
|
guestFlag?: GuestFlag;
|
|
}): RequestHandler<P> {
|
|
return (req: Request<P>, res: Response, next: NextFunction) => {
|
|
const user = req.user;
|
|
if (!user) { res.status(401).json({ error: "unauthenticated" }); return; }
|
|
if (user.role === "admin") { next(); return; }
|
|
if (user.role === "guest") {
|
|
if (opts.guestFlag && user.guest?.[opts.guestFlag] === true) { next(); return; }
|
|
res.status(403).json({ error: "forbidden" });
|
|
return;
|
|
}
|
|
if (opts.capability && user.capabilities?.has(opts.capability)) { next(); return; }
|
|
res.status(403).json({ error: "forbidden" });
|
|
};
|
|
}
|