diff --git a/Cargo.lock b/Cargo.lock index 6b45cd9..fa2f3f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-files" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0773d59061dedb49a8aed04c67291b9d8cf2fe0b60130a381aab53c6dd86e9be" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "bitflags 2.6.0", + "bytes", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "v_htmlescape", +] + [[package]] name = "actix-http" version = "3.8.0" @@ -30,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", + "base64 0.22.1", "bitflags 2.6.0", "brotli", "bytes", @@ -290,6 +313,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -478,12 +513,24 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bindgen" version = "0.69.4" @@ -516,6 +563,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block" version = "0.1.6" @@ -1052,6 +1108,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -1347,8 +1404,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1465,6 +1524,12 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + [[package]] name = "httparse" version = "1.9.4" @@ -1652,6 +1717,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1833,6 +1913,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2056,6 +2146,16 @@ dependencies = [ "zbus", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -2270,12 +2370,33 @@ dependencies = [ "regex", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2566,16 +2687,34 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "river-raid" version = "0.1.0" dependencies = [ + "actix-files", "actix-web", "alsa-sys", + "argon2", "cargo-watch", "chrono", "crossterm", "inline_colorization", + "jsonwebtoken", "ndarray", "rand", "rodio", @@ -2790,6 +2929,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -2847,6 +2998,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2878,6 +3035,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "symphonia" version = "0.5.4" @@ -3253,6 +3416,15 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -3280,6 +3452,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.2" @@ -3291,6 +3469,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "v_htmlescape" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 5016aa9..cece015 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,9 @@ actix-web = "4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tera = "1.12" +actix-files = "0.6.6" +argon2 = "0.5.3" +jsonwebtoken = "9.3.0" # [features] # serde = ["dep:serde"] \ No newline at end of file diff --git a/my_db/db b/my_db/db index 914abf6..9607770 100644 Binary files a/my_db/db and b/my_db/db differ diff --git a/my_db/snap.0000000000000090 b/my_db/snap.0000000000000090 deleted file mode 100644 index 78c95b2..0000000 Binary files a/my_db/snap.0000000000000090 and /dev/null differ diff --git a/my_db/snap.000000000000017C b/my_db/snap.000000000000017C new file mode 100644 index 0000000..ec1d5b4 Binary files /dev/null and b/my_db/snap.000000000000017C differ diff --git a/src/main.rs b/src/main.rs index b295cad..c979779 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,6 +121,7 @@ fn main2() -> Result<()> { +// todo this function should applied at a separate cargo #[actix_web::main] async fn main() -> Result<()>{ println!("Running web server..."); diff --git a/src/server.rs b/src/server.rs index 37c7e37..3e61d93 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,41 +1,128 @@ -use actix_web::{get, web, App, HttpRequest, Responder, HttpServer, HttpResponse}; +use actix_web::{get, post, web, App, HttpRequest, HttpResponse, HttpServer, Responder, ResponseError}; use sled::Db; +use actix_files as fs; use serde::{Serialize, Deserialize}; +use serde_json::{json}; use tera::{Tera, Context}; +use std::borrow::Borrow; use std::sync::Mutex; -// use shuttle_actix_web::ShuttleActixWeb; +use inline_colorization::*; + +extern crate argon2; +extern crate jsonwebtoken as jwt; +extern crate serde; +extern crate chrono; +extern crate serde_json; + +use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; +use argon2::password_hash::{SaltString, rand_core::OsRng}; +use jwt::{encode, Header, EncodingKey}; +use chrono::{Utc, Duration}; +use std::env; + + static WORKERS: u8 = 4; -#[derive(Serialize, Deserialize)] + +#[derive(Serialize, Deserialize, Debug)] struct Item { - name: String, - value: String, + username: String, + password: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Claims { + sub: String, + exp: usize, } +fn hash_password(password: &str) -> String { + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + let password_hash = argon2.hash_password(password.as_bytes(), &salt).unwrap(); + password_hash.to_string() +} + +fn verify_password(hash: &str, password: &str) -> bool { + let parsed_hash = PasswordHash::new(hash).unwrap(); + let argon2 = Argon2::default(); + argon2.verify_password(password.as_bytes(), &parsed_hash).is_ok() +} + +fn generate_jwt(username: &str) -> String { + let expiration = Utc::now() + .checked_add_signed(Duration::days(1)) + .expect("valid timestamp") + .timestamp(); + + let claims = Claims { + sub: username.to_owned(), + exp: expiration as usize, + }; + + let secret = env::var("JWT_SECRET").unwrap_or_else(|_| "secret".to_string()); + encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_ref())).unwrap() +} + + async fn add_item(db: web::Data>, item: web::Form) -> impl Responder { let db = db.lock().unwrap(); - let serialized = serde_json::to_vec(&item).unwrap(); - db.insert(item.name.as_bytes(), serialized).unwrap(); + let mut serialized = serde_json::to_vec(&item).unwrap(); + + let mut deserialized: serde_json::Value = serde_json::from_slice(&serialized).unwrap(); + let jwt_token = generate_jwt(&item.username); + + if let serde_json::Value::Object(ref mut map) = deserialized { + map.insert("password".to_string(), json!(hash_password(&item.password))); + map.insert("token".to_string(), json!(jwt_token)); + } + + serialized = serde_json::to_vec(&deserialized).unwrap(); + println!("{color_green}serialized version: {:?}{color_reset}\n", serialized); + println!("items: {:?}", item); + + db.insert(item.username.as_bytes(), serialized).unwrap(); HttpResponse::Ok().body("Item added") } +fn get_item(db: &Db, key: &str) -> sled::Result> { + if let Some(serialized) = db.get(key)? { + let item: Item = serde_json::from_slice(&serialized).unwrap(); + Ok(Some(item)) + } else { + Ok(None) + } +} + + +// todo: add this feature to the web. +async fn get_user(db: web::Data>) -> impl Responder { + HttpResponse::Ok().body("test") +} + +#[get("/signup")] async fn signup_form(tmpl: web::Data) -> impl Responder { let s = tmpl.render("signup.html", &Context::new()).unwrap(); HttpResponse::Ok().content_type("text/html").body(s) } #[get("/")] -async fn home_page(_req: HttpRequest) -> impl Responder { - "Welcome to the River Raid game" +async fn home_page(tmpl: web::Data) -> impl Responder { + let s = tmpl.render("home.html", &Context::new()).unwrap(); + HttpResponse::Ok().content_type("text/html").body(s) } + pub async fn run_server() -> std::io::Result<()> { let db_result = sled::open("my_db"); let db = match db_result { - Ok(db) => db, + Ok(db) => { + println!("user parsa is {:?}", Some(get_item(&db, "parsa"))); + db + } Err(e) => { eprintln!("Failed to open the database: {:?}", e); std::process::exit(1); @@ -49,8 +136,9 @@ pub async fn run_server() -> std::io::Result<()> { .app_data(web::Data::new(Mutex::new(db.clone()))) .app_data(web::Data::new(tera.clone())) .route("/add_item", web::post().to(add_item)) - .route("/signup", web::get().to(signup_form)) + .service(signup_form) .service(home_page) + // .service(get_user) }) .workers(WORKERS as usize) .bind("127.0.0.1:8081")? diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..11926a5 --- /dev/null +++ b/templates/home.html @@ -0,0 +1,60 @@ + + + + + + River Raid Home + + + +
+

Welcome to River Raid

+

Experience the classic arcade game in a new way. Navigate your jet through treacherous waters, avoid obstacles, and collect fuel to stay alive.

+ SignUp + +
+ + diff --git a/templates/signup.html b/templates/signup.html index 3922f23..5a8e563 100644 --- a/templates/signup.html +++ b/templates/signup.html @@ -1,16 +1,84 @@ - + - Signup + + + Sign Up + -

Signup

-
- -

- -

- -
+