ezidam/crates/users/src/totp_login_request.rs

73 lines
1.9 KiB
Rust

use crate::Error;
use chrono::{DateTime, Duration, Utc};
use database::sqlx::SqliteExecutor;
use database::TotpLoginRequests as DatabaseTotpLoginRequests;
use id::UserID;
pub const TOTP_REQUEST_COOKIE_NAME: &str = "totp_request";
pub const TOTP_REQUEST_LEN: usize = 25;
pub struct TotpLoginRequest {
// Info
token: String,
user: UserID,
// Timings
created_at: DateTime<Utc>,
expires_at: DateTime<Utc>,
used_at: Option<DateTime<Utc>>,
}
impl TotpLoginRequest {
pub fn token(&self) -> &str {
&self.token
}
pub fn user(&self) -> &UserID {
&self.user
}
pub fn has_expired(&self) -> bool {
self.expires_at < Utc::now()
}
pub fn used_at(&self) -> Option<DateTime<Utc>> {
self.used_at
}
}
impl From<DatabaseTotpLoginRequests> for TotpLoginRequest {
fn from(db: DatabaseTotpLoginRequests) -> Self {
Self {
token: db.token,
user: UserID(db.user),
created_at: db.created_at,
expires_at: db.expires_at,
used_at: db.used_at,
}
}
}
impl TotpLoginRequest {
pub async fn insert(
conn: impl SqliteExecutor<'_>,
token: &str,
user: &UserID,
validity_minutes: i64,
) -> Result<Option<()>, Error> {
let expires_at = Utc::now() + Duration::minutes(validity_minutes);
Ok(DatabaseTotpLoginRequests::insert(conn, token, &user.0, expires_at.timestamp()).await?)
}
pub async fn get_one(
conn: impl SqliteExecutor<'_>,
token: &str,
) -> Result<Option<Self>, Error> {
Ok(DatabaseTotpLoginRequests::get_one(conn, token)
.await?
.map(Self::from))
}
/// Consume and mark as used
pub async fn use_code(self, conn: impl SqliteExecutor<'_>) -> Result<Option<()>, Error> {
Ok(DatabaseTotpLoginRequests::use_token(conn, &self.token).await?)
}
}