diff options
author | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-13 22:41:20 +0100 |
---|---|---|
committer | Ilion Beyst <ilion.beyst@gmail.com> | 2021-12-13 22:41:20 +0100 |
commit | eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda (patch) | |
tree | 9cd2f38290fa059020feb049d8a2e2e91adac68b /backend/src/routes | |
parent | 8b4440f7236b0972c1a804eea4c8305b958ad03c (diff) | |
download | planetwars.dev-eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda.tar.xz planetwars.dev-eabeb7ed7b641dea0b8e71ab33ab97b4ed7a4cda.zip |
start implementing basic login functionality
Diffstat (limited to 'backend/src/routes')
-rw-r--r-- | backend/src/routes/mod.rs | 1 | ||||
-rw-r--r-- | backend/src/routes/users.rs | 100 |
2 files changed, 101 insertions, 0 deletions
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<Self, Self::Error> { + 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::<DbConn>().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<User> 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 = "<params>")] +pub async fn register(db_conn: DbConn, params: Json<RegistrationParams>) -> Json<UserData> { + 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 = "<params>")] +pub async fn login(db_conn: DbConn, params: Json<LoginParams>) -> 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<UserData> { + Json(user.into()) +} |