diff --git a/backend-actix/Cargo.lock b/backend-actix/Cargo.lock index 1795f47..aed21e9 100644 --- a/backend-actix/Cargo.lock +++ b/backend-actix/Cargo.lock @@ -393,6 +393,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", + "serde", "time 0.1.45", "wasm-bindgen", "winapi", @@ -433,9 +434,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] @@ -483,7 +484,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -500,7 +501,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -524,6 +525,7 @@ checksum = "4391a22b19c916e50bec4d6140f29bdda3e3bb187223fe6e3ea0b6e4d1021c04" dependencies = [ "bitflags", "byteorder", + "chrono", "diesel_derives", "itoa", "pq-sys", @@ -767,9 +769,9 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -1144,9 +1146,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -1233,7 +1235,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -1341,9 +1343,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.9" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" dependencies = [ "proc-macro2", "quote", @@ -1376,7 +1378,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] diff --git a/backend-actix/Cargo.toml b/backend-actix/Cargo.toml index 148ad61..1a59584 100644 --- a/backend-actix/Cargo.toml +++ b/backend-actix/Cargo.toml @@ -10,9 +10,9 @@ actix-web = "4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.3.0", features = ["serde", "v4"] } -diesel = { version = "2.0", features = ["postgres", "r2d2", "uuid"] } +diesel = { version = "2.0", features = ["postgres", "r2d2", "uuid", "chrono"] } diesel-derive-enum = { version = "2.0", features = ["postgres"] } argon2 = "0.5" -chrono = "0.4" +chrono = { version = "0.4", features = ["serde"] } jsonwebtoken = "8.1" validator = { version = "0.16", features = ["derive"] } \ No newline at end of file diff --git a/backend-actix/src/main.rs b/backend-actix/src/main.rs index 15496bb..e9ffb40 100644 --- a/backend-actix/src/main.rs +++ b/backend-actix/src/main.rs @@ -5,7 +5,7 @@ use actix_web::HttpServer; use actix_web::App; use actix_web::web; use diesel::PgConnection; -use request::{login, register}; +use request::{login, register, gamenights}; use diesel::r2d2::ConnectionManager; use diesel::r2d2::Pool; @@ -28,6 +28,7 @@ async fn main() -> std::io::Result<()> { .app_data(web::Data::new(pool.clone())) .service(login) .service(register) + .service(gamenights) }) .bind(("::1", 8080))? .run() diff --git a/backend-actix/src/request/authorization.rs b/backend-actix/src/request/authorization.rs new file mode 100644 index 0000000..9de36d3 --- /dev/null +++ b/backend-actix/src/request/authorization.rs @@ -0,0 +1,65 @@ +use std::future::{Ready, ready}; + +use actix_web::{FromRequest, http, HttpRequest, dev::Payload, web::Data}; +use chrono::Utc; +use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation}; +use serde::{Serialize, Deserialize}; +use uuid::Uuid; + +use crate::{schema::user::{User, get_user}, DbPool}; + +use super::error::ApiError; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + exp: i64, + uid: Uuid +} + +fn get_claims(req: &HttpRequest) -> Result { + let token = req.headers() + .get(http::header::AUTHORIZATION) + .map(|h| h.to_str().unwrap().split_at(7).1.to_string()); + + let token = token.ok_or(ApiError{ + status: 400, + message: "JWT-token was not specified in the Authorization header as Bearer: token".to_string() + })?; + + println!("{:?}", token); + + let secret = "secret"; + Ok(decode::(token.as_str(), &DecodingKey::from_secret(secret.as_bytes()), &Validation::default())?.claims) +} + +pub fn get_token(user: &User) -> Result { + let claims = Claims { + exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), + uid: user.id, + }; + + println!("{:?}", claims); + + let secret = "secret"; + Ok(encode( + &Header::default(), + &claims, + &EncodingKey::from_secret(secret.as_bytes()))?) +} + +impl FromRequest for User { + type Error = ApiError; + type Future = Ready>; + + fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { + ready( + (|| -> Result{ + let pool = req.app_data::>().expect("No database configured"); + let mut conn = pool.get().expect("couldn't get db connection from pool"); + let uid = get_claims(req)?.uid; + + Ok(get_user(&mut conn, uid)?) + })() + ) + } +} \ No newline at end of file diff --git a/backend-actix/src/request/gamenight_handlers.rs b/backend-actix/src/request/gamenight_handlers.rs new file mode 100644 index 0000000..4cc923a --- /dev/null +++ b/backend-actix/src/request/gamenight_handlers.rs @@ -0,0 +1,14 @@ +use actix_web::{get, web, Responder, http::header::ContentType, HttpResponse}; + +use crate::{DbPool, request::{error::ApiError, responses::GameNightResponse}, schema::{self, user::User}}; + +#[get("/gamenights")] +pub async fn gamenights(pool: web::Data, _user: User) -> Result { + let mut conn = pool.get().expect("couldn't get db connection from pool"); + let gamenights = schema::gamenights(&mut conn)?; + + Ok(HttpResponse::Ok() + .content_type(ContentType::json()) + .body(serde_json::to_string(&GameNightResponse { gamenights })?) + ) +} \ No newline at end of file diff --git a/backend-actix/src/request/mod.rs b/backend-actix/src/request/mod.rs index 4115649..a29ade6 100644 --- a/backend-actix/src/request/mod.rs +++ b/backend-actix/src/request/mod.rs @@ -1,8 +1,11 @@ mod requests; mod responses; -mod handler; +mod user_handlers; +mod gamenight_handlers; mod error; +mod authorization; -pub use handler::login; -pub use handler::register; \ No newline at end of file +pub use user_handlers::login; +pub use user_handlers::register; +pub use gamenight_handlers::gamenights; \ No newline at end of file diff --git a/backend-actix/src/request/responses.rs b/backend-actix/src/request/responses.rs index 710f468..077249e 100644 --- a/backend-actix/src/request/responses.rs +++ b/backend-actix/src/request/responses.rs @@ -1,6 +1,8 @@ use serde::{Serialize, Deserialize}; use uuid::Uuid; +use crate::schema::gamenight::Gamenight; + #[derive(Serialize, Deserialize)] pub struct LoginResponse { pub login_result: bool, @@ -27,4 +29,9 @@ impl LoginResponse { jwt_token: None } } +} + +#[derive(Serialize, Deserialize)] +pub struct GameNightResponse { + pub gamenights: Vec:: } \ No newline at end of file diff --git a/backend-actix/src/request/handler.rs b/backend-actix/src/request/user_handlers.rs similarity index 75% rename from backend-actix/src/request/handler.rs rename to backend-actix/src/request/user_handlers.rs index a088bf2..faede52 100644 --- a/backend-actix/src/request/handler.rs +++ b/backend-actix/src/request/user_handlers.rs @@ -1,18 +1,14 @@ use actix_web::http::header::ContentType; -use actix_web::{web, post, HttpResponse, Responder}; -use chrono::Utc; -use serde::{Serialize, Deserialize}; -use uuid::Uuid; +use actix_web::{web, post, HttpResponse, Responder, get}; use validator::ValidateArgs; use crate::DbPool; use crate::request::requests::{Login, Register}; use crate::request::error::ApiError; use crate::request::responses::LoginResponse; -use crate::schema::user::Role; +use crate::request::authorization::get_token; use crate::schema::{self}; use serde_json; -use jsonwebtoken::{encode, EncodingKey, Header}; impl Into for Login { fn into(self) -> schema::user::LoginUser { @@ -33,14 +29,9 @@ impl Into for Register { } } -#[derive(Debug, Serialize, Deserialize)] -struct Claims { - exp: i64, - uid: Uuid, - role: Role, -} -#[post("/login")] + +#[get("/token")] pub async fn login(pool: web::Data, login_data: web::Json) -> Result { let data = login_data.into_inner(); @@ -50,18 +41,7 @@ pub async fn login(pool: web::Data, login_data: web::Json) -> Res }) .await?? { - let my_claims = Claims { - exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), - uid: user.id, - role: user.role, - }; - - let secret = "secret"; - let token = encode( - &Header::default(), - &my_claims, - &EncodingKey::from_secret(secret.as_bytes()))?; - + let token = get_token(&user)?; LoginResponse::success(user.id, token) } else { @@ -74,7 +54,7 @@ pub async fn login(pool: web::Data, login_data: web::Json) -> Res ) } -#[post("/register")] +#[post("/user")] pub async fn register(pool: web::Data, register_data: web::Json) -> Result { let data1 = register_data.clone(); let data2 = register_data.clone(); diff --git a/backend-actix/src/schema/gamenight.rs b/backend-actix/src/schema/gamenight.rs new file mode 100644 index 0000000..ffb4b1f --- /dev/null +++ b/backend-actix/src/schema/gamenight.rs @@ -0,0 +1,20 @@ +use chrono::{DateTime, Utc}; +use diesel::{Insertable, Queryable, PgConnection, RunQueryDsl}; +use serde::{Serialize, Deserialize}; +use uuid::Uuid; +use crate::schema::schema::gamenight; + +use super::error::DatabaseError; + +#[derive(Serialize, Deserialize, Debug, Insertable, Queryable)] +#[diesel(table_name = gamenight)] +pub struct Gamenight { + pub id: Uuid, + pub name: String, + pub datetime: DateTime, + pub owner_id: Uuid, +} + +pub fn gamenights(conn: &mut PgConnection, ) -> Result, DatabaseError> { + Ok(gamenight::table.load::(conn)?) +} \ No newline at end of file diff --git a/backend-actix/src/schema/mod.rs b/backend-actix/src/schema/mod.rs index 55c1a8c..3d69c12 100644 --- a/backend-actix/src/schema/mod.rs +++ b/backend-actix/src/schema/mod.rs @@ -1,6 +1,8 @@ pub mod user; pub mod error; pub mod schema; +pub mod gamenight; pub use user::login; pub use user::register; +pub use gamenight::gamenights; diff --git a/backend-actix/src/schema/user.rs b/backend-actix/src/schema/user.rs index ed7c32b..c015ed3 100644 --- a/backend-actix/src/schema/user.rs +++ b/backend-actix/src/schema/user.rs @@ -85,6 +85,10 @@ pub fn login(conn: &mut PgConnection, user: LoginUser) -> Result, D } } +pub fn get_user(conn: &mut PgConnection, id: Uuid) -> Result { + Ok(users::table.find(id).first(conn)?) +} + pub fn unique_username(username: &String, conn: &mut PgConnection) -> Result<(), ValidationError> { match users::table .count()