use anyhow::{Context, Result}; use chrono::{TimeDelta, Utc}; use deadpool_diesel::postgres::Pool; use diesel::prelude::*; use uuid::Uuid; use crate::{app_error::AppError, models::CsrfToken, schema}; const TOKEN_PREFIX: &'static str = "csrf__"; const TTL_SEC: i64 = 60 * 60 * 24 * 7; pub async fn generate_csrf_token_for_user( db_pool: &Pool, uid: Option, ) -> Result { let id = Uuid::new_v4(); let expires_at = Utc::now() + TimeDelta::new(TTL_SEC, 0).context("Failed to generate TimeDelta")?; db_pool .get() .await? .interact(move |conn| { diesel::insert_into(schema::csrf_tokens::table) .values(( schema::csrf_tokens::id.eq(id), schema::csrf_tokens::user_id.eq(uid), schema::csrf_tokens::expires_at.eq(expires_at), )) .execute(conn) }) .await .unwrap()?; Ok(format!("{}{}", TOKEN_PREFIX, id.hyphenated().to_string())) } pub async fn validate_csrf_token_for_user( db_pool: &Pool, token: &str, uid: Option, ) -> Result { let id = match Uuid::try_parse(&token[TOKEN_PREFIX.len()..]) { Ok(id) => id, Err(_) => return Ok(false), }; let row = db_pool .get() .await? .interact(move |conn| { schema::csrf_tokens::table .select(CsrfToken::as_select()) .filter(schema::csrf_tokens::id.eq(id)) .filter(schema::csrf_tokens::expires_at.gt(Utc::now())) .filter(schema::csrf_tokens::user_id.is_not_distinct_from(uid)) .first(conn) .optional() }) .await .unwrap()?; Ok(row.is_some()) }