1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5use uuid::Uuid;
6
7use crate::error::{AuthError, AuthResult};
8use crate::types::{
9 Account, CreateAccount, CreateInvitation, CreateMember, CreateOrganization, CreateSession,
10 CreateTwoFactor, CreateUser, CreateVerification, Invitation, InvitationStatus, Member,
11 Organization, Session, TwoFactor, UpdateAccount, UpdateOrganization, UpdateUser, User,
12 Verification,
13};
14
15pub use super::memory_traits::{
16 MemoryAccount, MemoryInvitation, MemoryMember, MemoryOrganization, MemorySession,
17 MemoryTwoFactor, MemoryUser, MemoryVerification,
18};
19
20use super::traits::{
21 AccountOps, InvitationOps, MemberOps, OrganizationOps, SessionOps, TwoFactorOps, UserOps,
22 VerificationOps,
23};
24
25pub struct MemoryDatabaseAdapter<
40 U = User,
41 S = Session,
42 A = Account,
43 O = Organization,
44 M = Member,
45 I = Invitation,
46 V = Verification,
47> {
48 users: Arc<Mutex<HashMap<String, U>>>,
49 sessions: Arc<Mutex<HashMap<String, S>>>,
50 accounts: Arc<Mutex<HashMap<String, A>>>,
51 verifications: Arc<Mutex<HashMap<String, V>>>,
52 email_index: Arc<Mutex<HashMap<String, String>>>,
53 username_index: Arc<Mutex<HashMap<String, String>>>,
54 organizations: Arc<Mutex<HashMap<String, O>>>,
55 members: Arc<Mutex<HashMap<String, M>>>,
56 invitations: Arc<Mutex<HashMap<String, I>>>,
57 slug_index: Arc<Mutex<HashMap<String, String>>>,
58 two_factors: Arc<Mutex<HashMap<String, TwoFactor>>>,
59}
60
61impl MemoryDatabaseAdapter {
64 pub fn new() -> Self {
65 Self::default()
66 }
67}
68
69impl<U, S, A, O, M, I, V> Default for MemoryDatabaseAdapter<U, S, A, O, M, I, V> {
70 fn default() -> Self {
71 Self {
72 users: Arc::new(Mutex::new(HashMap::new())),
73 sessions: Arc::new(Mutex::new(HashMap::new())),
74 accounts: Arc::new(Mutex::new(HashMap::new())),
75 verifications: Arc::new(Mutex::new(HashMap::new())),
76 email_index: Arc::new(Mutex::new(HashMap::new())),
77 username_index: Arc::new(Mutex::new(HashMap::new())),
78 organizations: Arc::new(Mutex::new(HashMap::new())),
79 members: Arc::new(Mutex::new(HashMap::new())),
80 invitations: Arc::new(Mutex::new(HashMap::new())),
81 slug_index: Arc::new(Mutex::new(HashMap::new())),
82 two_factors: Arc::new(Mutex::new(HashMap::new())),
83 }
84 }
85}
86
87#[async_trait]
90impl<U, S, A, O, M, I, V> UserOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
91where
92 U: MemoryUser,
93 S: MemorySession,
94 A: MemoryAccount,
95 O: MemoryOrganization,
96 M: MemoryMember,
97 I: MemoryInvitation,
98 V: MemoryVerification,
99{
100 type User = U;
101
102 async fn create_user(&self, create_user: CreateUser) -> AuthResult<U> {
103 let mut users = self.users.lock().unwrap();
104 let mut email_index = self.email_index.lock().unwrap();
105 let mut username_index = self.username_index.lock().unwrap();
106
107 let id = create_user
108 .id
109 .clone()
110 .unwrap_or_else(|| Uuid::new_v4().to_string());
111
112 if let Some(email) = &create_user.email
113 && email_index.contains_key(email)
114 {
115 return Err(AuthError::config("Email already exists"));
116 }
117
118 if let Some(username) = &create_user.username
119 && username_index.contains_key(username)
120 {
121 return Err(AuthError::conflict(
122 "A user with this username already exists",
123 ));
124 }
125
126 let now = Utc::now();
127 let user = U::from_create(id.clone(), &create_user, now);
128
129 users.insert(id.clone(), user.clone());
130
131 if let Some(email) = &create_user.email {
132 email_index.insert(email.clone(), id.clone());
133 }
134 if let Some(username) = &create_user.username {
135 username_index.insert(username.clone(), id);
136 }
137
138 Ok(user)
139 }
140
141 async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<U>> {
142 let users = self.users.lock().unwrap();
143 Ok(users.get(id).cloned())
144 }
145
146 async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<U>> {
147 let email_index = self.email_index.lock().unwrap();
148 let users = self.users.lock().unwrap();
149
150 if let Some(user_id) = email_index.get(email) {
151 Ok(users.get(user_id).cloned())
152 } else {
153 Ok(None)
154 }
155 }
156
157 async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<U>> {
158 let username_index = self.username_index.lock().unwrap();
159 let users = self.users.lock().unwrap();
160
161 if let Some(user_id) = username_index.get(username) {
162 Ok(users.get(user_id).cloned())
163 } else {
164 Ok(None)
165 }
166 }
167
168 async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<U> {
169 let mut users = self.users.lock().unwrap();
170 let mut email_index = self.email_index.lock().unwrap();
171 let mut username_index = self.username_index.lock().unwrap();
172
173 let user = users.get_mut(id).ok_or(AuthError::UserNotFound)?;
174
175 if let Some(new_email) = &update.email {
177 if let Some(old_email) = user.email() {
178 email_index.remove(old_email);
179 }
180 email_index.insert(new_email.clone(), id.to_string());
181 }
182
183 if let Some(ref new_username) = update.username {
184 if let Some(old_username) = user.username() {
185 username_index.remove(old_username);
186 }
187 username_index.insert(new_username.clone(), id.to_string());
188 }
189
190 user.apply_update(&update);
191 Ok(user.clone())
192 }
193
194 async fn delete_user(&self, id: &str) -> AuthResult<()> {
195 let mut users = self.users.lock().unwrap();
196 let mut email_index = self.email_index.lock().unwrap();
197 let mut username_index = self.username_index.lock().unwrap();
198
199 if let Some(user) = users.remove(id) {
200 if let Some(email) = user.email() {
201 email_index.remove(email);
202 }
203 if let Some(username) = user.username() {
204 username_index.remove(username);
205 }
206 }
207
208 Ok(())
209 }
210}
211
212#[async_trait]
215impl<U, S, A, O, M, I, V> SessionOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
216where
217 U: MemoryUser,
218 S: MemorySession,
219 A: MemoryAccount,
220 O: MemoryOrganization,
221 M: MemoryMember,
222 I: MemoryInvitation,
223 V: MemoryVerification,
224{
225 type Session = S;
226
227 async fn create_session(&self, create_session: CreateSession) -> AuthResult<S> {
228 let mut sessions = self.sessions.lock().unwrap();
229
230 let id = Uuid::new_v4().to_string();
231 let token = format!("session_{}", Uuid::new_v4());
232 let now = Utc::now();
233 let session = S::from_create(id, token.clone(), &create_session, now);
234
235 sessions.insert(token, session.clone());
236 Ok(session)
237 }
238
239 async fn get_session(&self, token: &str) -> AuthResult<Option<S>> {
240 let sessions = self.sessions.lock().unwrap();
241 Ok(sessions.get(token).cloned())
242 }
243
244 async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<S>> {
245 let sessions = self.sessions.lock().unwrap();
246 Ok(sessions
247 .values()
248 .filter(|s| s.user_id() == user_id && s.active())
249 .cloned()
250 .collect())
251 }
252
253 async fn update_session_expiry(
254 &self,
255 token: &str,
256 expires_at: DateTime<Utc>,
257 ) -> AuthResult<()> {
258 let mut sessions = self.sessions.lock().unwrap();
259 if let Some(session) = sessions.get_mut(token) {
260 session.set_expires_at(expires_at);
261 }
262 Ok(())
263 }
264
265 async fn delete_session(&self, token: &str) -> AuthResult<()> {
266 let mut sessions = self.sessions.lock().unwrap();
267 sessions.remove(token);
268 Ok(())
269 }
270
271 async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()> {
272 let mut sessions = self.sessions.lock().unwrap();
273 sessions.retain(|_, s| s.user_id() != user_id);
274 Ok(())
275 }
276
277 async fn delete_expired_sessions(&self) -> AuthResult<usize> {
278 let mut sessions = self.sessions.lock().unwrap();
279 let now = Utc::now();
280 let initial_count = sessions.len();
281 sessions.retain(|_, s| s.expires_at() > now && s.active());
282 Ok(initial_count - sessions.len())
283 }
284
285 async fn update_session_active_organization(
286 &self,
287 token: &str,
288 organization_id: Option<&str>,
289 ) -> AuthResult<S> {
290 let mut sessions = self.sessions.lock().unwrap();
291 let session = sessions.get_mut(token).ok_or(AuthError::SessionNotFound)?;
292 session.set_active_organization_id(organization_id.map(|s| s.to_string()));
293 session.set_updated_at(Utc::now());
294 Ok(session.clone())
295 }
296}
297
298#[async_trait]
301impl<U, S, A, O, M, I, V> AccountOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
302where
303 U: MemoryUser,
304 S: MemorySession,
305 A: MemoryAccount,
306 O: MemoryOrganization,
307 M: MemoryMember,
308 I: MemoryInvitation,
309 V: MemoryVerification,
310{
311 type Account = A;
312
313 async fn create_account(&self, create_account: CreateAccount) -> AuthResult<A> {
314 let mut accounts = self.accounts.lock().unwrap();
315
316 let id = Uuid::new_v4().to_string();
317 let now = Utc::now();
318 let account = A::from_create(id.clone(), &create_account, now);
319
320 accounts.insert(id, account.clone());
321 Ok(account)
322 }
323
324 async fn get_account(
325 &self,
326 provider: &str,
327 provider_account_id: &str,
328 ) -> AuthResult<Option<A>> {
329 let accounts = self.accounts.lock().unwrap();
330 Ok(accounts
331 .values()
332 .find(|acc| acc.provider_id() == provider && acc.account_id() == provider_account_id)
333 .cloned())
334 }
335
336 async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<A>> {
337 let accounts = self.accounts.lock().unwrap();
338 Ok(accounts
339 .values()
340 .filter(|acc| acc.user_id() == user_id)
341 .cloned()
342 .collect())
343 }
344
345 async fn update_account(&self, id: &str, update: UpdateAccount) -> AuthResult<A> {
346 let mut accounts = self.accounts.lock().unwrap();
347 let account = accounts
348 .get_mut(id)
349 .ok_or_else(|| AuthError::not_found("Account not found"))?;
350 account.apply_update(&update);
351 Ok(account.clone())
352 }
353
354 async fn delete_account(&self, id: &str) -> AuthResult<()> {
355 let mut accounts = self.accounts.lock().unwrap();
356 accounts.remove(id);
357 Ok(())
358 }
359}
360
361#[async_trait]
364impl<U, S, A, O, M, I, V> VerificationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
365where
366 U: MemoryUser,
367 S: MemorySession,
368 A: MemoryAccount,
369 O: MemoryOrganization,
370 M: MemoryMember,
371 I: MemoryInvitation,
372 V: MemoryVerification,
373{
374 type Verification = V;
375
376 async fn create_verification(&self, create_verification: CreateVerification) -> AuthResult<V> {
377 let mut verifications = self.verifications.lock().unwrap();
378
379 let id = Uuid::new_v4().to_string();
380 let now = Utc::now();
381 let verification = V::from_create(id.clone(), &create_verification, now);
382
383 verifications.insert(id, verification.clone());
384 Ok(verification)
385 }
386
387 async fn get_verification(&self, identifier: &str, value: &str) -> AuthResult<Option<V>> {
388 let verifications = self.verifications.lock().unwrap();
389 let now = Utc::now();
390 Ok(verifications
391 .values()
392 .find(|v| v.identifier() == identifier && v.value() == value && v.expires_at() > now)
393 .cloned())
394 }
395
396 async fn get_verification_by_value(&self, value: &str) -> AuthResult<Option<V>> {
397 let verifications = self.verifications.lock().unwrap();
398 let now = Utc::now();
399 Ok(verifications
400 .values()
401 .find(|v| v.value() == value && v.expires_at() > now)
402 .cloned())
403 }
404
405 async fn get_verification_by_identifier(&self, identifier: &str) -> AuthResult<Option<V>> {
406 let verifications = self.verifications.lock().unwrap();
407 let now = Utc::now();
408 Ok(verifications
409 .values()
410 .find(|v| v.identifier() == identifier && v.expires_at() > now)
411 .cloned())
412 }
413
414 async fn delete_verification(&self, id: &str) -> AuthResult<()> {
415 let mut verifications = self.verifications.lock().unwrap();
416 verifications.remove(id);
417 Ok(())
418 }
419
420 async fn delete_expired_verifications(&self) -> AuthResult<usize> {
421 let mut verifications = self.verifications.lock().unwrap();
422 let now = Utc::now();
423 let initial_count = verifications.len();
424 verifications.retain(|_, v| v.expires_at() > now);
425 Ok(initial_count - verifications.len())
426 }
427}
428
429#[async_trait]
432impl<U, S, A, O, M, I, V> OrganizationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
433where
434 U: MemoryUser,
435 S: MemorySession,
436 A: MemoryAccount,
437 O: MemoryOrganization,
438 M: MemoryMember,
439 I: MemoryInvitation,
440 V: MemoryVerification,
441{
442 type Organization = O;
443
444 async fn create_organization(&self, create_org: CreateOrganization) -> AuthResult<O> {
445 let mut organizations = self.organizations.lock().unwrap();
446 let mut slug_index = self.slug_index.lock().unwrap();
447
448 if slug_index.contains_key(&create_org.slug) {
449 return Err(AuthError::conflict("Organization slug already exists"));
450 }
451
452 let id = create_org
453 .id
454 .clone()
455 .unwrap_or_else(|| Uuid::new_v4().to_string());
456 let now = Utc::now();
457 let organization = O::from_create(id.clone(), &create_org, now);
458
459 organizations.insert(id.clone(), organization.clone());
460 slug_index.insert(create_org.slug.clone(), id);
461
462 Ok(organization)
463 }
464
465 async fn get_organization_by_id(&self, id: &str) -> AuthResult<Option<O>> {
466 let organizations = self.organizations.lock().unwrap();
467 Ok(organizations.get(id).cloned())
468 }
469
470 async fn get_organization_by_slug(&self, slug: &str) -> AuthResult<Option<O>> {
471 let slug_index = self.slug_index.lock().unwrap();
472 let organizations = self.organizations.lock().unwrap();
473
474 if let Some(org_id) = slug_index.get(slug) {
475 Ok(organizations.get(org_id).cloned())
476 } else {
477 Ok(None)
478 }
479 }
480
481 async fn update_organization(&self, id: &str, update: UpdateOrganization) -> AuthResult<O> {
482 let mut organizations = self.organizations.lock().unwrap();
483 let mut slug_index = self.slug_index.lock().unwrap();
484
485 let org = organizations
486 .get_mut(id)
487 .ok_or_else(|| AuthError::not_found("Organization not found"))?;
488
489 if let Some(new_slug) = &update.slug {
491 let current_slug = org.slug().to_string();
492 if *new_slug != current_slug {
493 if slug_index.contains_key(new_slug.as_str()) {
494 return Err(AuthError::conflict("Organization slug already exists"));
495 }
496 slug_index.remove(¤t_slug);
497 slug_index.insert(new_slug.clone(), id.to_string());
498 }
499 }
500
501 org.apply_update(&update);
502 Ok(org.clone())
503 }
504
505 async fn delete_organization(&self, id: &str) -> AuthResult<()> {
506 let mut organizations = self.organizations.lock().unwrap();
507 let mut slug_index = self.slug_index.lock().unwrap();
508 let mut members = self.members.lock().unwrap();
509 let mut invitations = self.invitations.lock().unwrap();
510
511 if let Some(org) = organizations.remove(id) {
512 slug_index.remove(org.slug());
513 }
514
515 members.retain(|_, m| m.organization_id() != id);
516 invitations.retain(|_, i| i.organization_id() != id);
517
518 Ok(())
519 }
520
521 async fn list_user_organizations(&self, user_id: &str) -> AuthResult<Vec<O>> {
522 let members = self.members.lock().unwrap();
523 let organizations = self.organizations.lock().unwrap();
524
525 let org_ids: Vec<String> = members
526 .values()
527 .filter(|m| m.user_id() == user_id)
528 .map(|m| m.organization_id().to_string())
529 .collect();
530
531 let orgs = org_ids
532 .iter()
533 .filter_map(|id| organizations.get(id).cloned())
534 .collect();
535
536 Ok(orgs)
537 }
538}
539
540#[async_trait]
543impl<U, S, A, O, M, I, V> MemberOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
544where
545 U: MemoryUser,
546 S: MemorySession,
547 A: MemoryAccount,
548 O: MemoryOrganization,
549 M: MemoryMember,
550 I: MemoryInvitation,
551 V: MemoryVerification,
552{
553 type Member = M;
554
555 async fn create_member(&self, create_member: CreateMember) -> AuthResult<M> {
556 let mut members = self.members.lock().unwrap();
557
558 let exists = members.values().any(|m| {
559 m.organization_id() == create_member.organization_id
560 && m.user_id() == create_member.user_id
561 });
562
563 if exists {
564 return Err(AuthError::conflict(
565 "User is already a member of this organization",
566 ));
567 }
568
569 let id = Uuid::new_v4().to_string();
570 let now = Utc::now();
571 let member = M::from_create(id.clone(), &create_member, now);
572
573 members.insert(id, member.clone());
574 Ok(member)
575 }
576
577 async fn get_member(&self, organization_id: &str, user_id: &str) -> AuthResult<Option<M>> {
578 let members = self.members.lock().unwrap();
579 Ok(members
580 .values()
581 .find(|m| m.organization_id() == organization_id && m.user_id() == user_id)
582 .cloned())
583 }
584
585 async fn get_member_by_id(&self, id: &str) -> AuthResult<Option<M>> {
586 let members = self.members.lock().unwrap();
587 Ok(members.get(id).cloned())
588 }
589
590 async fn update_member_role(&self, member_id: &str, role: &str) -> AuthResult<M> {
591 let mut members = self.members.lock().unwrap();
592 let member = members
593 .get_mut(member_id)
594 .ok_or_else(|| AuthError::not_found("Member not found"))?;
595 member.set_role(role.to_string());
596 Ok(member.clone())
597 }
598
599 async fn delete_member(&self, member_id: &str) -> AuthResult<()> {
600 let mut members = self.members.lock().unwrap();
601 members.remove(member_id);
602 Ok(())
603 }
604
605 async fn list_organization_members(&self, organization_id: &str) -> AuthResult<Vec<M>> {
606 let members = self.members.lock().unwrap();
607 Ok(members
608 .values()
609 .filter(|m| m.organization_id() == organization_id)
610 .cloned()
611 .collect())
612 }
613
614 async fn count_organization_members(&self, organization_id: &str) -> AuthResult<usize> {
615 let members = self.members.lock().unwrap();
616 Ok(members
617 .values()
618 .filter(|m| m.organization_id() == organization_id)
619 .count())
620 }
621
622 async fn count_organization_owners(&self, organization_id: &str) -> AuthResult<usize> {
623 let members = self.members.lock().unwrap();
624 Ok(members
625 .values()
626 .filter(|m| m.organization_id() == organization_id && m.role() == "owner")
627 .count())
628 }
629}
630
631#[async_trait]
634impl<U, S, A, O, M, I, V> InvitationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
635where
636 U: MemoryUser,
637 S: MemorySession,
638 A: MemoryAccount,
639 O: MemoryOrganization,
640 M: MemoryMember,
641 I: MemoryInvitation,
642 V: MemoryVerification,
643{
644 type Invitation = I;
645
646 async fn create_invitation(&self, create_inv: CreateInvitation) -> AuthResult<I> {
647 let mut invitations = self.invitations.lock().unwrap();
648
649 let id = Uuid::new_v4().to_string();
650 let now = Utc::now();
651 let invitation = I::from_create(id.clone(), &create_inv, now);
652
653 invitations.insert(id, invitation.clone());
654 Ok(invitation)
655 }
656
657 async fn get_invitation_by_id(&self, id: &str) -> AuthResult<Option<I>> {
658 let invitations = self.invitations.lock().unwrap();
659 Ok(invitations.get(id).cloned())
660 }
661
662 async fn get_pending_invitation(
663 &self,
664 organization_id: &str,
665 email: &str,
666 ) -> AuthResult<Option<I>> {
667 let invitations = self.invitations.lock().unwrap();
668 Ok(invitations
669 .values()
670 .find(|i| {
671 i.organization_id() == organization_id
672 && i.email().to_lowercase() == email.to_lowercase()
673 && *i.status() == InvitationStatus::Pending
674 })
675 .cloned())
676 }
677
678 async fn update_invitation_status(&self, id: &str, status: InvitationStatus) -> AuthResult<I> {
679 let mut invitations = self.invitations.lock().unwrap();
680 let invitation = invitations
681 .get_mut(id)
682 .ok_or_else(|| AuthError::not_found("Invitation not found"))?;
683 invitation.set_status(status);
684 Ok(invitation.clone())
685 }
686
687 async fn list_organization_invitations(&self, organization_id: &str) -> AuthResult<Vec<I>> {
688 let invitations = self.invitations.lock().unwrap();
689 Ok(invitations
690 .values()
691 .filter(|i| i.organization_id() == organization_id)
692 .cloned()
693 .collect())
694 }
695
696 async fn list_user_invitations(&self, email: &str) -> AuthResult<Vec<I>> {
697 let invitations = self.invitations.lock().unwrap();
698 let now = Utc::now();
699 Ok(invitations
700 .values()
701 .filter(|i| {
702 i.email().to_lowercase() == email.to_lowercase()
703 && *i.status() == InvitationStatus::Pending
704 && i.expires_at() > now
705 })
706 .cloned()
707 .collect())
708 }
709}
710
711#[async_trait]
714impl<U, S, A, O, M, I, V> TwoFactorOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V>
715where
716 U: MemoryUser,
717 S: MemorySession,
718 A: MemoryAccount,
719 O: MemoryOrganization,
720 M: MemoryMember,
721 I: MemoryInvitation,
722 V: MemoryVerification,
723{
724 type TwoFactor = TwoFactor;
725
726 async fn create_two_factor(&self, create: CreateTwoFactor) -> AuthResult<TwoFactor> {
727 let mut two_factors = self.two_factors.lock().unwrap();
728
729 if two_factors.values().any(|tf| tf.user_id == create.user_id) {
731 return Err(AuthError::conflict(
732 "Two-factor authentication already enabled for this user",
733 ));
734 }
735
736 let id = Uuid::new_v4().to_string();
737 let now = Utc::now();
738 let two_factor: TwoFactor = MemoryTwoFactor::from_create(id.clone(), &create, now);
739
740 two_factors.insert(id, two_factor.clone());
741 Ok(two_factor)
742 }
743
744 async fn get_two_factor_by_user_id(&self, user_id: &str) -> AuthResult<Option<TwoFactor>> {
745 let two_factors = self.two_factors.lock().unwrap();
746 Ok(two_factors
747 .values()
748 .find(|tf| tf.user_id == user_id)
749 .cloned())
750 }
751
752 async fn update_two_factor_backup_codes(
753 &self,
754 user_id: &str,
755 backup_codes: &str,
756 ) -> AuthResult<TwoFactor> {
757 let mut two_factors = self.two_factors.lock().unwrap();
758 let two_factor = two_factors
759 .values_mut()
760 .find(|tf| tf.user_id == user_id)
761 .ok_or_else(|| AuthError::not_found("Two-factor record not found"))?;
762 two_factor.set_backup_codes(backup_codes.to_string());
763 Ok(two_factor.clone())
764 }
765
766 async fn delete_two_factor(&self, user_id: &str) -> AuthResult<()> {
767 let mut two_factors = self.two_factors.lock().unwrap();
768 two_factors.retain(|_, tf| tf.user_id != user_id);
769 Ok(())
770 }
771}