From da4019ec6167d1ebe12a0c620165458f834f1ed5 Mon Sep 17 00:00:00 2001 From: fernando Date: Thu, 15 Feb 2024 11:47:51 -0500 Subject: [PATCH] Proof of concept for login --- Cargo.lock | 171 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- Rocket.toml | 2 + sql/schema.sql | 8 +- src/controller/login.rs | 57 +++++++++++--- src/main.rs | 7 ++ src/model/mod.rs | 2 +- src/model/user.rs | 28 +++++++ 8 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 Rocket.toml create mode 100644 src/model/user.rs diff --git a/Cargo.lock b/Cargo.lock index f650787..c7e50b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,33 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[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 = "async-stream" version = "0.3.5" @@ -201,6 +228,15 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -210,6 +246,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "bytemuck" version = "1.14.2" @@ -243,6 +285,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.0", +] + [[package]] name = "cipher" version = "0.4.4" @@ -276,6 +330,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -410,6 +470,7 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" name = "eeg_internal" version = "0.1.0" dependencies = [ + "argon2", "maud", "rocket", "rocket_db_pools", @@ -807,6 +868,29 @@ dependencies = [ "want", ] +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.5.0" @@ -869,6 +953,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1183,6 +1276,17 @@ dependencies = [ "windows-targets 0.48.5", ] +[[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.14" @@ -1841,6 +1945,7 @@ dependencies = [ "atoi", "byteorder", "bytes", + "chrono", "crc", "crossbeam-queue", "dotenvy", @@ -1925,6 +2030,7 @@ dependencies = [ "bitflags 2.4.2", "byteorder", "bytes", + "chrono", "crc", "digest", "dotenvy", @@ -1966,6 +2072,7 @@ dependencies = [ "base64", "bitflags 2.4.2", "byteorder", + "chrono", "crc", "dotenvy", "etcetera", @@ -2002,6 +2109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" dependencies = [ "atoi", + "chrono", "flume", "futures-channel", "futures-core", @@ -2455,6 +2563,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + [[package]] name = "webpki-roots" version = "0.25.4" @@ -2498,6 +2660,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index adfc138..6c6d779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,14 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +argon2 = "0.5.3" maud = { version = "0.26.0", features = ["rocket"] } rocket = {version = "0.5.0", features = ["secrets"] } serde = "1.0.196" -sqlx = { version = "0.7.3", features = ["postgres"] } +sqlx = { version = "0.7.3", features = ["mysql", "macros", "chrono"] } [dependencies.rocket_db_pools] version = "0.1.0" features = ["sqlx_mysql"] -[default.databases.main] -url = "mysql://root:password@localhost:3306/eeg-administrative" diff --git a/Rocket.toml b/Rocket.toml new file mode 100644 index 0000000..a95f043 --- /dev/null +++ b/Rocket.toml @@ -0,0 +1,2 @@ +[default.databases.main] +url = "mysql://root:123456789@localhost:33306/eegsac_manager" diff --git a/sql/schema.sql b/sql/schema.sql index c97a7b8..2538c4c 100644 --- a/sql/schema.sql +++ b/sql/schema.sql @@ -9,10 +9,12 @@ CREATE TABLE user ( user_names VARCHAR(50) NOT NULL, user_surnames VARCHAR(50) NOT NULL, - user_creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - user_last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + user_creation DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + user_last_login DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); - +-- This is the hash & salt for a password "123456789" +-- $argon2id$v=19$m=65536,t=4,p=1$TE1wdklnMEpsMDAveWhzYw$nsKg2fALcXZ8AquM7jPGBUjM3Dyg5tgbDATKMeKPtfQ +-- insert into user (user_email, user_password, user_names, user_surnames) values ('fernando@eegsac.com', '$argon2id$v=19$m=65536,t=4,p=1$TE1wdklnMEpsMDAveWhzYw$nsKg2fALcXZ8AquM7jPGBUjM3Dyg5tgbDATKMeKPtfQ', 'Fernando', 'Araoz'); \ No newline at end of file diff --git a/src/controller/login.rs b/src/controller/login.rs index a824657..47743af 100644 --- a/src/controller/login.rs +++ b/src/controller/login.rs @@ -1,11 +1,17 @@ use maud::Markup; -use rocket::{ - form::Form, - http::{CookieJar, Status}, - State, +use rocket::{form::Form, http::CookieJar, State}; +use rocket_db_pools::Connection; + +use argon2::{ + password_hash::{PasswordHash, PasswordVerifier}, + Argon2, }; -use crate::auth::session::{SessionData, Sessions}; +use crate::{ + auth::session::{SessionData, Sessions}, + model::user::User, + DefaultDB, +}; #[derive(FromForm)] pub struct LoginData { @@ -14,9 +20,42 @@ pub struct LoginData { } #[get("/login")] -pub fn login(sessions: &State, cookies: &CookieJar<'_>) -> &'static str { - let session_id = sessions.insert(SessionData::new(1)); - cookies.add_private(("rocket_session_id", session_id.to_string())); +pub async fn login( + sessions: &State, + cookies: &CookieJar<'_>, + mut db: Connection, +) -> String { + // This data should come from a post request + let login_data = LoginData { + email: "fernando@eegsac.com".into(), + password: "123456789".into(), + }; - ":D" + // Get person from db + let person_result = User::get_by_email(&mut **db, &login_data.email).await; + let person = match person_result { + Ok(p) => p, + Err(reason) => return reason, + }; + + // Validate password + let parsed_hash = match PasswordHash::new(&person.user_password) { + Ok(h) => h, + Err(err) => { + println!("Error al parsear el hash: {:?}", err); + return format!("Error al parsear el hash: {:?}", err); + } + }; + + let password_correct = Argon2::default() + .verify_password(login_data.password.as_bytes(), &parsed_hash) + .is_ok(); + + if password_correct { + let session_id = sessions.insert(SessionData::new(person.user_id)); + cookies.add_private(("rocket_session_id", session_id.to_string())); + ":D".into() + } else { + "ContraseƱa incorrecta".into() + } } diff --git a/src/main.rs b/src/main.rs index b287062..88820ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,15 +4,22 @@ mod auth; mod controller; mod model; mod view; +use rocket_db_pools::Database; #[macro_use] extern crate rocket; +/// The default database pool. +#[derive(Database)] +#[database("main")] +pub struct DefaultDB(sqlx::MySqlPool); + #[launch] fn rocket() -> _ { rocket::build() .manage(auth::session::Sessions::new()) .register("/", catchers![view::not_authorized]) + .attach(DefaultDB::init()) .mount("/", routes![controller::index,]) .mount( "/f", diff --git a/src/model/mod.rs b/src/model/mod.rs index 8b13789..22d12a3 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1 +1 @@ - +pub mod user; diff --git a/src/model/user.rs b/src/model/user.rs new file mode 100644 index 0000000..368bf7c --- /dev/null +++ b/src/model/user.rs @@ -0,0 +1,28 @@ +use sqlx::{types::chrono::NaiveDateTime, MySqlConnection}; + +pub struct User { + pub user_id: i32, + pub user_email: String, + pub user_password: String, + pub user_names: String, + pub user_surnames: String, + pub user_creation: NaiveDateTime, + pub user_last_login: NaiveDateTime, +} + +impl User { + pub async fn get_by_email(db: &mut MySqlConnection, email: &str) -> Result { + let result = sqlx::query_as!(User, "SELECT * FROM user where user_email = ?", email) + .fetch_one(db) + .await; + + match result { + Ok(user) => Ok(user), + Err(sqlx::Error::RowNotFound) => Err("Usuario no encontrado".into()), + Err(err) => { + eprintln!("Error: {:?}", err); + Err("Error al buscar el usuario".into()) + } + } + } +}