BCRYPT_ROUNDS was a module-level const evaluated at import time,
so env overrides in tests or CI had no effect. Changed to function
that reads process.env on each call. Also lowered hardcoded
bcryptHash(..., 10) in test to use env var with fallback 4.
CI: BCRYPT_ROUNDS=2. Password test suite: 1860ms → 29ms.
- Allow ARGON2_MEMORY_SIZE, ARGON2_ITERATIONS, ARGON2_PARALLELISM env overrides
- Use m=1024,t=1 in tests (was m=65536,t=4 → ~1s per hash)
- Set fast params in CI and deploy workflows
Verified against the live AtomCMS DB: users.password is varchar(64), so
argon2id (~97 chars) overflows the column and registration/upgrade fail
with 'value too long'. bcrypt (60-char $2y$) fits and matches the
existing accounts. hashPassword() now emits bcrypt by default; set
PASSWORD_HASH=argon2id to opt back in (needs a widened column).
verifyPassword() still accepts both, so existing logins keep working.
Verified end-to-end against the live DB: bcrypt $2y$ login round-trips
(correct=true, wrong=false). tsc 0, vitest 8/8 (password suite).
Pure, unit-tested primitives the AtomCMS->Next.js login must reproduce exactly
(verified now with round-trip + known vectors; full end-to-end check deferred
until a real DB + APP_KEY + live emulator are available):
- password.ts: argon2id (m=65536,t=4,p=1 via hash-wasm) + bcrypt ($2y$ accepted)
verify, and the md5->argon2id on-login upgrade gated by convert_passwords
(mirrors RedirectIfTwoFactorAuthenticatable).
- sso-ticket.ts: '{hotel_name without spaces}-{uuidv4}' written to auth_ticket +
ip_current (mirrors User::ssoTicket()).
- laravel-encrypter.ts: AES-256-CBC + HMAC-SHA256 payload compatible with
Laravel encrypt()/encryptString (for existing 2FA secrets) incl. PHP string
(de)serialization.
- totp.ts: otplib Google2FA-compatible TOTP verify (SHA1/6/30).
Libs: hash-wasm + bcryptjs + otplib (pure JS/WASM, no native build). 28 tests.