revolt_database/models/mfa_tickets/ops/
mongodb.rs1use std::time::{Duration, SystemTime};
2
3use crate::{AbstractMFATickets, MFATicket, MongoDb};
4use bson::{to_document, Document};
5use iso8601_timestamp::Timestamp;
6use mongodb::options::UpdateOptions;
7use revolt_result::Result;
8use ulid::Ulid;
9
10const COL: &str = "mfa_tickets";
11
12#[async_trait]
13impl AbstractMFATickets for MongoDb {
14 async fn fetch_ticket_by_token(&self, token: &str) -> Result<MFATicket> {
18 let ticket: MFATicket = query!(self, find_one, COL, doc! { "token": token })?
19 .ok_or_else(|| create_error!(InvalidToken))?;
20
21 if let Ok(ulid) = Ulid::from_string(&ticket.id) {
22 if Timestamp::from(ulid.datetime() + Duration::from_mins(5)) > Timestamp::now_utc() {
23 Ok(ticket)
24 } else {
25 Err(create_error!(InvalidToken))
26 }
27 } else {
28 Err(create_error!(InvalidToken))
29 }
30 }
31
32 async fn save_ticket(&self, ticket: &MFATicket) -> Result<()> {
34 self.col::<MFATicket>(COL)
35 .update_one(
36 doc! {
37 "_id": &ticket.id
38 },
39 doc! {
40 "$set": to_document(ticket).map_err(|_| create_database_error!("to_document", COL))?,
41 },
42 )
43 .with_options(UpdateOptions::builder().upsert(true).build())
44 .await
45 .map_err(|_| create_database_error!("upsert_one", COL))
46 .map(|_| ())
47 }
48
49 async fn delete_ticket(&self, id: &str) -> Result<()> {
51 query!(self, delete_one_by_id, COL, id).map(|_| ())
52 }
53
54 async fn delete_expired_tickets(&self) -> Result<usize> {
56 let threshhold =
57 Ulid::from_datetime(SystemTime::now() - Duration::from_mins(5)).to_string();
58
59 self.col::<Document>(COL)
60 .delete_many(doc! {
61 "_id": { "$lt": threshhold }
62 })
63 .await
64 .map_err(|_| create_database_error!("delete_many", COL))
65 .map(|result| result.deleted_count as usize)
66 }
67}