From b6745387fb861d38d122faef719d76bb5cbdddbe Mon Sep 17 00:00:00 2001 From: Flotapponnier Date: Sun, 20 Sep 2026 15:27:20 +0200 Subject: [PATCH] crm: password minimum 12 characters (the signing secret keeps 16) Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw --- crm/.env.example | 2 +- crm/README.md | 3 ++- crm/app/login/page.tsx | 2 +- crm/lib/auth.ts | 7 +++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crm/.env.example b/crm/.env.example index 10b293d3c..7c8a20194 100644 --- a/crm/.env.example +++ b/crm/.env.example @@ -1,4 +1,4 @@ -# Shared password (16+ chars) and a random secret (16+ chars) that signs session cookies. +# Shared password (12+ chars) and a random secret (16+ chars) that signs session cookies. # Rotating either logs everyone out. CRM_PASSWORD= CRM_SESSION_SECRET= diff --git a/crm/README.md b/crm/README.md index c9bfa0f51..37fc1f36a 100644 --- a/crm/README.md +++ b/crm/README.md @@ -78,7 +78,8 @@ The cookie is `nonce.expiry.signature`, signed with `CRM_SESSION_SECRET` (random not the password, so a leaked cookie gives nothing to brute force) and valid only while its nonce is listed in `/data/sessions.json`: logout revokes it, rotating either variable logs everyone out. Login attempts are limited to 10 -per client per 15 minutes. Both variables must be 16 characters or more. +per client per 15 minutes. The password needs 12 characters or more, the +secret 16. Module state (snapshot cache, refresh mutex, PostHog budget, login counters) lives on `globalThis` and the snapshot file is re-read whenever its mtime diff --git a/crm/app/login/page.tsx b/crm/app/login/page.tsx index 863c50047..b788b032b 100644 --- a/crm/app/login/page.tsx +++ b/crm/app/login/page.tsx @@ -12,7 +12,7 @@ export default async function LoginPage({ searchParams }: { searchParams: Promis

{!authConfigured() ? (

- CRM_PASSWORD and CRM_SESSION_SECRET must both be set (16 characters minimum). Nobody can log in until they are. + CRM_PASSWORD (12 characters minimum) and CRM_SESSION_SECRET (16 minimum) must both be set. Nobody can log in until they are.

) : (
diff --git a/crm/lib/auth.ts b/crm/lib/auth.ts index 434693c87..00724c42f 100644 --- a/crm/lib/auth.ts +++ b/crm/lib/auth.ts @@ -12,13 +12,16 @@ import { listSession, sessionListed, unlistSession } from "@/lib/sessions"; export const COOKIE = "ocb_crm"; export const SESSION_DAYS = 30; -const MIN_LEN = 16; +// 12 for the password (a memorable one, behind the per-client and global +// login limits), 16 for the signing secret (random, never typed). +const MIN_PASSWORD_LEN = 12; +const MIN_SECRET_LEN = 16; const password = () => process.env.CRM_PASSWORD ?? ""; const secret = () => process.env.CRM_SESSION_SECRET ?? ""; export function authConfigured(): boolean { - return password().length >= MIN_LEN && secret().length >= MIN_LEN; + return password().length >= MIN_PASSWORD_LEN && secret().length >= MIN_SECRET_LEN; } const enc = new TextEncoder();