about summary refs log tree commit diff stats
path: root/crates/rocie-server/src/api/set/no_auth
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rocie-server/src/api/set/no_auth')
-rw-r--r--crates/rocie-server/src/api/set/no_auth/mod.rs7
-rw-r--r--crates/rocie-server/src/api/set/no_auth/user.rs131
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())
+    }
+}