chore: add rollback-safe password rollout window

This commit is contained in:
hectorzhao
2026-08-28 11:47:08 +08:00
parent 2744690f9f
commit d85ff85999
3 changed files with 32 additions and 0 deletions
+9
View File
@@ -5,9 +5,11 @@ const DEFAULT_N = 32768;
const DEFAULT_R = 8;
const DEFAULT_P = 1;
const MAX_MEMORY = 64 * 1024 * 1024;
const MAX_LEGACY_WRITE_WINDOW_MS = 2 * 60 * 60 * 1000;
const LEGACY_SHA256 = /^[a-f0-9]{64}$/i;
export async function hashPassword(password: string) {
if (legacyTransitionWriteEnabled()) return legacyHashPassword(password);
const salt = randomBytes(16);
const derived = await deriveScrypt(password, salt, KEY_LENGTH, {
N: DEFAULT_N,
@@ -18,6 +20,13 @@ export async function hashPassword(password: string) {
return `$scrypt$v=${VERSION}$N=${DEFAULT_N},r=${DEFAULT_R},p=${DEFAULT_P}$${salt.toString('base64url')}$${derived.toString('base64url')}`;
}
function legacyTransitionWriteEnabled() {
if (process.env.PASSWORD_HASH_LEGACY_TRANSITION !== 'true') return false;
const until = Date.parse(process.env.PASSWORD_HASH_LEGACY_WRITE_UNTIL ?? '');
const remaining = until - Date.now();
return Number.isFinite(until) && remaining > 0 && remaining <= MAX_LEGACY_WRITE_WINDOW_MS;
}
export async function verifyPassword(password: string, encoded: string) {
if (isLegacySha256(encoded)) {
const candidate = Buffer.from(legacyHashPassword(password), 'hex');