fix clippy issues
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Hamcha 2023-07-07 00:29:55 +02:00
parent 089163f79d
commit 9d6586063d
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89
8 changed files with 40 additions and 47 deletions

View file

@ -10,7 +10,7 @@ use crate::http::error::ApiError;
use super::{hash::random, user::User}; 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, status: StatusCode::UNAUTHORIZED,
code: "user-not-found", code: "user-not-found",
message: "The logged-in user was not found", message: "The logged-in user was not found",
@ -49,7 +49,7 @@ impl Session {
Ok(Self { Ok(Self {
id: result.id, id: result.id,
actor: user_id, actor: user_id,
secret: secret, secret,
created_at: now, created_at: now,
expires_at: now + duration, expires_at: now + duration,
}) })
@ -109,7 +109,7 @@ impl Session {
} }
} }
pub async fn refresh(self: Self, pool: &Pool<Postgres>, duration: Duration) -> Result<Self> { pub async fn refresh(self, pool: &Pool<Postgres>, duration: Duration) -> Result<Self> {
let expires_at = (Utc::now() + duration).naive_utc(); let expires_at = (Utc::now() + duration).naive_utc();
sqlx::query!( sqlx::query!(
@ -123,13 +123,13 @@ impl Session {
Ok(Session { expires_at, ..self }) Ok(Session { expires_at, ..self })
} }
pub fn token(self: &Self) -> String { pub fn token(&self) -> String {
format!("{}:{}", self.id.as_u128(), self.secret) format!("{}:{}", self.id.as_u128(), self.secret)
} }
pub fn parse_token(token: &str) -> Result<(Uuid, String)> { pub fn parse_token(token: &str) -> Result<(Uuid, String)> {
let (uuid_str, token_str) = token let (uuid_str, token_str) = token
.split_once(":") .split_once(':')
.ok_or_else(|| anyhow!("malformed token"))?; .ok_or_else(|| anyhow!("malformed token"))?;
Ok(( Ok((
Uuid::from_u128(uuid_str.parse::<u128>()?), Uuid::from_u128(uuid_str.parse::<u128>()?),
@ -137,7 +137,7 @@ impl Session {
)) ))
} }
pub async fn destroy(self: Self, pool: &Pool<Postgres>) -> Result<()> { pub async fn destroy(&self, pool: &Pool<Postgres>) -> Result<()> {
sqlx::query!("DELETE FROM sessions WHERE id = $1", self.id) sqlx::query!("DELETE FROM sessions WHERE id = $1", self.id)
.execute(pool) .execute(pool)
.await?; .await?;
@ -152,7 +152,7 @@ impl Session {
Ok(result.rows_affected()) 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()) Cookie::build("session", self.token())
.domain(domain) .domain(domain)
.secure(secure) .secure(secure)

View file

@ -10,5 +10,5 @@ pub enum Error {
IdentifierNotAvailable, IdentifierNotAvailable,
#[error("Database error: {0}")] #[error("Database error: {0}")]
DatabaseError(#[from] sqlx::Error), QueryFailed(#[from] sqlx::Error),
} }

View file

@ -63,7 +63,7 @@ impl SiteRepository for Database {
})?; })?;
if result.rows_affected() == 0 { if result.rows_affected() == 0 {
return Err(Error::NotFound.into()); return Err(Error::NotFound);
} }
Ok(()) Ok(())
@ -90,7 +90,7 @@ impl SiteRepository for Database {
}; };
if result.rows_affected() == 0 { if result.rows_affected() == 0 {
return Err(Error::NotFound.into()); return Err(Error::NotFound);
} }
Ok(()) Ok(())

View file

@ -10,12 +10,12 @@ use thiserror::Error;
use crate::content; use crate::content;
// Generic errors // Generic errors
const ERR_NOT_FOUND: ApiError<'static> = ApiError::ClientError { const ERR_NOT_FOUND: ApiError<'static> = ApiError::Client {
status: StatusCode::NOT_FOUND, status: StatusCode::NOT_FOUND,
code: "not-found", code: "not-found",
message: "resource 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, status: StatusCode::CONFLICT,
code: "id-not-available", code: "id-not-available",
message: "the chosen identifier is not available", message: "the chosen identifier is not available",
@ -24,41 +24,41 @@ const ERR_NOT_AVAILABLE: ApiError<'static> = ApiError::ClientError {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ApiError<'a> { pub enum ApiError<'a> {
#[error("client error: <{code}> {message}")] #[error("client error: <{code}> {message}")]
ClientError { Client {
status: StatusCode, status: StatusCode,
code: &'a str, code: &'a str,
message: &'a str, message: &'a str,
}, },
#[error("unexpected internal error: {0}")] #[error("unexpected internal error: {0}")]
InternalError(#[from] anyhow::Error), Internal(#[from] anyhow::Error),
#[error("database returnede error: {0}")] #[error("database returnede error: {0}")]
DatabaseError(#[from] sqlx::Error), Database(#[from] sqlx::Error),
#[error("incoming JSON format error: {0}")] #[error("incoming JSON format error: {0}")]
JSONFormatError(#[from] JsonRejection), JSONFormat(#[from] JsonRejection),
} }
impl IntoResponse for ApiError<'_> { impl IntoResponse for ApiError<'_> {
fn into_response(self) -> Response { fn into_response(self) -> Response {
match self { match self {
ApiError::InternalError(err) => ( ApiError::Internal(err) => (
StatusCode::INTERNAL_SERVER_ERROR, StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"code":"server-error", "message": err.to_string()})), Json(json!({"code":"server-error", "message": err.to_string()})),
) )
.into_response(), .into_response(),
ApiError::DatabaseError(err) => ( ApiError::Database(err) => (
StatusCode::INTERNAL_SERVER_ERROR, StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"code":"server-error", "message": err.to_string()})), Json(json!({"code":"server-error", "message": err.to_string()})),
) )
.into_response(), .into_response(),
ApiError::ClientError { ApiError::Client {
status, status,
code, code,
message, message,
} => (status, Json(json!({"code":code, "message": message}))).into_response(), } => (status, Json(json!({"code":code, "message": message}))).into_response(),
ApiError::JSONFormatError(rejection) => { ApiError::JSONFormat(rejection) => {
let status = match rejection { let status = match rejection {
JsonRejection::JsonDataError(_) => StatusCode::UNPROCESSABLE_ENTITY, JsonRejection::JsonDataError(_) => StatusCode::UNPROCESSABLE_ENTITY,
JsonRejection::JsonSyntaxError(_) => StatusCode::BAD_REQUEST, JsonRejection::JsonSyntaxError(_) => StatusCode::BAD_REQUEST,
@ -80,7 +80,7 @@ impl From<content::Error> for ApiError<'_> {
match err { match err {
content::Error::NotFound => ERR_NOT_FOUND, content::Error::NotFound => ERR_NOT_FOUND,
content::Error::IdentifierNotAvailable => ERR_NOT_AVAILABLE, content::Error::IdentifierNotAvailable => ERR_NOT_AVAILABLE,
content::Error::DatabaseError(err) => err.into(), content::Error::QueryFailed(err) => err.into(),
} }
} }
} }

View file

@ -22,16 +22,14 @@ use crate::{
state::AppState, state::AppState,
}; };
pub const INVALID_SESSION: ApiError = ApiError::ClientError { pub const INVALID_SESSION: ApiError = ApiError::Client {
status: StatusCode::UNAUTHORIZED, status: StatusCode::UNAUTHORIZED,
code: "authentication-required", code: "authentication-required",
message: "Please log-in and submit a valid session as a cookie", message: "Please log-in and submit a valid session as a cookie",
}; };
fn extract_session_token(header: &HeaderValue) -> Result<(Uuid, String)> { fn extract_session_token(header: &HeaderValue) -> Result<(Uuid, String)> {
Ok(Session::parse_token( Session::parse_token(Cookie::parse(header.to_str()?)?.value())
Cookie::parse(header.to_str()?)?.value(),
)?)
} }
pub struct RequireUser(pub User); pub struct RequireUser(pub User);
@ -78,18 +76,17 @@ pub async fn refresh_sessions<B>(
.get(COOKIE) .get(COOKIE)
.and_then(|header| extract_session_token(header).ok()) .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 // session validity requirements: secret must match, session must not have been expired
if session.secret == session_secret && session.expires_at >= Utc::now().naive_utc() { 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! // 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( .refresh(
&state.database, &state.database,
Duration::seconds(state.config.session_duration), Duration::seconds(state.config.session_duration),
) )
.await .await
.map(|s| (s, user)) .map(|s| (s, user))
.ok()
{ {
let extensions = req.extensions_mut(); let extensions = req.extensions_mut();
extensions.insert(session.clone()); extensions.insert(session.clone());

View file

@ -24,10 +24,10 @@ async fn bootstrap(State(state): State<Arc<AppState>>) -> impl IntoResponse {
.map_err(anyhow::Error::from)?; .map_err(anyhow::Error::from)?;
if !empty { if !empty {
return Err(ApiError::ClientError { return Err(ApiError::Client {
status: StatusCode::BAD_REQUEST, status: StatusCode::BAD_REQUEST,
code: "already-setup".into(), code: "already-setup",
message: "The instance was already bootstrapped".into(), message: "The instance was already bootstrapped",
}); });
} }
@ -36,7 +36,7 @@ async fn bootstrap(State(state): State<Arc<AppState>>) -> impl IntoResponse {
User::create( User::create(
&state.database, &state.database,
&username, username,
&password, &password,
&[ROLE_SUPERADMIN].to_vec(), &[ROLE_SUPERADMIN].to_vec(),
) )

View file

@ -35,10 +35,10 @@ async fn login(
.map_err(ApiError::from)?; .map_err(ApiError::from)?;
let invalid = || -> ApiError { let invalid = || -> ApiError {
ApiError::ClientError { ApiError::Client {
status: StatusCode::UNAUTHORIZED, status: StatusCode::UNAUTHORIZED,
code: "invalid-login".into(), code: "invalid-login",
message: "No matching user was found".into(), message: "No matching user was found",
} }
}; };
@ -52,7 +52,7 @@ async fn login(
let session = Session::create( let session = Session::create(
&state.database, &state.database,
user.id, user.id,
Duration::seconds(state.config.session_duration.into()), Duration::seconds(state.config.session_duration),
) )
.await .await
.map_err(ApiError::from)?; .map_err(ApiError::from)?;
@ -64,7 +64,7 @@ async fn login(
response.headers_mut().insert( response.headers_mut().insert(
SET_COOKIE, SET_COOKIE,
session session
.cookie(state.config.domain().as_str(), state.config.secure()) .cookie(&state.config.domain(), state.config.secure())
.parse() .parse()
.map_err(anyhow::Error::from)?, .map_err(anyhow::Error::from)?,
); );
@ -85,7 +85,7 @@ async fn logout(
let mut response: Response = Json(json!({ "ok": true })).into_response(); let mut response: Response = Json(json!({ "ok": true })).into_response();
response.headers_mut().insert( response.headers_mut().insert(
SET_COOKIE, 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() .parse()
.map_err(anyhow::Error::from)?, .map_err(anyhow::Error::from)?,
); );

View file

@ -1,5 +1,5 @@
use axum::{ use axum::{
extract::{Path, State}, extract::Path,
response::IntoResponse, response::IntoResponse,
routing::{get, post}, routing::{get, post},
Json, Router, Json, Router,
@ -7,10 +7,7 @@ use axum::{
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
content::page::PageRepository, content::page::PageRepository, database::Database, http::error::ApiError, state::AppState,
database::Database,
http::{error::ApiError, session::RequireUser},
state::AppState,
}; };
async fn get_page<Repo: PageRepository>( async fn get_page<Repo: PageRepository>(
@ -20,10 +17,9 @@ async fn get_page<Repo: PageRepository>(
Ok(Json(repository.get_page_from_url(&site, &slug).await?)) Ok(Json(repository.get_page_from_url(&site, &slug).await?))
} }
async fn create_page<Repo: PageRepository>( async fn create_page<Repo: PageRepository>(//repository: Repo,
repository: Repo, //Path(site): Path<String>,
Path(site): Path<String>, //RequireUser(user): RequireUser,
RequireUser(user): RequireUser,
) -> Result<impl IntoResponse, ApiError<'static>> { ) -> Result<impl IntoResponse, ApiError<'static>> {
Ok(Json("todo")) Ok(Json("todo"))
} }