diff --git a/src/seedpass/core/config_manager.py b/src/seedpass/core/config_manager.py index 31b469c..0e45c7a 100644 --- a/src/seedpass/core/config_manager.py +++ b/src/seedpass/core/config_manager.py @@ -51,7 +51,7 @@ class ConfigManager: "backup_interval": 0, "secret_mode_enabled": False, "clipboard_clear_delay": 45, - "quick_unlock": False, + "quick_unlock_enabled": False, "nostr_max_retries": MAX_RETRIES, "nostr_retry_delay": float(RETRY_DELAY), "min_uppercase": 2, @@ -80,7 +80,7 @@ class ConfigManager: data.setdefault("backup_interval", 0) data.setdefault("secret_mode_enabled", False) data.setdefault("clipboard_clear_delay", 45) - data.setdefault("quick_unlock", False) + data.setdefault("quick_unlock_enabled", data.get("quick_unlock", False)) data.setdefault("nostr_max_retries", MAX_RETRIES) data.setdefault("nostr_retry_delay", float(RETRY_DELAY)) data.setdefault("min_uppercase", 2) @@ -320,13 +320,13 @@ class ConfigManager: def set_quick_unlock(self, enabled: bool) -> None: """Persist the quick unlock toggle.""" cfg = self.load_config(require_pin=False) - cfg["quick_unlock"] = bool(enabled) + cfg["quick_unlock_enabled"] = bool(enabled) self.save_config(cfg) def get_quick_unlock(self) -> bool: """Retrieve whether quick unlock is enabled.""" cfg = self.load_config(require_pin=False) - return bool(cfg.get("quick_unlock", False)) + return bool(cfg.get("quick_unlock_enabled", False)) def set_nostr_max_retries(self, retries: int) -> None: """Persist the maximum number of Nostr retry attempts.""" diff --git a/src/seedpass/core/manager.py b/src/seedpass/core/manager.py index 87147a8..77ff604 100644 --- a/src/seedpass/core/manager.py +++ b/src/seedpass/core/manager.py @@ -17,6 +17,7 @@ import hashlib from typing import Optional, Literal import shutil import time +from datetime import datetime, timezone import builtins import threading import queue @@ -345,6 +346,15 @@ class PasswordManager: self.initialize_managers() self.locked = False self.update_activity() + if ( + getattr(self, "config_manager", None) + and self.config_manager.get_quick_unlock() + ): + logger.info( + "Quick unlock used by %s at %s", + self.current_fingerprint or "unknown", + datetime.now(timezone.utc).isoformat(), + ) self.last_unlock_duration = time.perf_counter() - start if getattr(self, "verbose_timing", False): logger.info("Vault unlocked in %.2f seconds", self.last_unlock_duration) diff --git a/src/tests/test_config_manager.py b/src/tests/test_config_manager.py index f1f4b0e..4095bd3 100644 --- a/src/tests/test_config_manager.py +++ b/src/tests/test_config_manager.py @@ -23,7 +23,7 @@ def test_config_defaults_and_round_trip(): assert cfg["pin_hash"] == "" assert cfg["password_hash"] == "" assert cfg["additional_backup_path"] == "" - assert cfg["quick_unlock"] is False + assert cfg["quick_unlock_enabled"] is False assert cfg["kdf_iterations"] == 50_000 cfg_mgr.set_pin("1234") diff --git a/src/tests/test_quick_unlock_default.py b/src/tests/test_quick_unlock_default.py new file mode 100644 index 0000000..1f635c6 --- /dev/null +++ b/src/tests/test_quick_unlock_default.py @@ -0,0 +1,34 @@ +import logging +from types import SimpleNamespace +from pathlib import Path +import sys + +import pytest + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass.core.manager import PasswordManager +from seedpass.core.config_manager import ConfigManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + + +def test_quick_unlock_default_off(tmp_path): + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + assert cfg_mgr.get_quick_unlock() is False + + +def test_quick_unlock_logs_event(tmp_path, caplog): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = "user123" + pm.setup_encryption_manager = lambda *a, **k: None + pm.initialize_bip85 = lambda: None + pm.initialize_managers = lambda: None + pm.update_activity = lambda: None + pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: True) + + with caplog.at_level(logging.INFO): + pm.unlock_vault(password="pw") + + assert any("Quick unlock used by user123" in rec.message for rec in caplog.records)