From eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Mon, 13 Dec 2021 22:41:20 +0100 Subject: start implementing basic login functionality --- backend/src/routes/mod.rs | 1 + backend/src/routes/users.rs | 100 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 backend/src/routes/mod.rs create mode 100644 backend/src/routes/users.rs (limited to 'backend/src/routes') diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs new file mode 100644 index 0000000..913bd46 --- /dev/null +++ b/backend/src/routes/mod.rs @@ -0,0 +1 @@ +pub mod users; diff --git a/backend/src/routes/users.rs b/backend/src/routes/users.rs new file mode 100644 index 0000000..274b712 --- /dev/null +++ b/backend/src/routes/users.rs @@ -0,0 +1,100 @@ +use crate::db::{sessions, users}; +use crate::{ + db::users::{Credentials, User}, + DbConn, +}; +use rocket::serde::json::Json; +use serde::{Deserialize, Serialize}; + +use rocket::http::Status; +use rocket::request::{self, FromRequest, Outcome, Request}; + +#[derive(Debug)] +pub enum AuthTokenError { + BadCount, + Missing, + Invalid, +} + +// TODO: error handling and proper lifetimes +#[rocket::async_trait] +impl<'r> FromRequest<'r> for User { + type Error = AuthTokenError; + + async fn from_request(request: &'r Request<'_>) -> Outcome { + let keys: Vec<_> = request.headers().get("Authorization").collect(); + let token = match keys.len() { + 0 => return Outcome::Failure((Status::BadRequest, AuthTokenError::Missing)), + 1 => keys[0].to_string(), + _ => return Outcome::Failure((Status::BadRequest, AuthTokenError::BadCount)), + }; + let db = request.guard::().await.unwrap(); + let (_session, user) = db + .run(move |conn| sessions::find_user_by_session(&token, conn)) + .await + .unwrap(); + Outcome::Success(user) + } +} + +#[derive(Serialize, Deserialize)] +pub struct UserData { + pub user_id: i32, + pub username: String, +} + +impl From for UserData { + fn from(user: User) -> Self { + UserData { + user_id: user.user_id, + username: user.username, + } + } +} + +#[derive(Deserialize)] +pub struct RegistrationParams { + pub username: String, + pub password: String, +} + +#[post("/register", data = "")] +pub async fn register(db_conn: DbConn, params: Json) -> Json { + db_conn + .run(move |conn| { + let credentials = Credentials { + username: ¶ms.username, + password: ¶ms.password, + }; + let user = users::create_user(&credentials, conn).unwrap(); + Json(user.into()) + }) + .await +} + +#[derive(Deserialize)] +pub struct LoginParams { + pub username: String, + pub password: String, +} + +#[post("/login", data = "")] +pub async fn login(db_conn: DbConn, params: Json) -> String { + db_conn + .run(move |conn| { + let credentials = Credentials { + username: ¶ms.username, + password: ¶ms.password, + }; + // TODO: handle failures + let user = users::authenticate_user(&credentials, conn).unwrap(); + let session = sessions::create_session(&user, conn); + return session.token; + }) + .await +} + +#[get("/users/me")] +pub async fn current_user(user: User) -> Json { + Json(user.into()) +} -- cgit v1.2.3