fix(阶段3): 匿名不可读用户档案,真名改为默认不下发

F1:GET /profiles/:username 只挂了 optionalAuth、handler 内无登录判断,
匿名可读 email、adminType、className、lastLogin。用户名又能经 /rankings/users
公开枚举,等于可以无 cookie 批量收集全校学生的邮箱与最后登录时间。
handler 开头补上未登录即返回空,对齐旧后端 account/views/oj.py 的
UserProfileAPI.get 首行 `if not user.is_authenticated: return self.success()`。

F2:旧后端把「是否下发真名」做成 UsernameSerializer(need_real_name=False)
的默认关闭开关,全仓 11 处调用只有比赛榜单一处显式打开;新后端没搬这一层,
真名随用户对象无条件下发,13 个下发点里 8 个匿名可达。

这里补回同一层:helpers.ts 新增 sampleUser(),realName 默认不下发,
需要的地方显式传 { includeRealName: true }。12 个下发点改为走这个函数,
只有比赛榜单一处打开(对齐 contest/serializers.py:84 的 is_contest_admin)。
没有逐处删字段 —— 那样下次新增端点还会重犯。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 01:59:05 -06:00
co-authored by Claude Opus 5
parent 9c04b00e3f
commit b4b61af6b0
6 changed files with 52 additions and 27 deletions
+3 -7
View File
@@ -28,7 +28,7 @@ import { optionalAuth, type AppEnv } from "../auth/middleware"
import { db, schema } from "../db"
import { failure, success } from "../http"
import { JudgeStatus } from "../judge/status"
import { objectValue as toObject, queryInteger } from "./helpers"
import { objectValue as toObject, queryInteger, sampleUser } from "./helpers"
export const problemRoutes = new Hono<AppEnv>()
@@ -83,7 +83,7 @@ function listItem(
submissionNumber: row.problem.submissionNumber,
acceptedNumber: row.problem.acceptedNumber,
difficulty: row.problem.difficulty,
createdBy: { id: row.user.id, username: row.user.username, realName: row.realName },
createdBy: sampleUser(row.user, row.realName),
tags: tags.get(row.problem.id) ?? [],
contestId: row.problem.contestId,
allowFlowchart: row.problem.allowFlowchart,
@@ -327,11 +327,7 @@ problemRoutes.get("/problems/:displayId", optionalAuth, async (c) => {
shareSubmission: row.problem.shareSubmission,
contestId: row.problem.contestId,
tags: tagRows.map((tag) => tag.name),
createdBy: {
id: row.creatorId,
username: row.creatorUsername,
realName: null,
},
createdBy: sampleUser({ id: row.creatorId, username: row.creatorUsername }, null),
myStatus,
myFailedCount,
allowFlowchart: row.problem.allowFlowchart,