refactor: 另外两处守卫也收到注册行上
走查题单进度时撞到 `/problem-sets/:id/user-progress` 对学生 403 —— 那是**正确**的 (它是给教师看全班进度的),但守卫又写在 handler 体内。评审的 M3 只列了 3 处, 按同一模式扫全仓,还有 2 处: content.ts POST /messages isSuperAdmin problemset.ts GET /problem-sets/:id/user-progress isTeacherOrAbove 改用 requireSuperAdmin / requireTeacher,理由同 M3:守卫要能从注册行上看出来, 不然下一个人加同类端点容易漏掉那个 if。 实测档位没变:学生两条都 403,教师看全班进度 200。 路由遮蔽检查仍然干净。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,11 +15,11 @@ import {
|
|||||||
import { and, asc, count, desc, eq, inArray } from "drizzle-orm"
|
import { and, asc, count, desc, eq, inArray } from "drizzle-orm"
|
||||||
import { Hono } from "hono"
|
import { Hono } from "hono"
|
||||||
|
|
||||||
import { requireAuth, type AppEnv } from "../auth/middleware"
|
import { requireAuth, requireSuperAdmin, type AppEnv } from "../auth/middleware"
|
||||||
import { db, schema } from "../db"
|
import { db, schema } from "../db"
|
||||||
import { failure, success } from "../http"
|
import { failure, success } from "../http"
|
||||||
import { JudgeStatus } from "../judge/status"
|
import { JudgeStatus } from "../judge/status"
|
||||||
import { isSuperAdmin, objectValue, queryInteger, sampleUser } from "./helpers"
|
import { objectValue, queryInteger, sampleUser } from "./helpers"
|
||||||
|
|
||||||
export const contentRoutes = new Hono<AppEnv>()
|
export const contentRoutes = new Hono<AppEnv>()
|
||||||
|
|
||||||
@@ -108,9 +108,8 @@ contentRoutes.get("/messages", requireAuth, async (c) => {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
contentRoutes.post("/messages", requireAuth, async (c) => {
|
contentRoutes.post("/messages", requireSuperAdmin, async (c) => {
|
||||||
const user = c.get("user")!
|
const user = c.get("user")!
|
||||||
if (!isSuperAdmin(user)) return failure(c, 403, "permission-denied", "Permission denied")
|
|
||||||
const parsed = createMessageRequestSchema.safeParse(await c.req.json().catch(() => null))
|
const parsed = createMessageRequestSchema.safeParse(await c.req.json().catch(() => null))
|
||||||
if (!parsed.success) return failure(c, 400, "invalid-request", "Invalid message payload")
|
if (!parsed.success) return failure(c, 400, "invalid-request", "Invalid message payload")
|
||||||
if (parsed.data.recipientId === user.id) return failure(c, 400, "invalid-recipient", "Can not send a message to yourself")
|
if (parsed.data.recipientId === user.id) return failure(c, 400, "invalid-recipient", "Can not send a message to yourself")
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ import {
|
|||||||
} from "drizzle-orm"
|
} from "drizzle-orm"
|
||||||
import { Hono } from "hono"
|
import { Hono } from "hono"
|
||||||
|
|
||||||
import { optionalAuth, requireAuth, type AppEnv } from "../auth/middleware"
|
import { optionalAuth, requireAuth, requireTeacher, type AppEnv } from "../auth/middleware"
|
||||||
import { db, schema } from "../db"
|
import { db, schema } from "../db"
|
||||||
import { publishAchievementNotification } from "../events"
|
import { publishAchievementNotification } from "../events"
|
||||||
import { failure, success } from "../http"
|
import { failure, success } from "../http"
|
||||||
import { JudgeStatus } from "../judge/status"
|
import { JudgeStatus } from "../judge/status"
|
||||||
import { updateAchievementsForProblemSet } from "../services/achievements"
|
import { updateAchievementsForProblemSet } from "../services/achievements"
|
||||||
import { isTeacherOrAbove, objectValue, queryInteger, sampleUser } from "./helpers"
|
import { objectValue, queryInteger, sampleUser } from "./helpers"
|
||||||
|
|
||||||
export const problemsetRoutes = new Hono<AppEnv>()
|
export const problemsetRoutes = new Hono<AppEnv>()
|
||||||
|
|
||||||
@@ -362,9 +362,7 @@ problemsetRoutes.get("/problem-sets/:id/badges", async (c) => {
|
|||||||
return success(c, badges.map((badge) => badgeData(badge)))
|
return success(c, badges.map((badge) => badgeData(badge)))
|
||||||
})
|
})
|
||||||
|
|
||||||
problemsetRoutes.get("/problem-sets/:id/user-progress", requireAuth, async (c) => {
|
problemsetRoutes.get("/problem-sets/:id/user-progress", requireTeacher, async (c) => {
|
||||||
const user = c.get("user")!
|
|
||||||
if (!isTeacherOrAbove(user)) return failure(c, 403, "permission-denied", "Permission denied")
|
|
||||||
const id = queryInteger(c.req.param("id"), 0, { min: 1 })
|
const id = queryInteger(c.req.param("id"), 0, { min: 1 })
|
||||||
const [problemSet] = await db.select({ id: schema.problemset.id }).from(schema.problemset).where(and(
|
const [problemSet] = await db.select({ id: schema.problemset.id }).from(schema.problemset).where(and(
|
||||||
eq(schema.problemset.id, id), eq(schema.problemset.visible, true), ne(schema.problemset.status, "draft"),
|
eq(schema.problemset.id, id), eq(schema.problemset.visible, true), ne(schema.problemset.status, "draft"),
|
||||||
|
|||||||
Reference in New Issue
Block a user