Coverage for src/lexigram/auth/storage/in_memory_stores.py: 60%
43 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
1"""In-memory session store for development and testing."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7if TYPE_CHECKING:
8 from lexigram.auth.models.session import UserSession
11class InMemorySessionStore:
12 """In-memory session storage for development and testing.
14 This store is NOT suitable for production as it does not persist data
15 across restarts and does not support multi-instance deployments.
16 """
18 def __init__(self) -> None:
19 self._sessions: dict[str, UserSession] = {}
21 async def create(self, session: UserSession) -> str:
22 """Create a new session."""
23 self._sessions[session.session_id] = session
24 return session.session_id
26 async def get(self, session_id: str) -> UserSession | None:
27 """Get a session by ID."""
28 return self._sessions.get(session_id)
30 async def update(self, session_id: str, **updates: Any) -> None:
31 """Update session fields."""
32 session = self._sessions.get(session_id)
33 if session:
34 for key, value in updates.items():
35 if hasattr(session, key):
36 object.__setattr__(session, key, value)
38 async def delete(self, session_id: str) -> bool:
39 """Delete a session."""
40 if session_id in self._sessions:
41 del self._sessions[session_id]
42 return True
43 return False
45 async def delete_all_for_user(self, user_id: str) -> int:
46 """Delete all sessions for a user."""
47 to_delete = [sid for sid, s in self._sessions.items() if s.user_id == user_id]
48 for sid in to_delete:
49 del self._sessions[sid]
50 return len(to_delete)
52 async def list_for_user(self, user_id: str) -> list[UserSession]:
53 """List all sessions for a user."""
54 return [
55 s
56 for s in self._sessions.values()
57 if s.user_id == user_id and s.is_active and not s.is_expired()
58 ]
61class InMemoryMFAStore:
62 """In-memory MFA storage for development and testing.
64 This store is NOT suitable for production.
65 """
67 def __init__(self) -> None:
68 self._mfa: dict[str, dict[str, Any]] = {}
70 async def get(self, user_id: str) -> dict[str, Any] | None:
71 """Get MFA config for a user."""
72 return self._mfa.get(user_id)
74 async def save(self, mfa_data: dict[str, object]) -> None:
75 """Save MFA config for a user."""
76 user_id = mfa_data.get("user_id")
77 if isinstance(user_id, str):
78 self._mfa[user_id] = mfa_data
80 async def delete(self, user_id: str) -> bool:
81 """Delete MFA config for a user."""
82 if user_id in self._mfa:
83 del self._mfa[user_id]
84 return True
85 return False
88__all__ = [
89 "InMemoryMFAStore",
90 "InMemorySessionStore",
91]