diff --git a/src/auth/session.rs b/src/auth/session.rs index ab8ebdb..268f6ff 100644 --- a/src/auth/session.rs +++ b/src/auth/session.rs @@ -10,7 +10,7 @@ use crate::http::error::ApiError; use super::{hash::random, user::User}; -pub const USER_NOT_FOUND: ApiError<'static> = ApiError::ClientError { +pub const USER_NOT_FOUND: ApiError<'static> = ApiError::Client { status: StatusCode::UNAUTHORIZED, code: "user-not-found", message: "The logged-in user was not found", @@ -49,7 +49,7 @@ impl Session { Ok(Self { id: result.id, actor: user_id, - secret: secret, + secret, created_at: now, expires_at: now + duration, }) @@ -109,7 +109,7 @@ impl Session { } } - pub async fn refresh(self: Self, pool: &Pool, duration: Duration) -> Result { + pub async fn refresh(self, pool: &Pool, duration: Duration) -> Result { let expires_at = (Utc::now() + duration).naive_utc(); sqlx::query!( @@ -123,13 +123,13 @@ impl Session { Ok(Session { expires_at, ..self }) } - pub fn token(self: &Self) -> String { + pub fn token(&self) -> String { format!("{}:{}", self.id.as_u128(), self.secret) } pub fn parse_token(token: &str) -> Result<(Uuid, String)> { let (uuid_str, token_str) = token - .split_once(":") + .split_once(':') .ok_or_else(|| anyhow!("malformed token"))?; Ok(( Uuid::from_u128(uuid_str.parse::()?), @@ -137,7 +137,7 @@ impl Session { )) } - pub async fn destroy(self: Self, pool: &Pool) -> Result<()> { + pub async fn destroy(&self, pool: &Pool) -> Result<()> { sqlx::query!("DELETE FROM sessions WHERE id = $1", self.id) .execute(pool) .await?; @@ -152,7 +152,7 @@ impl Session { Ok(result.rows_affected()) } - pub fn cookie(self: &Self, domain: &str, secure: bool) -> String { + pub fn cookie(&self, domain: &str, secure: bool) -> String { Cookie::build("session", self.token()) .domain(domain) .secure(secure) diff --git a/src/content/mod.rs b/src/content/mod.rs index 054fbfc..54dc371 100644 --- a/src/content/mod.rs +++ b/src/content/mod.rs @@ -10,5 +10,5 @@ pub enum Error { IdentifierNotAvailable, #[error("Database error: {0}")] - DatabaseError(#[from] sqlx::Error), + QueryFailed(#[from] sqlx::Error), } diff --git a/src/database/site.rs b/src/database/site.rs index a6b8235..1dde272 100644 --- a/src/database/site.rs +++ b/src/database/site.rs @@ -63,7 +63,7 @@ impl SiteRepository for Database { })?; if result.rows_affected() == 0 { - return Err(Error::NotFound.into()); + return Err(Error::NotFound); } Ok(()) @@ -90,7 +90,7 @@ impl SiteRepository for Database { }; if result.rows_affected() == 0 { - return Err(Error::NotFound.into()); + return Err(Error::NotFound); } Ok(()) diff --git a/src/http/error.rs b/src/http/error.rs index 8c75d60..a86ec8b 100644 --- a/src/http/error.rs +++ b/src/http/error.rs @@ -10,12 +10,12 @@ use thiserror::Error; use crate::content; // Generic errors -const ERR_NOT_FOUND: ApiError<'static> = ApiError::ClientError { +const ERR_NOT_FOUND: ApiError<'static> = ApiError::Client { status: StatusCode::NOT_FOUND, code: "not-found", message: "resource not found", }; -const ERR_NOT_AVAILABLE: ApiError<'static> = ApiError::ClientError { +const ERR_NOT_AVAILABLE: ApiError<'static> = ApiError::Client { status: StatusCode::CONFLICT, code: "id-not-available", message: "the chosen identifier is not available", @@ -24,41 +24,41 @@ const ERR_NOT_AVAILABLE: ApiError<'static> = ApiError::ClientError { #[derive(Error, Debug)] pub enum ApiError<'a> { #[error("client error: <{code}> {message}")] - ClientError { + Client { status: StatusCode, code: &'a str, message: &'a str, }, #[error("unexpected internal error: {0}")] - InternalError(#[from] anyhow::Error), + Internal(#[from] anyhow::Error), #[error("database returnede error: {0}")] - DatabaseError(#[from] sqlx::Error), + Database(#[from] sqlx::Error), #[error("incoming JSON format error: {0}")] - JSONFormatError(#[from] JsonRejection), + JSONFormat(#[from] JsonRejection), } impl IntoResponse for ApiError<'_> { fn into_response(self) -> Response { match self { - ApiError::InternalError(err) => ( + ApiError::Internal(err) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"code":"server-error", "message": err.to_string()})), ) .into_response(), - ApiError::DatabaseError(err) => ( + ApiError::Database(err) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"code":"server-error", "message": err.to_string()})), ) .into_response(), - ApiError::ClientError { + ApiError::Client { status, code, message, } => (status, Json(json!({"code":code, "message": message}))).into_response(), - ApiError::JSONFormatError(rejection) => { + ApiError::JSONFormat(rejection) => { let status = match rejection { JsonRejection::JsonDataError(_) => StatusCode::UNPROCESSABLE_ENTITY, JsonRejection::JsonSyntaxError(_) => StatusCode::BAD_REQUEST, @@ -80,7 +80,7 @@ impl From for ApiError<'_> { match err { content::Error::NotFound => ERR_NOT_FOUND, content::Error::IdentifierNotAvailable => ERR_NOT_AVAILABLE, - content::Error::DatabaseError(err) => err.into(), + content::Error::QueryFailed(err) => err.into(), } } } diff --git a/src/http/session.rs b/src/http/session.rs index 30d75f8..0f66470 100644 --- a/src/http/session.rs +++ b/src/http/session.rs @@ -22,16 +22,14 @@ use crate::{ state::AppState, }; -pub const INVALID_SESSION: ApiError = ApiError::ClientError { +pub const INVALID_SESSION: ApiError = ApiError::Client { status: StatusCode::UNAUTHORIZED, code: "authentication-required", message: "Please log-in and submit a valid session as a cookie", }; fn extract_session_token(header: &HeaderValue) -> Result<(Uuid, String)> { - Ok(Session::parse_token( - Cookie::parse(header.to_str()?)?.value(), - )?) + Session::parse_token(Cookie::parse(header.to_str()?)?.value()) } pub struct RequireUser(pub User); @@ -78,18 +76,17 @@ pub async fn refresh_sessions( .get(COOKIE) .and_then(|header| extract_session_token(header).ok()) { - if let Some(Some((session, user))) = Session::find(&state.database, session_id).await.ok() { + if let Ok(Some((session, user))) = Session::find(&state.database, session_id).await { // session validity requirements: secret must match, session must not have been expired if session.secret == session_secret && session.expires_at >= Utc::now().naive_utc() { // in the future we might wanna change the session secret, if we do, do it here! - if let Some((session, user)) = session + if let Ok((session, user)) = session .refresh( &state.database, Duration::seconds(state.config.session_duration), ) .await .map(|s| (s, user)) - .ok() { let extensions = req.extensions_mut(); extensions.insert(session.clone()); diff --git a/src/routes/admin.rs b/src/routes/admin.rs index 3defd12..f6cd1c0 100644 --- a/src/routes/admin.rs +++ b/src/routes/admin.rs @@ -24,10 +24,10 @@ async fn bootstrap(State(state): State>) -> impl IntoResponse { .map_err(anyhow::Error::from)?; if !empty { - return Err(ApiError::ClientError { + return Err(ApiError::Client { status: StatusCode::BAD_REQUEST, - code: "already-setup".into(), - message: "The instance was already bootstrapped".into(), + code: "already-setup", + message: "The instance was already bootstrapped", }); } @@ -36,7 +36,7 @@ async fn bootstrap(State(state): State>) -> impl IntoResponse { User::create( &state.database, - &username, + username, &password, &[ROLE_SUPERADMIN].to_vec(), ) diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 6a81e2b..0df61a4 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -35,10 +35,10 @@ async fn login( .map_err(ApiError::from)?; let invalid = || -> ApiError { - ApiError::ClientError { + ApiError::Client { status: StatusCode::UNAUTHORIZED, - code: "invalid-login".into(), - message: "No matching user was found".into(), + code: "invalid-login", + message: "No matching user was found", } }; @@ -52,7 +52,7 @@ async fn login( let session = Session::create( &state.database, user.id, - Duration::seconds(state.config.session_duration.into()), + Duration::seconds(state.config.session_duration), ) .await .map_err(ApiError::from)?; @@ -64,7 +64,7 @@ async fn login( response.headers_mut().insert( SET_COOKIE, session - .cookie(state.config.domain().as_str(), state.config.secure()) + .cookie(&state.config.domain(), state.config.secure()) .parse() .map_err(anyhow::Error::from)?, ); @@ -85,7 +85,7 @@ async fn logout( let mut response: Response = Json(json!({ "ok": true })).into_response(); response.headers_mut().insert( SET_COOKIE, - Session::cookie_for_delete(state.config.domain().as_str(), state.config.secure()) + Session::cookie_for_delete(&state.config.domain(), state.config.secure()) .parse() .map_err(anyhow::Error::from)?, ); diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 58e4c0b..7ea89cd 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -1,5 +1,5 @@ use axum::{ - extract::{Path, State}, + extract::Path, response::IntoResponse, routing::{get, post}, Json, Router, @@ -7,10 +7,7 @@ use axum::{ use std::sync::Arc; use crate::{ - content::page::PageRepository, - database::Database, - http::{error::ApiError, session::RequireUser}, - state::AppState, + content::page::PageRepository, database::Database, http::error::ApiError, state::AppState, }; async fn get_page( @@ -20,10 +17,9 @@ async fn get_page( Ok(Json(repository.get_page_from_url(&site, &slug).await?)) } -async fn create_page( - repository: Repo, - Path(site): Path, - RequireUser(user): RequireUser, +async fn create_page(//repository: Repo, + //Path(site): Path, + //RequireUser(user): RequireUser, ) -> Result> { Ok(Json("todo")) }