From 3edf5d60f54bfd0cd2c818e5fb1ca133e324325d Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 30 Dec 2021 11:45:59 +0100 Subject: rename to planetwars-server --- planetwars-server/src/routes/bots.rs | 75 ++++++++++++++++++++++++++++ planetwars-server/src/routes/mod.rs | 2 + planetwars-server/src/routes/users.rs | 94 +++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 planetwars-server/src/routes/bots.rs create mode 100644 planetwars-server/src/routes/mod.rs create mode 100644 planetwars-server/src/routes/users.rs (limited to 'planetwars-server/src/routes') diff --git a/planetwars-server/src/routes/bots.rs b/planetwars-server/src/routes/bots.rs new file mode 100644 index 0000000..da09669 --- /dev/null +++ b/planetwars-server/src/routes/bots.rs @@ -0,0 +1,75 @@ +use axum::extract::{Path, RawBody}; +use axum::http::StatusCode; +use axum::Json; +use rand::Rng; +use serde::{Deserialize, Serialize}; +use std::io::Cursor; +use std::path; + +use crate::db::bots::{self, CodeBundle}; +use crate::db::users::User; +use crate::DatabaseConnection; +use bots::Bot; + +#[derive(Serialize, Deserialize, Debug)] +pub struct BotParams { + name: String, +} + +pub async fn create_bot( + conn: DatabaseConnection, + user: User, + params: Json, +) -> (StatusCode, Json) { + let bot_params = bots::NewBot { + owner_id: user.id, + name: ¶ms.name, + }; + let bot = bots::create_bot(&bot_params, &conn).unwrap(); + (StatusCode::CREATED, Json(bot)) +} + +// TODO: handle errors +pub async fn get_bot(conn: DatabaseConnection, Path(bot_id): Path) -> Json { + let bot = bots::find_bot(bot_id, &conn).unwrap(); + Json(bot) +} + +// TODO: proper error handling +pub async fn upload_bot_code( + conn: DatabaseConnection, + user: User, + Path(bot_id): Path, + RawBody(body): RawBody, +) -> (StatusCode, Json) { + // TODO: put in config somewhere + let data_path = "./data/bots"; + + let bot = bots::find_bot(bot_id, &conn).expect("Bot not found"); + + assert_eq!(user.id, bot.owner_id); + + // generate a random filename + let token: [u8; 16] = rand::thread_rng().gen(); + let name = base64::encode(&token); + + let path = path::Path::new(data_path).join(name); + // let capped_buf = data.open(10usize.megabytes()).into_bytes().await.unwrap(); + // assert!(capped_buf.is_complete()); + // let buf = capped_buf.into_inner(); + let buf = hyper::body::to_bytes(body).await.unwrap(); + + zip::ZipArchive::new(Cursor::new(buf)) + .unwrap() + .extract(&path) + .unwrap(); + + let bundle = bots::NewCodeBundle { + bot_id: bot.id, + path: path.to_str().unwrap(), + }; + let code_bundle = + bots::create_code_bundle(&bundle, &conn).expect("Failed to create code bundle"); + + (StatusCode::CREATED, Json(code_bundle)) +} diff --git a/planetwars-server/src/routes/mod.rs b/planetwars-server/src/routes/mod.rs new file mode 100644 index 0000000..718d7ef --- /dev/null +++ b/planetwars-server/src/routes/mod.rs @@ -0,0 +1,2 @@ +pub mod bots; +pub mod users; diff --git a/planetwars-server/src/routes/users.rs b/planetwars-server/src/routes/users.rs new file mode 100644 index 0000000..fc77d7b --- /dev/null +++ b/planetwars-server/src/routes/users.rs @@ -0,0 +1,94 @@ +use crate::db::users::{Credentials, User}; +use crate::db::{sessions, users}; +use crate::DatabaseConnection; +use axum::extract::{FromRequest, RequestParts, TypedHeader}; +use axum::headers::authorization::Bearer; +use axum::headers::Authorization; +use axum::http::StatusCode; +use axum::{async_trait, Json}; +use serde::{Deserialize, Serialize}; + +type AuthorizationHeader = TypedHeader>; + +#[async_trait] +impl FromRequest for User +where + B: Send, +{ + type Rejection = (StatusCode, String); + + async fn from_request(req: &mut RequestParts) -> Result { + let conn = DatabaseConnection::from_request(req).await?; + let TypedHeader(Authorization(bearer)) = AuthorizationHeader::from_request(req) + .await + .map_err(|_| (StatusCode::UNAUTHORIZED, "".to_string()))?; + + let (_session, user) = sessions::find_user_by_session(bearer.token(), &conn) + .map_err(|_| (StatusCode::UNAUTHORIZED, "".to_string()))?; + + Ok(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.id, + username: user.username, + } + } +} + +#[derive(Deserialize)] +pub struct RegistrationParams { + pub username: String, + pub password: String, +} + +pub async fn register( + conn: DatabaseConnection, + params: Json, +) -> Json { + let credentials = Credentials { + username: ¶ms.username, + password: ¶ms.password, + }; + let user = users::create_user(&credentials, &conn).unwrap(); + Json(user.into()) +} + +#[derive(Deserialize)] +pub struct LoginParams { + pub username: String, + pub password: String, +} + +pub async fn login( + conn: DatabaseConnection, + params: Json, +) -> Result { + let credentials = Credentials { + username: ¶ms.username, + password: ¶ms.password, + }; + // TODO: handle failures + let authenticated = users::authenticate_user(&credentials, &conn); + + match authenticated { + None => Err(StatusCode::FORBIDDEN), + Some(user) => { + let session = sessions::create_session(&user, &conn); + Ok(session.token) + } + } +} + +pub async fn current_user(user: User) -> Json { + Json(user.into()) +} -- cgit v1.2.3