mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-09 15:58:48 +00:00
Add notification tracking and tests
This commit is contained in:
@@ -51,6 +51,9 @@ MAX_PASSWORD_LENGTH = 128 # Maximum allowed password length
|
|||||||
# Timeout in seconds before the vault locks due to inactivity
|
# Timeout in seconds before the vault locks due to inactivity
|
||||||
INACTIVITY_TIMEOUT = 15 * 60 # 15 minutes
|
INACTIVITY_TIMEOUT = 15 * 60 # 15 minutes
|
||||||
|
|
||||||
|
# Duration in seconds that a notification remains active
|
||||||
|
NOTIFICATION_DURATION = 10
|
||||||
|
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
# Additional Constants (if any)
|
# Additional Constants (if any)
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
|
@@ -75,6 +75,7 @@ from constants import (
|
|||||||
DEFAULT_PASSWORD_LENGTH,
|
DEFAULT_PASSWORD_LENGTH,
|
||||||
INACTIVITY_TIMEOUT,
|
INACTIVITY_TIMEOUT,
|
||||||
DEFAULT_SEED_BACKUP_FILENAME,
|
DEFAULT_SEED_BACKUP_FILENAME,
|
||||||
|
NOTIFICATION_DURATION,
|
||||||
initialize_app,
|
initialize_app,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -137,6 +138,8 @@ class PasswordManager:
|
|||||||
self.nostr_client: Optional[NostrClient] = None
|
self.nostr_client: Optional[NostrClient] = None
|
||||||
self.config_manager: Optional[ConfigManager] = None
|
self.config_manager: Optional[ConfigManager] = None
|
||||||
self.notifications: queue.Queue[Notification] = queue.Queue()
|
self.notifications: queue.Queue[Notification] = queue.Queue()
|
||||||
|
self._current_notification: Optional[Notification] = None
|
||||||
|
self._notification_expiry: float = 0.0
|
||||||
|
|
||||||
# Track changes to trigger periodic Nostr sync
|
# Track changes to trigger periodic Nostr sync
|
||||||
self.is_dirty: bool = False
|
self.is_dirty: bool = False
|
||||||
@@ -228,8 +231,26 @@ class PasswordManager:
|
|||||||
self.last_activity = time.time()
|
self.last_activity = time.time()
|
||||||
|
|
||||||
def notify(self, message: str, level: str = "INFO") -> None:
|
def notify(self, message: str, level: str = "INFO") -> None:
|
||||||
"""Enqueue a notification for later retrieval."""
|
"""Enqueue a notification and set it as the active message."""
|
||||||
self.notifications.put(Notification(message, level))
|
note = Notification(message, level)
|
||||||
|
self.notifications.put(note)
|
||||||
|
self._current_notification = note
|
||||||
|
self._notification_expiry = time.time() + NOTIFICATION_DURATION
|
||||||
|
|
||||||
|
def get_current_notification(self) -> Optional[Notification]:
|
||||||
|
"""Return the active notification if it hasn't expired."""
|
||||||
|
if not self.notifications.empty():
|
||||||
|
latest = self.notifications.queue[-1]
|
||||||
|
if latest is not self._current_notification:
|
||||||
|
self._current_notification = latest
|
||||||
|
self._notification_expiry = time.time() + NOTIFICATION_DURATION
|
||||||
|
|
||||||
|
if (
|
||||||
|
self._current_notification is not None
|
||||||
|
and time.time() < self._notification_expiry
|
||||||
|
):
|
||||||
|
return self._current_notification
|
||||||
|
return None
|
||||||
|
|
||||||
def lock_vault(self) -> None:
|
def lock_vault(self) -> None:
|
||||||
"""Clear sensitive information from memory."""
|
"""Clear sensitive information from memory."""
|
||||||
|
45
src/tests/test_manager_current_notification.py
Normal file
45
src/tests/test_manager_current_notification.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import queue
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
|
from password_manager.manager import PasswordManager, Notification
|
||||||
|
from constants import NOTIFICATION_DURATION
|
||||||
|
|
||||||
|
|
||||||
|
def _make_pm():
|
||||||
|
pm = PasswordManager.__new__(PasswordManager)
|
||||||
|
pm.notifications = queue.Queue()
|
||||||
|
pm._current_notification = None
|
||||||
|
pm._notification_expiry = 0.0
|
||||||
|
return pm
|
||||||
|
|
||||||
|
|
||||||
|
def test_notify_sets_current(monkeypatch):
|
||||||
|
pm = _make_pm()
|
||||||
|
current = {"val": 100.0}
|
||||||
|
monkeypatch.setattr("password_manager.manager.time.time", lambda: current["val"])
|
||||||
|
pm.notify("hello")
|
||||||
|
note = pm._current_notification
|
||||||
|
assert isinstance(note, Notification)
|
||||||
|
assert note.message == "hello"
|
||||||
|
assert pm._notification_expiry == 100.0 + NOTIFICATION_DURATION
|
||||||
|
assert pm.notifications.qsize() == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_current_notification_ttl(monkeypatch):
|
||||||
|
pm = _make_pm()
|
||||||
|
now = {"val": 0.0}
|
||||||
|
monkeypatch.setattr("password_manager.manager.time.time", lambda: now["val"])
|
||||||
|
pm.notify("note1")
|
||||||
|
|
||||||
|
assert pm.get_current_notification().message == "note1"
|
||||||
|
assert pm.notifications.qsize() == 1
|
||||||
|
|
||||||
|
now["val"] += NOTIFICATION_DURATION - 1
|
||||||
|
assert pm.get_current_notification().message == "note1"
|
||||||
|
|
||||||
|
now["val"] += 2
|
||||||
|
assert pm.get_current_notification() is None
|
Reference in New Issue
Block a user