fix(perm): access-check before bot-existence (no 403/404 leak); label permissions audit action

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.8 committed 2026-05-30 14:12:04 +08:00
1 parent 1ca1ca9d0c
commit 907a6651f5
2 files changed
+8 -2

No files matched your search

+7 -2
View File
@@ -16,6 +16,13 @@ export function createPlayerRouter(
): Router { ): Router {
const router = Router(); const router = Router();
// Access check runs BEFORE the existence/resolver check so a member who is
// not allowed a bot always gets a uniform 403 — whether or not the bot
// exists — instead of a 404 that would leak which bot IDs are real.
// requireBotAccess only needs req.params.botId and req.user (set by the
// global requireAuth mounted earlier), so it works before the resolver.
router.use("/:botId", requireBotAccess("botId"));
router.use("/:botId", (req, res, next) => { router.use("/:botId", (req, res, next) => {
const bot = botManager.getBot(req.params.botId); const bot = botManager.getBot(req.params.botId);
if (!bot) { if (!bot) {
@@ -26,8 +33,6 @@ export function createPlayerRouter(
next(); next();
}); });
router.use("/:botId", requireBotAccess("botId"));
/** Map API platform string to the corresponding command flag. */ /** Map API platform string to the corresponding command flag. */
const platformFlag = (platform: unknown): string => { const platformFlag = (platform: unknown): string => {
if (platform === "bilibili") return "-b"; if (platform === "bilibili") return "-b";
+1
View File
@@ -1326,6 +1326,7 @@ function describeAction(e: AuditEntry): string {
case 'user.password_reset': return `重置 ${target} 的密码`; case 'user.password_reset': return `重置 ${target} 的密码`;
case 'user.password_changed': return `修改自己的密码`; case 'user.password_changed': return `修改自己的密码`;
case 'user.role_changed': return `变更 ${target} 的角色`; case 'user.role_changed': return `变更 ${target} 的角色`;
case 'user.permissions_changed': return `权限变更 → ${target}`;
default: return `${e.action} → ${target}`; default: return `${e.action} → ${target}`;
} }
} }