diff options
| -rw-r--r-- | lib/register.ts | 2 | ||||
| -rw-r--r-- | routes/users.ts | 19 |
2 files changed, 18 insertions, 3 deletions
diff --git a/lib/register.ts b/lib/register.ts index bd1049c8..16aa5b02 100644 --- a/lib/register.ts +++ b/lib/register.ts @@ -32,7 +32,7 @@ export default async (user, ip) => { if (password) { user.password = await Bun.password.hash(password, { algorithm: "bcrypt", - cost: 4, + cost: 12, }); } diff --git a/routes/users.ts b/routes/users.ts index f10b728b..63699777 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -350,7 +350,7 @@ export default { if (password && password === confirm) { user.password = await Bun.password.hash(password, { algorithm: "bcrypt", - cost: 4, + cost: 12, }); } @@ -427,6 +427,21 @@ export default { if ((await db.ttl(ipFailKey)) < 0) await db.expire(ipFailKey, 600); return res.code(401).send("2fa required"); } + + // Transparent bcrypt upgrade: legacy accounts were hashed at cost 4 + // (~1,300 guesses/s). Now that we hold the verified plaintext, re-hash + // at the current cost so the stored hash strengthens on next login. + const cost = Number.parseInt( + user.password.match(/^\$2[aby]\$(\d{2})\$/)?.[1] ?? "0", + 10, + ); + if (cost < 12) { + user.password = await Bun.password.hash(password, { + algorithm: "bcrypt", + cost: 12, + }); + await s(`user:${user.id}`, user); + } } if (username !== "coinos") @@ -787,7 +802,7 @@ export default { user.password = await Bun.password.hash(password, { algorithm: "bcrypt", - cost: 4, + cost: 12, }); await s(`user:${id}`, user); |
