shoutdotdev/src/guards.rs

55 lines
1.8 KiB
Rust

use anyhow::Result;
use deadpool_diesel::postgres::Connection;
use diesel::prelude::*;
use uuid::Uuid;
use crate::{
app_error::AppError, csrf::validate_csrf_token, team_memberships::TeamMembership, teams::Team,
users::User,
};
/// Returns a ForbiddenError if user is not a member of the indicated team.
/// Intended to be used in HTTP handlers to check authorization. The team
/// struct is often useful in such cases, so it is returned if the
/// authorization check is successful.
pub async fn require_team_membership(
current_user: &User,
team_id: &Uuid,
db_conn: &Connection,
) -> Result<Team, AppError> {
let maybe_team = {
let current_user_id = current_user.id;
let team_id = *team_id;
db_conn
.interact::<_, Result<Option<(Team, _)>>>(move |conn| {
TeamMembership::all()
.filter(TeamMembership::with_user_id(&current_user_id))
.filter(TeamMembership::with_team_id(&team_id))
.first(conn)
.optional()
.map_err(Into::into)
})
.await
.unwrap()?
};
match maybe_team {
Some((team, _)) => Ok(team),
None => Err(AppError::ForbiddenError(
"not a member of requested team".to_string(),
)),
}
}
/// Returns a ForbiddenError if the CSRF token parameters do not match an entry
/// in the database. Do not expect this function to invalidate tokens after use.
pub async fn require_valid_csrf_token(
csrf_token: &str,
current_user: &User,
db_conn: &Connection,
) -> Result<(), AppError> {
if validate_csrf_token(db_conn, csrf_token, Some(current_user.id)).await? {
Ok(())
} else {
Err(AppError::ForbiddenError("invalid CSRF token".to_string()))
}
}