re-implement guards using AppError returns instead of macros
This commit is contained in:
parent
47bb893d3f
commit
f7ca1c134b
3 changed files with 53 additions and 48 deletions
|
@ -7,6 +7,7 @@ use axum::response::{IntoResponse, Response};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AppError {
|
pub enum AppError {
|
||||||
InternalServerError(Error),
|
InternalServerError(Error),
|
||||||
|
ForbiddenError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell axum how to convert `AppError` into a response.
|
// Tell axum how to convert `AppError` into a response.
|
||||||
|
@ -14,9 +15,13 @@ impl IntoResponse for AppError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
match self {
|
match self {
|
||||||
Self::InternalServerError(err) => {
|
Self::InternalServerError(err) => {
|
||||||
tracing::error!("Application error: {:#}", err);
|
tracing::error!("Application error: {}", err);
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response()
|
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response()
|
||||||
}
|
}
|
||||||
|
Self::ForbiddenError(client_message) => {
|
||||||
|
tracing::info!("Forbidden: {}", client_message);
|
||||||
|
(StatusCode::FORBIDDEN, client_message).into_response()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,45 @@
|
||||||
macro_rules! require_team_membership {
|
use deadpool_diesel::postgres::Connection;
|
||||||
($current_user:expr, $team_id:expr, $db_conn:expr) => {{
|
use diesel::prelude::*;
|
||||||
let current_user_id = $current_user.id.clone();
|
use uuid::Uuid;
|
||||||
match $db_conn
|
|
||||||
|
use crate::{
|
||||||
|
app_error::AppError, csrf::validate_csrf_token, team_memberships::TeamMembership, teams::Team,
|
||||||
|
users::User,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn require_team_membership(
|
||||||
|
current_user: &User,
|
||||||
|
team_id: &Uuid,
|
||||||
|
db_conn: &Connection,
|
||||||
|
) -> Result<Team, AppError> {
|
||||||
|
let current_user_id = current_user.id.clone();
|
||||||
|
let team_id = team_id.clone();
|
||||||
|
match db_conn
|
||||||
.interact(move |conn| {
|
.interact(move |conn| {
|
||||||
crate::team_memberships::TeamMembership::all()
|
TeamMembership::all()
|
||||||
.filter(crate::team_memberships::TeamMembership::with_user_id(
|
.filter(TeamMembership::with_user_id(current_user_id))
|
||||||
current_user_id,
|
.filter(TeamMembership::with_team_id(team_id))
|
||||||
))
|
|
||||||
.filter(crate::team_memberships::TeamMembership::with_team_id(
|
|
||||||
$team_id,
|
|
||||||
))
|
|
||||||
.first(conn)
|
.first(conn)
|
||||||
.optional()
|
.optional()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()?
|
.unwrap()?
|
||||||
{
|
{
|
||||||
Some((team, _)) => team,
|
Some((team, _)) => Ok(team),
|
||||||
None => {
|
None => Err(AppError::ForbiddenError(
|
||||||
return Ok((
|
|
||||||
axum::http::StatusCode::FORBIDDEN,
|
|
||||||
"not a member of requested team".to_string(),
|
"not a member of requested team".to_string(),
|
||||||
)
|
)),
|
||||||
.into_response());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}};
|
|
||||||
}
|
|
||||||
pub(crate) use require_team_membership;
|
|
||||||
|
|
||||||
macro_rules! require_valid_csrf_token {
|
pub async fn require_valid_csrf_token(
|
||||||
($csrf_token:expr, $current_user:expr, $db_conn:expr) => {{
|
csrf_token: &str,
|
||||||
if !crate::csrf::validate_csrf_token(&$db_conn, &$csrf_token, Some($current_user.id))
|
current_user: &User,
|
||||||
.await?
|
db_conn: &Connection,
|
||||||
{
|
) -> Result<(), AppError> {
|
||||||
return Ok((
|
if validate_csrf_token(db_conn, csrf_token, Some(current_user.id.clone())).await? {
|
||||||
axum::http::StatusCode::FORBIDDEN,
|
Ok(())
|
||||||
"invalid CSRF token".to_string(),
|
} else {
|
||||||
)
|
Err(AppError::ForbiddenError("invalid CSRF token".to_string()))
|
||||||
.into_response());
|
|
||||||
}
|
}
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
pub(crate) use require_valid_csrf_token;
|
|
||||||
|
|
|
@ -111,8 +111,8 @@ async fn post_new_api_key(
|
||||||
CurrentUser(current_user): CurrentUser,
|
CurrentUser(current_user): CurrentUser,
|
||||||
Form(form): Form<PostNewApiKeyForm>,
|
Form(form): Form<PostNewApiKeyForm>,
|
||||||
) -> Result<impl IntoResponse, AppError> {
|
) -> Result<impl IntoResponse, AppError> {
|
||||||
guards::require_valid_csrf_token!(form.csrf_token, current_user, db_conn);
|
guards::require_valid_csrf_token(&form.csrf_token, ¤t_user, &db_conn).await?;
|
||||||
let team = guards::require_team_membership!(current_user, team_id, db_conn);
|
let team = guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
||||||
|
|
||||||
ApiKey::generate_for_team(&db_conn, team.id.clone()).await?;
|
ApiKey::generate_for_team(&db_conn, team.id.clone()).await?;
|
||||||
Ok(Redirect::to(&format!(
|
Ok(Redirect::to(&format!(
|
||||||
|
@ -158,7 +158,7 @@ async fn post_new_team(
|
||||||
CurrentUser(current_user): CurrentUser,
|
CurrentUser(current_user): CurrentUser,
|
||||||
Form(form): Form<PostNewTeamForm>,
|
Form(form): Form<PostNewTeamForm>,
|
||||||
) -> Result<impl IntoResponse, AppError> {
|
) -> Result<impl IntoResponse, AppError> {
|
||||||
guards::require_valid_csrf_token!(form.csrf_token, current_user, db_conn);
|
guards::require_valid_csrf_token(&form.csrf_token, ¤t_user, &db_conn).await?;
|
||||||
|
|
||||||
let team_id = Uuid::now_v7();
|
let team_id = Uuid::now_v7();
|
||||||
let team = Team {
|
let team = Team {
|
||||||
|
@ -195,7 +195,7 @@ async fn projects_page(
|
||||||
Path(team_id): Path<Uuid>,
|
Path(team_id): Path<Uuid>,
|
||||||
CurrentUser(current_user): CurrentUser,
|
CurrentUser(current_user): CurrentUser,
|
||||||
) -> Result<impl IntoResponse, AppError> {
|
) -> Result<impl IntoResponse, AppError> {
|
||||||
let team = guards::require_team_membership!(current_user, team_id, db_conn);
|
let team = guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
||||||
|
|
||||||
let team_id = team.id.clone();
|
let team_id = team.id.clone();
|
||||||
let api_keys = db_conn
|
let api_keys = db_conn
|
||||||
|
|
Loading…
Add table
Reference in a new issue