1
0
Fork 0
forked from 2sys/shoutdotdev
shoutdotdev/src/csrf.rs

61 lines
1.8 KiB
Rust
Raw Normal View History

2025-02-26 13:10:50 -08:00
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<Uuid>,
) -> Result<String, AppError> {
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<Uuid>,
) -> Result<bool, AppError> {
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())
}