diff --git a/Cargo.lock b/Cargo.lock index 823efb9..f650787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,41 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.7" @@ -208,6 +243,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -220,7 +265,13 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" dependencies = [ + "aes-gcm", + "base64", + "hkdf", "percent-encoding", + "rand", + "sha2", + "subtle", "time", "version_check", ] @@ -271,9 +322,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "der" version = "0.7.8" @@ -580,6 +641,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.1" @@ -763,6 +834,15 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "is-terminal" version = "0.4.10" @@ -1068,6 +1148,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "overload" version = "0.1.1" @@ -1180,6 +1266,18 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +[[package]] +name = "polyval" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2291,6 +2389,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 2a82e41..adfc138 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] maud = { version = "0.26.0", features = ["rocket"] } -rocket = "0.5.0" +rocket = {version = "0.5.0", features = ["secrets"] } serde = "1.0.196" sqlx = { version = "0.7.3", features = ["postgres"] } diff --git a/src/auth/mod.rs b/src/auth/mod.rs index c41a5ba..3629e48 100644 --- a/src/auth/mod.rs +++ b/src/auth/mod.rs @@ -20,11 +20,16 @@ impl<'r> FromRequest<'r> for User { // get the session id from the cookie let session_opt = req.cookies().get("rocket_session_id"); - let session_id = match session_opt { + let session_id_str = match session_opt { Some(s) => s.value(), None => return Outcome::Error((Status::Unauthorized, ())), }; + let session_id = match session_id_str.parse::() { + Ok(s) => s, + Err(_) => return Outcome::Error((Status::Unauthorized, ())), + }; + let sessions_outcome = req.guard::<&State>().await; let sessions = match sessions_outcome { Outcome::Success(s) => s, diff --git a/src/auth/session.rs b/src/auth/session.rs index f539f41..e81a98e 100644 --- a/src/auth/session.rs +++ b/src/auth/session.rs @@ -1,24 +1,34 @@ use serde::{Deserialize, Serialize}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{collections::HashMap, sync::Mutex}; pub struct Sessions { - sessions: Mutex>, + sessions: Mutex>, + next_id: AtomicUsize, } impl Sessions { pub fn new() -> Self { Sessions { sessions: Mutex::new(HashMap::new()), + next_id: AtomicUsize::new(0), } } - pub fn insert(&self, session_id: String, session_data: SessionData) { + /// Insert a new session into the map and return its id. + /// This id can be used to retrieve the session later. + /// It is meant to be encrypted and sent to the client as a cookie. + pub fn insert(&self, session_data: SessionData) -> usize { + let next_session_id = self.next_id.fetch_add(1, Ordering::Relaxed); + let mut map = self.sessions.lock().unwrap(); - map.insert(session_id, session_data); + map.insert(next_session_id, session_data); + + next_session_id } - pub fn get(&self, session_id: &str) -> Option { + pub fn get(&self, session_id: usize) -> Option { let mut map = self.sessions.lock().unwrap(); // Remove expired sessions @@ -29,7 +39,7 @@ impl Sessions { .expect("Time went backwards") .as_secs(); - let keys = map.keys().cloned().collect::>(); + let keys = map.keys().cloned().collect::>(); for key in keys { if map.get(&key).unwrap().expires_at < current_time { @@ -38,7 +48,7 @@ impl Sessions { } // Get the session & extend its duration - let new_session = match map.get(session_id) { + let new_session = match map.get(&session_id) { Some(s) => s.extend_duration(current_time), None => return None, }; @@ -46,7 +56,7 @@ impl Sessions { let returned_session = new_session.clone(); // Update the session in the map - map.insert(session_id.to_string(), new_session); + map.insert(session_id, new_session); Some(returned_session) } diff --git a/src/controller/login.rs b/src/controller/login.rs index de46ef7..a824657 100644 --- a/src/controller/login.rs +++ b/src/controller/login.rs @@ -1,5 +1,9 @@ use maud::Markup; -use rocket::{form::Form, http::Status, State}; +use rocket::{ + form::Form, + http::{CookieJar, Status}, + State, +}; use crate::auth::session::{SessionData, Sessions}; @@ -10,8 +14,9 @@ pub struct LoginData { } #[get("/login")] -pub fn login(sessions: &State) -> &'static str { - sessions.insert("123456".into(), SessionData::new(1)); +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())); ":D" } diff --git a/src/controller/mod.rs b/src/controller/mod.rs index 1bf2123..60a7a21 100644 --- a/src/controller/mod.rs +++ b/src/controller/mod.rs @@ -1,10 +1,13 @@ use maud::Markup; +use rocket::http::CookieJar; pub mod login; pub mod register; pub mod user; #[get("/")] -pub fn index() -> Markup { +pub fn index(cookies: &CookieJar<'_>) -> Markup { + cookies.add_private(("rocket_session_id", "123456")); + crate::view::login::login() }