Address the security-auditor findings the user selected (items 2, 3, 4): Default admin credentials (P2): remove the fixed `Ten31` default. First boot now generates a strong random admin password (secrets.token_urlsafe), records it 0600 at /data/.admin-password, and surfaces it once via a new "Show Initial Admin Password" StartOS action (CLI `show-admin-password`). The stored password is cleared when the admin is reset (CLI reset-password) or self-changes it (change-password endpoint). Login hardening (P2): add a per-IP in-memory sliding-window rate limiter (10 failures / 5 min -> 429 + Retry-After) in ratelimit.py; run a dummy argon2 verify when the user is unknown so timing can't enumerate usernames; keep a single generic 401 for unknown-user and wrong-password. Hardening (P3): server process now runs unprivileged -- Dockerfile adds uid 10001 appuser; start.sh (still root) chowns the mounted /data then drops via `setpriv` before exec'ing uvicorn. Spreadsheet imports are size-capped via storage.read_capped (413 past MAX_UPLOAD_SIZE) in the schedule, capital preview, and batch paths. batch_import no longer returns raw exception text (generic per-file messages). Verified in the packed amd64 container: PID1 uvicorn runs as uid 10001, /data owned 10001 with 0600 secrets; generated admin password retrievable via CLI and logs in (200); 11th bad login -> 429; admin reset clears the stored password. Tests: test_auth_hardening.py (4). Full suite 21 passed; frontend tsc + StartOS bundle clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
29 lines
1.3 KiB
TypeScript
29 lines
1.3 KiB
TypeScript
export { v_0_2_26 as current } from './v_0_2_26'
|
|
import { v_0_1_0 } from './v_0_1_0'
|
|
import { v_0_2_0 } from './v_0_2_0'
|
|
import { v_0_2_1 } from './v_0_2_1'
|
|
import { v_0_2_3 } from './v_0_2_3'
|
|
import { v_0_2_4 } from './v_0_2_4'
|
|
import { v_0_2_5 } from './v_0_2_5'
|
|
import { v_0_2_6 } from './v_0_2_6'
|
|
import { v_0_2_7 } from './v_0_2_7'
|
|
import { v_0_2_8 } from './v_0_2_8'
|
|
import { v_0_2_9 } from './v_0_2_9'
|
|
import { v_0_2_10 } from './v_0_2_10'
|
|
import { v_0_2_11 } from './v_0_2_11'
|
|
import { v_0_2_12 } from './v_0_2_12'
|
|
import { v_0_2_13 } from './v_0_2_13'
|
|
import { v_0_2_14 } from './v_0_2_14'
|
|
import { v_0_2_15 } from './v_0_2_15'
|
|
import { v_0_2_16 } from './v_0_2_16'
|
|
import { v_0_2_17 } from './v_0_2_17'
|
|
import { v_0_2_18 } from './v_0_2_18'
|
|
import { v_0_2_19 } from './v_0_2_19'
|
|
import { v_0_2_20 } from './v_0_2_20'
|
|
import { v_0_2_21 } from './v_0_2_21'
|
|
import { v_0_2_22 } from './v_0_2_22'
|
|
import { v_0_2_23 } from './v_0_2_23'
|
|
import { v_0_2_24 } from './v_0_2_24'
|
|
import { v_0_2_25 } from './v_0_2_25'
|
|
export const other = [v_0_1_0, v_0_2_0, v_0_2_1, v_0_2_3, v_0_2_4, v_0_2_5, v_0_2_6, v_0_2_7, v_0_2_8, v_0_2_9, v_0_2_10, v_0_2_11, v_0_2_12, v_0_2_13, v_0_2_14, v_0_2_15, v_0_2_16, v_0_2_17, v_0_2_18, v_0_2_19, v_0_2_20, v_0_2_21, v_0_2_22, v_0_2_23, v_0_2_24, v_0_2_25]
|