refactor(密码): 删掉 PASSWORD_HASH_UPGRADE,无条件写 argon2
Some checks failed
Deploy / deploy (push) Has been cancelled

上一个 commit 把五个写入点收进 hashPassword,顺手把开关默认值翻成了 true 并
留下 false 分支当退路。这个退路是假的,删掉。

**开关只能拦住将来,修不了已经发生的。** 等真到了要把旧站拉回来的那天,活跃
账号早就都被登录/重置密码升成 argon2 了,这时候设 `=false` 一个也救不回来。
正经退路是切换手册「万一已经改坏了」那节的脚本 —— 拿 `raw_password` 重算
Django 的 `make_password`,能修已经变成 argon2 的账号。留着一个永远轮不到它
上场的开关,只是给后来人多一件要读懂的东西。

删掉的:`config.passwordHashUpgrade`、`hashDjangoPbkdf2` 和它那套 Django 参数
(1200000 迭代 / 22 位 salt / RANDOM_STRING_CHARS)、两个 compose 里的
`PASSWORD_HASH_UPGRADE` env。auth.ts 的登录升级变成无条件。

保留的:

- `hashPassword()` —— 虽然现在只是一行 argon2,但「只有一个地方写密码」正是上
  一个 commit 的重点。五处各写各的才是当初那个 bug 的根。
- `verifyPassword` 的 **pbkdf2 分支** —— 生产库 1710 个账号全是 Django 写的
  pbkdf2(迭代次数 120000~1200000),只会在各自下次登录时才迁移。删了就是
  全站登不上。代码注释里写死了这句话。
- 切换手册里的 `raw_password` 恢复脚本,以及回滚流程里新加的「密码要额外处理」
  那一步。

## 验证

改完重跑了一遍关键路径(临时造一个 Django 生成的 120000 迭代老哈希):

- 存量账号登录 200 → 哈希变成 argon2 → 再登 200 → 错密码 401
- 后台重置密码 → argon2 → 新密码能登录
- 注册 → argon2 → 能登录

tsc(apps/api) 0 error、check:routes 168 条无遮蔽、vue-tsc 0 error、build 通过、
两个 compose `config -q` 通过。测试用户已删干净。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 23:50:55 -06:00
parent 694e147a21
commit dd6a6a04eb
7 changed files with 48 additions and 115 deletions

View File

@@ -66,24 +66,6 @@ export const config = {
sessionCookie: "oj2_session",
sessionTtlSeconds: Number(process.env.SESSION_TTL_SECONDS ?? 7 * 24 * 60 * 60),
secureCookies: process.env.COOKIE_SECURE === "true",
// 写密码用 argon2id 还是 Django 格式的 pbkdf2。**默认 argon2** —— 旧站已经下线
// 2026-08-26没有回滚路径要照顾了。
//
// true默认五个写入点全写 argon2id登录成功时把存量 pbkdf2 顺手升级掉。
// false 全写 Django 格式的 `pbkdf2_sha256$1200000$…`,登录时也不动
// 存量哈希 —— 旧后端验得了。**万一要把旧站拉回来,设这个。**
//
// ⚠️ **无论开关怎么设,`verifyPassword` 的 pbkdf2 分支永远不能删。** 生产库
// 1710 个账号全是 Django 写的 pbkdf2迭代次数横跨 1200001200000因为
// 跨了好几个 Django 版本),它们只会在各自下次登录时才升级成 argon2
// 删掉那个分支就是全站登不上。
//
// 历史:这个开关原来默认关闭,用来堵「升级成 argon2 的账号回不去旧站」这道
// 单向门(并行试跑第一天就撞过,见 phase5 切换手册)。但它当时**只管住了
// 登录时的自动升级那一处**,注册 / 管理员改密码 / 批量导入 / 重置密码四条
// 路无条件写 argon2 —— 老师给学生点一次「重置密码」,那个账号照样回不去。
// 现在五处统一走 auth/password.ts 的 hashPassword开关两个方向都是真的。
passwordHashUpgrade: process.env.PASSWORD_HASH_UPGRADE !== "false",
judgeServerUrl: process.env.JUDGE_SERVER_URL ?? "http://localhost:8081",
judgeServerToken: judgeServerToken(),
judgeConcurrency: Number(process.env.JUDGE_CONCURRENCY ?? 2),