From 2c0439db6a88f5ab2f19b6a29b039efaab0db923 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 17 Sep 2026 15:01:23 +0200 Subject: [PATCH] refactor(auth): remove obsolete CONVERT_PASSWORDS env var Legacy md5/argon2id hashes are now always upgraded to bcrypt on login, so the CONVERT_PASSWORDS flag is no longer used. Drop it from env schema, .env.example, the docker installer, and test mocks. --- .env.example | 4 +--- scripts/docker-install.sh | 2 +- src/actions/auth-precheck.test.ts | 2 +- src/env.ts | 6 ------ src/lib/auth/password.test.ts | 4 ++-- src/lib/auth/password.ts | 5 ++++- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index ac03dfa6..a110cc71 100644 --- a/.env.example +++ b/.env.example @@ -36,9 +36,7 @@ BADGE_URL=/swf/c_images/album1584 # --- SECURITY & HASHING --- AUTH_SECRET=your-super-secret-auth-key-change-this-min-32-chars APP_KEY=base64:your-app-key-here= -# Deprecated: legacy md5/argon2id hashes are ALWAYS upgraded to bcrypt on -# login now. Kept only for config compatibility with existing deploys. -# CONVERT_PASSWORDS=true +# Bcrypt cost factor for new password hashes. BCRYPT_COST=12 # --- PATHS --- diff --git a/scripts/docker-install.sh b/scripts/docker-install.sh index fc8e233c..47a919ae 100644 --- a/scripts/docker-install.sh +++ b/scripts/docker-install.sh @@ -78,7 +78,7 @@ else [[ "$auth_secret" =~ ^[0-9a-f]{64}$ ]] || fail "Could not generate the authentication secret." env_tmp="$(mktemp "$DIR/.env.install.XXXXXX")" { - printf '%s\n' 'NODE_ENV=production' 'PORT=3002' 'NEXT_TELEMETRY_DISABLED=1' 'AUTH_TRUST_HOST=true' 'CONVERT_PASSWORDS=true' + printf '%s\n' 'NODE_ENV=production' 'PORT=3002' 'NEXT_TELEMETRY_DISABLED=1' 'AUTH_TRUST_HOST=true' printf "HOTEL_NAME='%s'\nAPP_URL='%s'\nAUTH_URL='%s'\n" "$hotel" "$public_url" "$public_url" printf "DATABASE_URL='%s'\nREDIS_URL='%s'\nAUTH_SECRET='%s'\n" "$database_url" "$redis_url" "$auth_secret" printf "IMAGER_URL='%s'\nIMAGING_UPSTREAM_URL='%s'\nBADGE_URL='/swf/c_images/album1584'\n" "$imager_url" "$imager_url" diff --git a/src/actions/auth-precheck.test.ts b/src/actions/auth-precheck.test.ts index a8f20010..1f340493 100644 --- a/src/actions/auth-precheck.test.ts +++ b/src/actions/auth-precheck.test.ts @@ -17,7 +17,7 @@ const core = vi.hoisted(() => ({ }), })); -vi.mock("@/env", () => ({ env: { CONVERT_PASSWORDS: false } })); +vi.mock("@/env", () => ({ env: {} })); vi.mock("@/lib/auth/login-core", () => core); vi.mock("@/lib/rate-limit", () => ({ clientIp: vi.fn(), rateLimit: vi.fn() })); vi.mock("@/lib/services/captcha", () => ({ diff --git a/src/env.ts b/src/env.ts index d2d84a3d..dec979c5 100644 --- a/src/env.ts +++ b/src/env.ts @@ -69,12 +69,6 @@ const schema = z // Laravel APP_KEY (base64:...) — needed to read existing 2FA secrets. APP_KEY: z.string().optional(), - // Deprecated: legacy md5/argon2id hashes are ALWAYS upgraded to bcrypt - // on login now (no flag required). Kept for config compatibility. - CONVERT_PASSWORDS: z - .string() - .optional() - .transform((v) => v === "true" || v === "1"), // bcrypt cost factor used for new password hashes. BCRYPT_COST: z.coerce.number().int().min(4).max(31).default(12), // Filesystem dir the badge uploader writes .gif into (the emulator's diff --git a/src/lib/auth/password.test.ts b/src/lib/auth/password.test.ts index 1732dfd2..5f2b0ea1 100644 --- a/src/lib/auth/password.test.ts +++ b/src/lib/auth/password.test.ts @@ -138,14 +138,14 @@ describe("isDoubleMd5Of", () => { describe("isSaltedMd5Of", () => { it("verifies md5(salt+password) with hash:salt layout", async () => { const salt = "pepper123"; - const stored = `${(await md5Hex(salt + "oldpass"))}:${salt}`; + const stored = `${await md5Hex(salt + "oldpass")}:${salt}`; expect(await isSaltedMd5Of("oldpass", stored)).toBe(true); expect(await isSaltedMd5Of("wrong", stored)).toBe(false); }); it("verifies md5(password+salt) with hash:salt layout", async () => { const salt = "pepper123"; - const stored = `${(await md5Hex("oldpass" + salt))}:${salt}`; + const stored = `${await md5Hex("oldpass" + salt)}:${salt}`; expect(await isSaltedMd5Of("oldpass", stored)).toBe(true); }); diff --git a/src/lib/auth/password.ts b/src/lib/auth/password.ts index 72b3ab5f..0cbba748 100644 --- a/src/lib/auth/password.ts +++ b/src/lib/auth/password.ts @@ -57,7 +57,10 @@ export async function isDoubleMd5Of( stored: string, ): Promise { if (!/^[a-f0-9]{32}$/i.test(stored)) return false; - return (await md5Hex(await md5Hex(password))).toLowerCase() === stored.toLowerCase(); + return ( + (await md5Hex(await md5Hex(password))).toLowerCase() === + stored.toLowerCase() + ); } /**