From eb281ad058005fbf75af4626a3346c6cfff3f245 Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Sun, 5 Apr 2026 12:11:32 -0400 Subject: [PATCH] docs(operator-guide): PIN hashing is unified (issue #2) Describes the canonical [security] pin_hash key, the PBKDF2 format emitted by 'vigilar config set-pin', and the deprecation warning for the legacy [system] arm_pin_hash. Drops the three-way mismatch known-limitation. --- docs/operator-guide.md | 44 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/operator-guide.md b/docs/operator-guide.md index df48918..317f505 100644 --- a/docs/operator-guide.md +++ b/docs/operator-guide.md @@ -113,8 +113,9 @@ omitted sections behave sensibly. `.vge` files. - `hls_dir` (default `/var/vigilar/hls`): HLS segment output. - `log_level` (default `"INFO"`): one of DEBUG, INFO, WARNING, ERROR. -- `arm_pin_hash` (default `""`): commented out in the sample; set via - `vigilar config set-pin`. +- `arm_pin_hash` (default `""`): **deprecated.** Still parsed but + ignored at runtime. Use `[security] pin_hash` instead; run + `vigilar config set-pin` to generate the canonical hash. ### `[mqtt]` @@ -291,11 +292,10 @@ enabled = false`, `[visitors] enabled = false`, `[highlights] enabled - `[location] latitude`, `longitude` (default `0.0`): used for sunrise and sunset lookups. -- `[security] pin_hash` and `recovery_passphrase_hash`: populated by - `vigilar config set-pin` (the same hash is also stored under - `[system] arm_pin_hash` on the `system` model; both fields exist - because the web UI uses `[security]` while the CLI helper prints a - `[system]` line — pick one location and stick with it). +- `[security] pin_hash` (canonical arm/disarm PIN store) and + `recovery_passphrase_hash`: both populated by + `vigilar config set-pin`. The `[system] arm_pin_hash` field is + deprecated; see the `[system]` section above. ## CLI reference @@ -344,9 +344,9 @@ sudo -u vigilar /opt/vigilar/venv/bin/vigilar config show \ ``` Dumps the parsed config as JSON with `web.password_hash`, -`system.arm_pin_hash`, and `alerts.webhook.secret` redacted. Useful -for confirming which defaults Pydantic applied for keys you did not -set. +`security.pin_hash`, `security.recovery_passphrase_hash`, and +`alerts.webhook.secret` redacted. Useful for confirming which +defaults Pydantic applied for keys you did not set. ### `vigilar config set-password` @@ -365,10 +365,12 @@ prints a `password_hash = "salt_hex:key_hex"` line to paste into sudo -u vigilar /opt/vigilar/venv/bin/vigilar config set-pin ``` -Prompts for an arm/disarm PIN, generates a random 32-byte HMAC key, -computes `HMAC-SHA256(key, pin)`, and prints an `arm_pin_hash = -"secret_hex:mac_hex"` line to paste into `[system]`. Again, no file -write. +Prompts for an arm/disarm PIN, derives a salted PBKDF2-SHA256 hash +(600,000 iterations) via `vigilar.alerts.pin.hash_pin`, and prints a +`pin_hash = "pbkdf2_sha256$salt$dk"` line to paste into `[security]`. +Again, no file write. The same hash format is verified identically by +the web arm/disarm endpoint and by `ArmStateFSM` in the event +processor — there is one canonical PIN store. ## Secrets and security @@ -388,9 +390,13 @@ write. volume on integrity-verified storage (dm-integrity, ZFS with checksums) or mirror to write-once media. - The web UI password is a scrypt hash set by `vigilar config - set-password` and stored at `[web] password_hash`. The arm PIN is - an HMAC stored at `[system] arm_pin_hash` (and/or `[security] - pin_hash`). + set-password` and stored at `[web] password_hash`. The arm/disarm + PIN is a PBKDF2-SHA256 hash (600k iterations, salted) set by + `vigilar config set-pin` and stored at `[security] pin_hash`. + A legacy `[system] arm_pin_hash` field is still parsed but ignored + at runtime; if it's set and `[security] pin_hash` is empty, the + service logs a deprecation warning at startup and arm/disarm will + behave as if no PIN were configured until you re-run `set-pin`. - TLS: `gen_cert.sh` uses `mkcert` if present, otherwise an `openssl` ECDSA P-256 self-signed certificate valid for 3650 days with SANs for `vigilar.local`, `localhost`, `127.0.0.1`, and the detected LAN @@ -602,10 +608,6 @@ Do not expose port `49735` directly on the WAN; require the tunnel. `[health]` for real disk policy. - **No schema migrations.** There is no Alembic (or equivalent) in the tree. Rollbacks rely on your backup discipline. -- **Duplicate PIN fields.** `vigilar config set-pin` writes to - `[system] arm_pin_hash`, while the web arm/disarm flow reads from - `[security] pin_hash`. Both models exist. If you set one and the - other side does not behave as expected, mirror the value manually. ## Troubleshooting