From 547793e91056e97bb97e4fdc31b7eb8448839424 Mon Sep 17 00:00:00 2001 From: mobergmann Date: Tue, 21 Nov 2023 23:56:31 +0100 Subject: [PATCH] wip --- src/{storage.rs => database.rs} | 0 src/logic.rs | 29 ++++++++------- src/logic/account.rs | 0 src/logic/activities.rs | 0 src/logic/auth.rs | 37 ++++++++++++++++++++ src/logic/users.rs | 0 src/main.rs | 10 +++--- src/{services.rs => routes.rs} | 62 ++++++++++++++++++++------------- 8 files changed, 97 insertions(+), 41 deletions(-) rename src/{storage.rs => database.rs} (100%) create mode 100644 src/logic/account.rs create mode 100644 src/logic/activities.rs create mode 100644 src/logic/auth.rs create mode 100644 src/logic/users.rs rename src/{services.rs => routes.rs} (52%) diff --git a/src/storage.rs b/src/database.rs similarity index 100% rename from src/storage.rs rename to src/database.rs diff --git a/src/logic.rs b/src/logic.rs index 38ce2b7..826d75e 100644 --- a/src/logic.rs +++ b/src/logic.rs @@ -1,7 +1,12 @@ +mod auth; +mod account; +mod users; +mod activities; + use crate::activity::{BareActivity, StringBareActivity}; -use crate::storage::Error; +use crate::database::Error; use crate::user::{BareUser, PublicUser, User}; -use crate::{hasher, storage}; +use crate::{hasher, database}; use axum::extract::Path; use axum::http::StatusCode; use axum::response::IntoResponse; @@ -17,19 +22,19 @@ pub async fn ping() -> impl IntoResponse { pub async fn sign_up(Json(payload): Json) -> impl IntoResponse { // if username already exists, return with error - if storage::user_exists(&payload.name).await { + if database::user_exists(&payload.name).await { return (StatusCode::CONFLICT).into_response(); } // create a new user - match storage::insert_new_user(&payload).await { + match database::insert_new_user(&payload).await { Ok(user) => (StatusCode::CREATED, Json(user)).into_response(), Err(_) => (StatusCode::INTERNAL_SERVER_ERROR).into_response(), } } pub async fn sign_in(mut auth: AuthContext, Json(payload): Json) -> impl IntoResponse { - let user = match storage::get_user(&payload.name).await { + let user = match database::get_user(&payload.name).await { Ok(user) => user, Err(_) => return (StatusCode::NOT_FOUND, "name does not exist").into_response(), }; @@ -48,7 +53,7 @@ pub async fn sign_out(mut auth: AuthContext) -> impl IntoResponse { } pub async fn get_activity(mut auth: AuthContext, Path(activity_id): Path) -> impl IntoResponse { - let activity = match storage::get_activity(activity_id).await { + let activity = match database::get_activity(activity_id).await { Ok(activity) => activity, Err(Error::ElementNotFound) => return (StatusCode::NOT_FOUND).into_response(), Err(_) => { @@ -79,7 +84,7 @@ pub async fn get_activities_from_to(mut auth: AuthContext, Path((from, to)): Pat println!("from: {}, to: {}", from, to); - match storage::get_activities(&from, &to).await { + match database::get_activities(&from, &to).await { Ok(activities) => (StatusCode::OK, Json(activities)).into_response(), Err(_) => (StatusCode::INTERNAL_SERVER_ERROR).into_response(), } @@ -121,7 +126,7 @@ pub async fn new_activity( println!("from: {}, to: {}", end_time, start_time); - match storage::new_activity(&BareActivity { + match database::new_activity(&BareActivity { amount: payload.amount, activity_type: payload.activity_type, start_time: start_time, @@ -146,7 +151,7 @@ pub async fn delete_activity( mut auth: AuthContext, Path(activity_id): Path, ) -> impl IntoResponse { - let activity = match storage::get_activity(activity_id).await { + let activity = match database::get_activity(activity_id).await { Ok(activity) => activity, Err(Error::ElementNotFound) => return (StatusCode::NOT_FOUND).into_response(), Err(_) => { @@ -159,7 +164,7 @@ pub async fn delete_activity( return (StatusCode::UNAUTHORIZED).into_response(); } - let activity = match storage::delete_activity(activity_id).await { + let activity = match database::delete_activity(activity_id).await { Ok(activity) => activity, Err(_) => { return (StatusCode::INTERNAL_SERVER_ERROR).into_response() @@ -170,7 +175,7 @@ pub async fn delete_activity( pub async fn get_user(mut auth: AuthContext, Path(username): Path) -> impl IntoResponse { - let user = match storage::get_user(&username).await { + let user = match database::get_user(&username).await { Ok(user) => user, Err(Error::ElementNotFound) => return (StatusCode::NO_CONTENT).into_response(), Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR).into_response(), @@ -181,7 +186,7 @@ pub async fn get_user(mut auth: AuthContext, Path(username): Path) -> im pub async fn get_user_by_id(mut auth: AuthContext, Path(user_id): Path) -> impl IntoResponse { - let user = match storage::get_user_by_id(&user_id).await { + let user = match database::get_user_by_id(&user_id).await { Ok(user) => user, Err(Error::ElementNotFound) => return (StatusCode::NO_CONTENT).into_response(), Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR).into_response(), diff --git a/src/logic/account.rs b/src/logic/account.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/logic/activities.rs b/src/logic/activities.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/logic/auth.rs b/src/logic/auth.rs new file mode 100644 index 0000000..313e8a5 --- /dev/null +++ b/src/logic/auth.rs @@ -0,0 +1,37 @@ +type AuthContext = axum_login::extractors::AuthContext>; + +use crate::user::{BareUser, PublicUser, User}; +use crate::database::{BareUser, PublicUser, User}; + +use axum_login::SqliteStore; +use axum::response::IntoResponse; +use axum::http::StatusCode; +use axum::Json; + +pub async fn sign_in(mut auth: AuthContext, Json(payload): Json) -> impl IntoResponse +{ + let user = match database::get_user(&payload.name).await + { + Ok(user) => user, + Err(_) => return (StatusCode::NOT_FOUND, "name does not exist").into_response(), + }; + + if !hasher::verify(&user.password_hash, &payload.password) + { + return (StatusCode::UNAUTHORIZED, "password doesn't match").into_response(); + } + + auth.login(&user).await.unwrap(); + (StatusCode::OK, Json(user)).into_response() +} + +pub async fn sign_out(mut auth: AuthContext) -> impl IntoResponse +{ + auth.logout().await; + (StatusCode::OK).into_response() +} + +pub async fn ping() -> impl IntoResponse +{ + (StatusCode::OK).into_response() +} diff --git a/src/logic/users.rs b/src/logic/users.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 3b013f9..507be94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,8 @@ mod activity; mod hasher; mod logic; -mod services; -mod storage; +mod routes; +mod database; mod user; use axum::Router; @@ -10,14 +10,14 @@ use axum::Router; #[tokio::main] async fn main() { // init database or exit program on error - match storage::init().await { + match database::init().await { Ok(_) => {}, Err(_) => panic!("Error while initializing the database."), }; let app = Router::new() - .merge(services::backend_router().await) - .merge(services::frontend_router().await); + .merge(routes::backend_router().await) + .merge(routes::frontend_router().await); axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) .serve(app.into_make_service()) diff --git a/src/services.rs b/src/routes.rs similarity index 52% rename from src/services.rs rename to src/routes.rs index 1369541..dfbe5d6 100644 --- a/src/services.rs +++ b/src/routes.rs @@ -1,10 +1,10 @@ use crate::logic::*; use crate::user::User; -use crate::storage::DB_URI; +use crate::database::DB_URI; use axum::http::StatusCode; use axum::response::IntoResponse; -use axum::routing::{delete, get, post}; +use axum::routing::{delete, get, put, post}; use axum::Router; use axum_login::axum_sessions::async_session::MemoryStore; use axum_login::axum_sessions::{SameSite, SessionLayer}; @@ -23,40 +23,54 @@ pub async fn frontend_router() -> Router { } pub async fn backend_router() -> Router { - let secret = rand::thread_rng().gen::<[u8; 64]>(); + let secret = rand::thread_rng().gen::<[u8; 64]>(); // todo use secret from environment variable let session_store = MemoryStore::new(); let session_layer = SessionLayer::new(session_store, &secret) .with_secure(false) .with_same_site_policy(SameSite::Lax); - let pool = SqlitePoolOptions::new().connect(DB_URI).await.unwrap(); - let user_store = SqliteStore::::new(pool); let auth_layer = AuthLayer::new(user_store, &secret); - Router::new() - // account management routes + let auth_router = Router::new() + .route("/v1/auth/ping", get(ping)) + .route_layer(RequireAuthorizationLayer::::login()) + .route("/v1/auth/login", post(login)) + .route("/v1/auth/logout", put(logout)) + .layer(&auth_layer) + .layer(&session_layer); + + let account_router = Router::new() .route("/v1/account", get(get_account)) - .route("/v1/account/edit", post(edit_account)) + .route("/v1/account", post(new_account)) + .route("/v1/account", put(edit_account)) .route("/v1/account", delete(delete_account)) - // user - .route("/v1/user/id/:id", get(get_user_by_id)) - .route("/v1/user/:username", get(get_user)) - // activity routes - .route("/v1/activities/:id", get(get_activity)) - .route("/v1/activities/:from/:to", get(get_activities_from_to)) + .route("/v1/account/password", put(change_account_password)) + .route_layer(RequireAuthorizationLayer::::login()) + .layer(&auth_layer) + .layer(&session_layer); + + let users_router = Router::new() + .route("/v1/users/id/:id", get(get_user_by_id)) + .route("/v1/users/:username", get(get_user)) + .route_layer(RequireAuthorizationLayer::::login()) + .layer(&auth_layer) + .layer(&session_layer); + + let activities_router = Router::new() .route("/v1/activities", post(new_activity)) - .route("/v1/activities/edit", post(edit_activity)) + .route("/v1/activities/:id", get(get_activity)) + .route("/v1/activities/:id", put(edit_activity)) .route("/v1/activities/:id", delete(delete_activity)) - // for checking if you are logged in - .route("/v1/ping", get(ping)) - // routes above are protected + .route("/v1/activities/:from/:to", get(get_activities_from_to)) .route_layer(RequireAuthorizationLayer::::login()) - // authentication routes - .route("/v1/auth/sign_up", post(sign_up)) - .route("/v1/auth/sign_in", post(sign_in)) - .route("/v1/auth/sign_out", get(sign_out)) - .layer(auth_layer) - .layer(session_layer) + .layer(&auth_layer) + .layer(&session_layer); + + Router::new() + .merge(auth_router) + .merge(account_router) + .merge(users_router) + .merge(activities_router) }