Coverage for src / local_deep_research / database / session_passwords.py: 91%

23 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-01-11 00:51 +0000

1""" 

2Session-based password storage for metrics access. 

3 

4This module provides a way to temporarily store passwords in memory 

5for the duration of a user's session, allowing background threads 

6to access encrypted databases for metrics writing. 

7 

8SECURITY NOTES: 

91. Passwords are only stored in memory, never on disk 

102. Passwords are stored in plain text in memory (encryption removed as it 

11 provided no real security benefit - see issue #593) 

123. Passwords are automatically cleared on logout 

134. This is only used for metrics/logging, not user data access 

14""" 

15 

16from typing import Optional 

17 

18from loguru import logger 

19 

20from .credential_store_base import CredentialStoreBase 

21 

22 

23class SessionPasswordStore(CredentialStoreBase): 

24 """ 

25 Stores passwords temporarily for active sessions. 

26 Used to allow background threads to write metrics to encrypted databases. 

27 """ 

28 

29 def __init__(self, ttl_hours: int = 24): 

30 """ 

31 Initialize the session password store. 

32 

33 Args: 

34 ttl_hours: How long to keep passwords (default 24 hours) 

35 """ 

36 super().__init__(ttl_hours * 3600) # Convert to seconds 

37 

38 def store_session_password( 

39 self, username: str, session_id: str, password: str 

40 ) -> None: 

41 """ 

42 Store a password for an active session. 

43 

44 Args: 

45 username: The username 

46 session_id: The Flask session ID 

47 password: The password to store 

48 """ 

49 key = f"{username}:{session_id}" 

50 self._store_credentials( 

51 key, {"username": username, "password": password} 

52 ) 

53 logger.debug(f"Stored session password for {username}") 

54 

55 def get_session_password( 

56 self, username: str, session_id: str 

57 ) -> Optional[str]: 

58 """ 

59 Retrieve a password for an active session. 

60 

61 Args: 

62 username: The username 

63 session_id: The Flask session ID 

64 

65 Returns: 

66 The decrypted password or None if not found/expired 

67 """ 

68 key = f"{username}:{session_id}" 

69 result = self._retrieve_credentials(key, remove=False) 

70 return result[1] if result else None 

71 

72 def clear_session(self, username: str, session_id: str) -> None: 

73 """ 

74 Clear password for a specific session (on logout). 

75 

76 Args: 

77 username: The username 

78 session_id: The Flask session ID 

79 """ 

80 key = f"{username}:{session_id}" 

81 self.clear_entry(key) 

82 logger.debug(f"Cleared session password for {username}") 

83 

84 # Implement abstract methods for compatibility 

85 def store(self, username: str, session_id: str, password: str) -> None: 

86 """Alias for store_session_password.""" 

87 self.store_session_password(username, session_id, password) 

88 

89 def retrieve(self, username: str, session_id: str) -> Optional[str]: 

90 """Alias for get_session_password.""" 

91 return self.get_session_password(username, session_id) 

92 

93 

94# Global instance 

95session_password_store = SessionPasswordStore()