diff options
Diffstat (limited to 'crates/rocie-server/src/api/set/no_auth')
| -rw-r--r-- | crates/rocie-server/src/api/set/no_auth/mod.rs | 7 | ||||
| -rw-r--r-- | crates/rocie-server/src/api/set/no_auth/user.rs | 131 |
2 files changed, 138 insertions, 0 deletions
diff --git a/crates/rocie-server/src/api/set/no_auth/mod.rs b/crates/rocie-server/src/api/set/no_auth/mod.rs new file mode 100644 index 0000000..27783fc --- /dev/null +++ b/crates/rocie-server/src/api/set/no_auth/mod.rs @@ -0,0 +1,7 @@ +use actix_web::web; + +pub(crate) mod user; + +pub(crate) fn register_paths(cfg: &mut web::ServiceConfig) { + cfg.service(user::login).service(user::logout).service(user::provision); +} diff --git a/crates/rocie-server/src/api/set/no_auth/user.rs b/crates/rocie-server/src/api/set/no_auth/user.rs new file mode 100644 index 0000000..7acb482 --- /dev/null +++ b/crates/rocie-server/src/api/set/no_auth/user.rs @@ -0,0 +1,131 @@ +use actix_identity::Identity; +use actix_web::{HttpMessage, HttpRequest, HttpResponse, Responder, Result, post, web}; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +use crate::{ + api::set::auth::user::UserStub, + app::App, + storage::sql::{ + insert::Operations, + user::{PasswordHash, User, UserId}, + }, +}; + +#[derive(ToSchema, Deserialize, Serialize)] +struct LoginInfo { + /// The id of the user. + id: UserId, + + /// The password of the user. + password: String, +} + +/// Log in as a specific user +#[utoipa::path( + responses( + ( + status = OK, + description = "User logged in", + ), + ( + status = NOT_FOUND, + description = "User id not found" + ), + ( + status = FORBIDDEN, + description = "Password did not match" + ), + ( + status = INTERNAL_SERVER_ERROR, + description = "Server encountered error", + body = String + ) + ), + request_body = LoginInfo, +)] +#[post("/login")] +async fn login( + request: HttpRequest, + app: web::Data<App>, + info: web::Json<LoginInfo>, +) -> Result<impl Responder> { + let info = info.into_inner(); + + if let Some(user) = User::from_id(&app, info.id).await? { + if user.password_hash.verify(&info.password) { + Identity::login(&request.extensions(), info.id.to_string())?; + Ok(HttpResponse::Ok().finish()) + } else { + Ok(HttpResponse::Forbidden().finish()) + } + } else { + Ok(HttpResponse::NotFound().finish()) + } +} + +/// Log the current user out +#[utoipa::path( + responses( + ( + status = OK, + description = "User logged out", + ), + ( + status = INTERNAL_SERVER_ERROR, + description = "Server encountered error", + body = String + ) + ), +)] +#[post("/logout")] +async fn logout(user: Identity) -> impl Responder { + user.logout(); + HttpResponse::Ok() +} + +/// Provision this instance. +/// +/// This only works, if no users exist yet. +#[utoipa::path( + responses( + ( + status = OK, + description = "User created and logged in", + body = UserId, + ), + ( + status = FORBIDDEN, + description = "Instance already provisioned", + ), + ( + status = INTERNAL_SERVER_ERROR, + description = "Server encountered error", + body = String + ) + ), + request_body = UserStub, +)] +#[post("/provision")] +async fn provision( + request: HttpRequest, + app: web::Data<App>, + new_user: web::Json<UserStub>, +) -> Result<impl Responder> { + if User::get_all(&app).await?.is_empty() { + let user = new_user.into_inner(); + + let mut ops = Operations::new("register user (during provisioning)"); + + let password_hash = PasswordHash::from_password(&user.password); + let user = User::register(user.name, password_hash, user.description, &mut ops); + + ops.apply(&app).await?; + + Identity::login(&request.extensions(), user.id.to_string())?; + + Ok(HttpResponse::Ok().json(user.id)) + } else { + Ok(HttpResponse::Forbidden().finish()) + } +} |
