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

@@ -3,7 +3,6 @@ import { eq, sql } from "drizzle-orm"
import { Hono } from "hono"
import { optionalAuth, type AppEnv } from "../auth/middleware"
import { config } from "../config"
import { createSession, destroySession } from "../auth/session"
import { hashPassword, verifyPassword } from "../auth/password"
import { db, schema } from "../db"
@@ -55,10 +54,9 @@ authRoutes.post("/auth/login", async (c) => {
const now = new Date().toISOString()
const update: { lastLogin: string; password?: string } = { lastLogin: now }
// 存量 pbkdf2 顺手升级成 argon2。**只在总开关打开时做** —— 升过的账号回不去
// 旧站,见 config.passwordHashUpgrade。开关关着时 hashPassword 写的也是 pbkdf2
// 所以这里不升级、别处不写 argon2回滚路径才是完整的。
if (password.needsUpgrade && config.passwordHashUpgrade) {
// 存量 pbkdf2 顺手升级成 argon2。生产库 1710 个账号都是 Django 写的 pbkdf2
// 靠这里随登录逐个迁移;没登录过的照旧由 verifyPassword pbkdf2 分支兜着。
if (password.needsUpgrade) {
update.password = await hashPassword(parsed.data.password)
}
await db.update(schema.user).set(update).where(eq(schema.user.id, user.id))