From 7fda351c02cf36a13eb7304221d3d7cae78ffb18 Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Sun, 5 Apr 2026 11:26:07 -0400 Subject: [PATCH] fix(events): ArmStateFSM uses PBKDF2 via alerts.pin (issue #2) Was: unsalted SHA-256 read from [system] arm_pin_hash. Now: PBKDF2-SHA256 600k iterations read from [security] pin_hash, matching the web arm/disarm path and the alerts/pin module. Also drops the redundant pin re-hash on the arm_state_log audit row (a fresh PBKDF2 salt made the column valueless for traceability). Part of issue #2 PIN hashing unification. Co-Authored-By: Claude Sonnet 4.6 --- tests/unit/test_events.py | 6 +++--- vigilar/events/state.py | 15 ++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/unit/test_events.py b/tests/unit/test_events.py index 6e6e023..f802524 100644 --- a/tests/unit/test_events.py +++ b/tests/unit/test_events.py @@ -1,6 +1,5 @@ """Tests for the Phase 6 events subsystem: rules, arm state FSM, history.""" -import hashlib import time import pytest @@ -19,7 +18,7 @@ from vigilar.storage.queries import insert_event def _make_config(rules=None, pin_hash=""): return VigilarConfig( - system={"arm_pin_hash": pin_hash}, + security={"pin_hash": pin_hash}, cameras=[], sensors=[], rules=rules or [], @@ -27,7 +26,8 @@ def _make_config(rules=None, pin_hash=""): def _pin_hash(pin: str) -> str: - return hashlib.sha256(pin.encode()).hexdigest() + from vigilar.alerts.pin import hash_pin + return hash_pin(pin) # --------------------------------------------------------------------------- diff --git a/vigilar/events/state.py b/vigilar/events/state.py index dad5b1f..12f66a7 100644 --- a/vigilar/events/state.py +++ b/vigilar/events/state.py @@ -1,12 +1,11 @@ """Arm state finite state machine.""" -import hashlib -import hmac import logging import time from sqlalchemy.engine import Engine +from vigilar.alerts.pin import verify_pin as _verify_pin_hash from vigilar.config import VigilarConfig from vigilar.constants import ArmState, EventType, Severity, Topics from vigilar.storage.queries import get_current_arm_state, insert_arm_state, insert_event @@ -19,7 +18,7 @@ class ArmStateFSM: def __init__(self, engine: Engine, config: VigilarConfig): self._engine = engine - self._pin_hash = config.system.arm_pin_hash + self._pin_hash = config.security.pin_hash self._state = ArmState.DISARMED self._bus = None self._load_initial_state() @@ -43,12 +42,11 @@ class ArmStateFSM: return self._state def verify_pin(self, pin: str) -> bool: - """Verify a PIN against the stored hash using HMAC comparison.""" + """Verify a PIN against the stored PBKDF2 hash.""" if not self._pin_hash: # No PIN configured — allow all transitions return True - candidate = hashlib.sha256(pin.encode()).hexdigest() - return hmac.compare_digest(candidate, self._pin_hash) + return _verify_pin_hash(pin, self._pin_hash) def transition( self, @@ -68,9 +66,8 @@ class ArmStateFSM: old_state = self._state self._state = new_state - # Log to database - pin_hash = hashlib.sha256(pin.encode()).hexdigest() if pin else None - insert_arm_state(self._engine, new_state.value, triggered_by, pin_hash) + # Log to database (pin_hash column is no longer populated — see #2) + insert_arm_state(self._engine, new_state.value, triggered_by, None) # Log event insert_event(