diff --git a/Docs/Architekture.md b/Docs/Architekture.md index 6c549ff..8148e3a 100644 --- a/Docs/Architekture.md +++ b/Docs/Architekture.md @@ -920,7 +920,51 @@ BanGUI maintains its **own SQLite database** (separate from the fail2ban databas --- -## 6. Authentication & Session Management +## 6. Setup & Configuration Persistence + +### 6.1 Initial Setup Wizard & One-Time Configuration + +The setup wizard (`POST /api/setup`) runs once during first-time startup to configure: +- Master password (bcrypt-hashed) +- Runtime database path (where BanGUI stores operational state) +- fail2ban Unix socket path +- IANA timezone +- Session duration (in minutes) +- Map color thresholds for geolocation visualization + +**Atomicity & Crash-Safety:** + +Setup is implemented with explicit transaction boundaries across two SQLite databases (bootstrap config DB and runtime app DB) to ensure atomicity: + +1. **Phase 1 (Bootstrap DB transaction)**: Set `setup_state = "in_progress"` and persist `database_path`. On commit, this is the first checkpoint — if process crashes here, the next setup attempt will detect and clean up. + +2. **Phase 2 (Filesystem + Runtime DB)**: Initialize runtime database schema outside a transaction (idempotent via `CREATE TABLE IF NOT EXISTS`). + +3. **Phase 3 (Runtime DB transaction)**: Batch-write all runtime settings (password hash, paths, config) atomically in a single `BEGIN IMMEDIATE ... COMMIT` transaction. Either all settings are persisted or none are. + +4. **Phase 4 (Bootstrap DB transaction)**: Set `setup_state = "complete"` and `setup_completed = "1"`. This is the final commit point — only when this succeeds is setup considered complete. + +**Password Hash Idempotency:** + +The bcrypt password hash is computed early (before any DB writes) to ensure that if setup is retried after a crash, the same hash is used throughout all retry attempts. This prevents divergent hashes due to bcrypt's random salt generation. + +**State Machine:** + +| State | Meaning | Recovery | +|-------|---------|----------| +| `null` | Setup not started | Normal flow: begin setup | +| `"in_progress"` | Bootstrap DB marked, runtime DB being initialized | Retry from beginning (runtime DB may be partial) | +| `"complete"` | All settings persisted, setup finished | Skip setup (already done) | + +If a crash is detected in `"in_progress"` state on the next startup, cleanup logic can detect this and either retry or remove the partial runtime database before retrying. + +**Backward Compatibility:** + +The `setup_completed = "1"` key is still written for backward compatibility with cache detection. Modern code checks `setup_state = "complete"` for clearer semantics. + +--- + +## 8. Authentication & Session Management - **Single-user model** — one master password, no usernames. - Password is hashed with a strong algorithm (e.g., bcrypt or argon2) and stored in the application database during setup. @@ -934,7 +978,7 @@ BanGUI maintains its **own SQLite database** (separate from the fail2ban databas - **Runtime state** (`RuntimeState` in `app.utils.runtime_state`) — stores mutable application state: `server_status` (fail2ban online/offline), `last_activation` (jail activation tracking), `pending_recovery` (crash detection), `runtime_settings` (effective configuration), and service-specific state holders like `jail_service_state` (`JailServiceState` for jail capability detection cache). RuntimeState fields are managed through dedicated functions (e.g., `record_activation()`, `clear_pending_recovery()`) and via dependency injection to services. Service-specific state (like `JailServiceState`) is nested within `RuntimeState` to keep all mutable state in one controlled location. **⚠️ RuntimeState is process-local and only safe when BanGUI runs as a single asyncio worker.** Mutations must not span `await` points (cooperative scheduling within a single event loop is safe). In multi-worker deployments, each process has its own copy — logouts from worker A don't affect worker B's cache, health status updates are per-worker, and activation tracking is unreliable. BanGUI enforces single-worker mode (TASK-002) to prevent this issue. For future multi-worker support, replace RuntimeState with a shared coordination backend (Redis, shared memory, database). See `app/utils/runtime_state.py` module docstring for details. - **Setup-completion flag** — once `is_setup_complete()` returns `True`, the result is stored in `app.state._setup_complete_cached`. The `SetupRedirectMiddleware` skips the DB query on all subsequent requests, removing 1 SQL query per request for the common post-setup case. The completion flag is only written after the runtime database is successfully initialized and all initial setup settings are persisted, preventing a failed setup from permanently bypassing the setup wizard. -### 6.1 CSRF Protection +### 8.1 CSRF Protection State-mutating endpoints (POST, PUT, DELETE, PATCH) that use cookie-based authentication are protected against Cross-Site Request Forgery (CSRF) attacks via a **custom header check middleware**. @@ -949,7 +993,7 @@ State-mutating endpoints (POST, PUT, DELETE, PATCH) that use cookie-based authen This mechanism complements the existing `SameSite=Lax` cookie policy, which blocks traditional `