fix: unify PIN hashing across CLI, FSM, and web (closes #2) #7

Merged
alee merged 16 commits from fix/issue-2-pin-unification into main 2026-04-05 16:59:51 +00:00
2 changed files with 9 additions and 12 deletions
Showing only changes of commit efa3ce4b1b - Show all commits

View File

@@ -1,6 +1,5 @@
"""Tests for the Phase 6 events subsystem: rules, arm state FSM, history.""" """Tests for the Phase 6 events subsystem: rules, arm state FSM, history."""
import hashlib
import time import time
import pytest import pytest
@@ -19,7 +18,7 @@ from vigilar.storage.queries import insert_event
def _make_config(rules=None, pin_hash=""): def _make_config(rules=None, pin_hash=""):
return VigilarConfig( return VigilarConfig(
system={"arm_pin_hash": pin_hash}, security={"pin_hash": pin_hash},
cameras=[], cameras=[],
sensors=[], sensors=[],
rules=rules or [], rules=rules or [],
@@ -27,7 +26,8 @@ def _make_config(rules=None, pin_hash=""):
def _pin_hash(pin: str) -> str: def _pin_hash(pin: str) -> str:
return hashlib.sha256(pin.encode()).hexdigest() from vigilar.alerts.pin import hash_pin
return hash_pin(pin)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@@ -1,12 +1,11 @@
"""Arm state finite state machine.""" """Arm state finite state machine."""
import hashlib
import hmac
import logging import logging
import time import time
from sqlalchemy.engine import Engine from sqlalchemy.engine import Engine
from vigilar.alerts.pin import verify_pin as _verify_pin_hash
from vigilar.config import VigilarConfig from vigilar.config import VigilarConfig
from vigilar.constants import ArmState, EventType, Severity, Topics from vigilar.constants import ArmState, EventType, Severity, Topics
from vigilar.storage.queries import get_current_arm_state, insert_arm_state, insert_event 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): def __init__(self, engine: Engine, config: VigilarConfig):
self._engine = engine self._engine = engine
self._pin_hash = config.system.arm_pin_hash self._pin_hash = config.security.pin_hash
self._state = ArmState.DISARMED self._state = ArmState.DISARMED
self._bus = None self._bus = None
self._load_initial_state() self._load_initial_state()
@@ -43,12 +42,11 @@ class ArmStateFSM:
return self._state return self._state
def verify_pin(self, pin: str) -> bool: 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: if not self._pin_hash:
# No PIN configured — allow all transitions # No PIN configured — allow all transitions
return True return True
candidate = hashlib.sha256(pin.encode()).hexdigest() return _verify_pin_hash(pin, self._pin_hash)
return hmac.compare_digest(candidate, self._pin_hash)
def transition( def transition(
self, self,
@@ -68,9 +66,8 @@ class ArmStateFSM:
old_state = self._state old_state = self._state
self._state = new_state self._state = new_state
# Log to database # Log to database (pin_hash column is no longer populated — see #2)
pin_hash = hashlib.sha256(pin.encode()).hexdigest() if pin else None insert_arm_state(self._engine, new_state.value, triggered_by, None)
insert_arm_state(self._engine, new_state.value, triggered_by, pin_hash)
# Log event # Log event
insert_event( insert_event(