cyaxon_authifier/database/
dummy.rs

1use crate::{
2	models::{Account, Invite, MFATicket, Session, EmailVerification, DeletionInfo},
3	Result, Success, Error
4};
5
6use futures::lock::Mutex;
7use std::sync::Arc;
8use std::collections::HashMap;
9
10use super::{definition::AbstractDatabase, Migration};
11
12#[derive(Default, Clone)]
13pub struct DummyDb {
14	pub accounts: Arc<Mutex<HashMap<String, Account>>>,
15	pub invites: Arc<Mutex<HashMap<String, Invite>>>,
16	pub sessions: Arc<Mutex<HashMap<String, Session>>>,
17	pub tickets: Arc<Mutex<HashMap<String, MFATicket>>>,
18}
19
20#[async_trait]
21impl AbstractDatabase for DummyDb {
22	/// Run a database migration
23	async fn run_migration(&self, migration: Migration) -> Success {
24			println!("skip migration {:?}", migration);
25			Ok(())
26	}
27
28	/// Find account by id
29	async fn find_account(&self, id: &str) -> Result<Account> {
30			let accounts = self.accounts.lock().await;
31			accounts.get(id).cloned().ok_or(Error::UnknownUser)
32	}
33
34	/// Find account by normalized email
35	async fn find_account_by_normalized_email(
36			&self,
37			normalized_email: &str,
38	) -> Result<Option<Account>> {
39			let accounts = self.accounts.lock().await;
40			Ok(accounts.values()
41					.find(|account| account.email_normalized == normalized_email)
42					.cloned())
43	}
44
45	/// Find account with active pending email verification
46	async fn find_account_with_email_verification(&self, token_to_match: &str) -> Result<Account> {
47			let accounts = self.accounts.lock().await;
48			accounts.values()
49					.find(|account| match &account.verification {
50							EmailVerification::Pending { token, .. } | EmailVerification::Moving { token, .. } => token == token_to_match,
51							_ => false
52					})
53					.cloned()
54					.ok_or(Error::InvalidToken)
55	}
56
57	/// Find account with active password reset
58	async fn find_account_with_password_reset(&self, token: &str) -> Result<Account> {
59			let accounts = self.accounts.lock().await;
60			accounts.values()
61					.find(|account| if let Some(reset) = &account.password_reset {
62							reset.token == token
63					} else {
64							false
65					})
66					.cloned()
67					.ok_or(Error::InvalidToken)
68	}
69
70	/// Find account with active deletion token
71	async fn find_account_with_deletion_token(&self, token_to_match: &str) -> Result<Account> {
72			let accounts = self.accounts.lock().await;
73			accounts.values()
74					.find(|account| if let Some(DeletionInfo::WaitingForVerification { token, .. }) = &account.deletion {
75							token == token_to_match
76					} else {
77							false
78					})
79					.cloned()
80					.ok_or(Error::InvalidToken)
81	}
82
83	/// Find invite by id
84	async fn find_invite(&self, id: &str) -> Result<Invite> {
85			let invites = self.invites.lock().await;
86			invites.get(id).cloned().ok_or(Error::InvalidInvite)
87	}
88
89	/// Find session by id
90	async fn find_session(&self, id: &str) -> Result<Session> {
91			let sessions = self.sessions.lock().await;
92			sessions.get(id).cloned().ok_or(Error::UnknownUser)
93	}
94
95	/// Find sessions by user id
96	async fn find_sessions(&self, user_id: &str) -> Result<Vec<Session>> {
97			let sessions = self.sessions.lock().await;
98			Ok(sessions
99					.values()
100					.filter(|session| session.user_id == user_id)
101					.cloned()
102					.collect())
103	}
104
105	/// Find sessions by user ids
106	async fn find_sessions_with_subscription(&self, user_ids: &[String]) -> Result<Vec<Session>> {
107			let sessions = self.sessions.lock().await;
108			Ok(sessions
109					.values()
110					.filter(|session| session.subscription.is_some() && user_ids.contains(&session.id))
111					.cloned()
112					.collect())
113	}
114
115	/// Find session by token
116	async fn find_session_by_token(&self, token: &str) -> Result<Option<Session>> {
117			let sessions = self.sessions.lock().await;
118			Ok(sessions.values()
119					.find(|session| session.token == token)
120					.cloned())
121	}
122
123	/// Find ticket by token
124	async fn find_ticket_by_token(&self, token: &str) -> Result<Option<MFATicket>> {
125			let tickets = self.tickets.lock().await;
126			Ok(tickets.values()
127					.find(|ticket| ticket.token == token)
128					.cloned())
129	}
130
131	// Save account
132	async fn save_account(&self, account: &Account) -> Success {
133			let mut accounts = self.accounts.lock().await;
134			accounts.insert(account.id.to_string(), account.clone());
135			Ok(())
136	}
137
138	/// Save session
139	async fn save_session(&self, session: &Session) -> Success {
140			let mut sessions = self.sessions.lock().await;
141			sessions.insert(session.id.to_string(), session.clone());
142			Ok(())
143	}
144
145	/// Save invite
146	async fn save_invite(&self, invite: &Invite) -> Success {
147			let mut invites = self.invites.lock().await;
148			invites.insert(invite.id.to_string(), invite.clone());
149			Ok(())
150	}
151
152	/// Save ticket
153	async fn save_ticket(&self, ticket: &MFATicket) -> Success {
154			let mut tickets = self.tickets.lock().await;
155			tickets.insert(ticket.id.to_string(), ticket.clone());
156			Ok(())
157	}
158
159	/// Delete session
160	async fn delete_session(&self, id: &str) -> Success {
161			let mut sessions = self.sessions.lock().await;
162			if sessions.remove(id).is_some() {
163					Ok(())
164			} else {
165					Err(Error::InvalidSession)
166			}
167	}
168
169	/// Delete session
170	async fn delete_all_sessions(&self, user_id: &str, ignore: Option<String>) -> Success {
171			let mut sessions = self.sessions.lock().await;
172			sessions.retain(|_, session|
173					if session.user_id == user_id {
174							if let Some(ignore) = &ignore {
175									ignore == &session.id
176							} else {
177									false
178							}
179					} else {
180							true
181					}
182			);
183
184			Ok(())
185	}
186
187	/// Delete ticket
188	async fn delete_ticket(&self, id: &str) -> Success {
189			let mut tickets = self.tickets.lock().await;
190			if tickets.remove(id).is_some() {
191					Ok(())
192			} else {
193					Err(Error::InvalidToken)
194			}
195	}
196}