diff --git a/Cargo.lock b/Cargo.lock index e4abab3..823efb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,6 +351,7 @@ version = "0.1.0" dependencies = [ "maud", "rocket", + "rocket_db_pools", "serde", "sqlx", ] @@ -1348,6 +1349,20 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rocket" version = "0.5.0" @@ -1402,6 +1417,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "rocket_db_pools" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ebde3e24cbe917062b862136fd532d1ace80e0377a2f5fed541fadd764f1e5" +dependencies = [ + "rocket", + "rocket_db_pools_codegen", + "sqlx", + "version_check", +] + +[[package]] +name = "rocket_db_pools_codegen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "184a6f59eed0bf3d1cccb091960a2a1c89efa829b8a41158b269985a9c1bee95" +dependencies = [ + "devise", + "quote", +] + [[package]] name = "rocket_http" version = "0.5.0" @@ -1468,6 +1505,36 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1492,6 +1559,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "serde" version = "1.0.196" @@ -1684,14 +1761,19 @@ dependencies = [ "once_cell", "paste", "percent-encoding", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", "smallvec", "sqlformat", "thiserror", + "tokio", + "tokio-stream", "tracing", "url", + "webpki-roots", ] [[package]] @@ -1730,6 +1812,7 @@ dependencies = [ "sqlx-sqlite", "syn 1.0.109", "tempfile", + "tokio", "url", ] @@ -2208,6 +2291,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[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.0" @@ -2258,6 +2347,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "whoami" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index 19b0bee..2a82e41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,10 @@ maud = { version = "0.26.0", features = ["rocket"] } rocket = "0.5.0" serde = "1.0.196" sqlx = { version = "0.7.3", features = ["postgres"] } + +[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/src/auth/mod.rs b/src/auth/mod.rs new file mode 100644 index 0000000..95c2152 --- /dev/null +++ b/src/auth/mod.rs @@ -0,0 +1,40 @@ +use rocket::response::Redirect; +use rocket::State; +use rocket::{ + http::Status, + request::{FromRequest, Outcome, Request}, +}; + +pub mod session; + +use session::SessionData; +use session::Sessions; + +#[derive(Debug, Clone)] +pub struct User(SessionData); + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for User { + type Error = (); + + async fn from_request(req: &'r Request<'_>) -> Outcome { + // get the session id from the cookie + let session_opt = req.cookies().get("rocket_session_id"); + + let session_id = match session_opt { + Some(s) => s.value(), + None => return Outcome::Error((Status::Unauthorized, ())), + }; + + let sessions_outcome = req.guard::<&State>().await; + let sessions = match sessions_outcome { + Outcome::Success(s) => s, + _ => return Outcome::Error((Status::InternalServerError, ())), + }; + + match sessions.get(session_id) { + Some(s) => Outcome::Success(User(s.clone())), + None => Outcome::Error((Status::Unauthorized, ())), + } + } +} diff --git a/src/auth/session.rs b/src/auth/session.rs new file mode 100644 index 0000000..8c0fa4a --- /dev/null +++ b/src/auth/session.rs @@ -0,0 +1,28 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +pub struct Sessions { + sessions: HashMap, +} + +impl Sessions { + pub fn new() -> Self { + Sessions { + sessions: HashMap::new(), + } + } + + pub fn insert(&mut self, session_id: String, session_data: SessionData) { + self.sessions.insert(session_id, session_data); + } + + pub fn get(&self, session_id: &str) -> Option<&SessionData> { + self.sessions.get(session_id) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SessionData { + user_id: i32, +} diff --git a/src/controller/mod.rs b/src/controller/mod.rs index b8d4136..17d67d7 100644 --- a/src/controller/mod.rs +++ b/src/controller/mod.rs @@ -1,10 +1,11 @@ use maud::Markup; -pub mod user; +use crate::auth::User; + pub mod register; +pub mod user; #[get("/")] -pub fn index() -> Markup { +pub fn index(_u: User) -> Markup { crate::view::login::login() } - diff --git a/src/controller/user.rs b/src/controller/user.rs index bb0f7d9..12b839b 100644 --- a/src/controller/user.rs +++ b/src/controller/user.rs @@ -1,4 +1,4 @@ -use maud::{Markup, html}; +use maud::{html, Markup}; use rocket::{form::Form, http::Status}; #[derive(FromForm, Debug)] @@ -15,26 +15,30 @@ pub async fn create_user(user: Form) -> (Status, Markup) { let email_domain = user.user_email.split('@').collect::>()[1]; if email_domain != "eegsac.com" { - return (Status::BadRequest, html! { - div id="user_create_response" - class="bg-red-500 text-white p-2 rounded transition-opacity" - classes="add opacity-0:5s, add hidden:1s" - { - "El dominio del correo electrónico debe ser eegsac.com" - } - }); + return ( + Status::BadRequest, + html! { + div id="user_create_response" + class="bg-red-500 text-white p-2 rounded transition-opacity" + classes="add opacity-0:5s, add hidden:1s" + { + "El dominio del correo electrónico debe ser eegsac.com" + } + }, + ); } - - - (Status::Ok, html! { - div id="user_create_response" - class="bg-green-700 text-white p-2 rounded transition-opacity" - classes="add opacity-0:5s, add hidden:1s" - // Reset the form state - x-init="user_name = ''; user_surname = ''; user_email = ''; user_password = '';" - { - "Registrado con éxito" - } - }) + ( + Status::Ok, + html! { + div id="user_create_response" + class="bg-green-700 text-white p-2 rounded transition-opacity" + classes="add opacity-0:5s, add hidden:1s" + // Reset the form state + x-init="user_name = ''; user_surname = ''; user_email = ''; user_password = '';" + { + "Registrado con éxito" + } + }, + ) } diff --git a/src/main.rs b/src/main.rs index e4db466..28c3224 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,9 @@ use rocket::fs::FileServer; +mod auth; mod controller; -mod view; mod model; +mod view; #[macro_use] extern crate rocket; @@ -10,12 +11,9 @@ extern crate rocket; #[launch] fn rocket() -> _ { rocket::build() - .mount("/", routes![ - controller::index, - - ]) - .mount("/f", routes![ - controller::user::create_user, - ]) + .manage(auth::session::Sessions::new()) + .register("/", catchers![view::not_authorized]) + .mount("/", routes![controller::index,]) + .mount("/f", routes![controller::user::create_user,]) .mount("/static", FileServer::from("static")) } diff --git a/src/model/mod.rs b/src/model/mod.rs index e69de29..8b13789 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -0,0 +1 @@ + diff --git a/src/view/fragments/mod.rs b/src/view/fragments/mod.rs index e69de29..8b13789 100644 --- a/src/view/fragments/mod.rs +++ b/src/view/fragments/mod.rs @@ -0,0 +1 @@ + diff --git a/src/view/mod.rs b/src/view/mod.rs index 9739eb3..2b1467e 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -24,3 +24,15 @@ pub fn default_skeleton(content: Markup) -> Markup { } } } + + +#[catch(401)] +pub fn not_authorized() -> Markup { + html! { + p style="background-color: rgb(248, 113, 113); color: white; padding: 0.5rem; border-radius: 0.5rem;" + { + "Tu sesión ha expirado, o no tienes permiso para ver esta página." + " Por favor, inicia sesión o contacta al administrador." + } + } +} diff --git a/src/view/register.rs b/src/view/register.rs index f90206b..a6a51ae 100644 --- a/src/view/register.rs +++ b/src/view/register.rs @@ -7,7 +7,7 @@ pub fn register() -> Markup { h1 { "Registrar nuevo usuario" } div x-data="{user_name: '', user_surname: '', user_email: '', user_password: ''}" - { + { form hx-post="/f/user" hx-target="#user_create_response" @@ -32,7 +32,7 @@ pub fn register() -> Markup { br; button class="bg-pink-300 text-black py-2 px-4 rounded-full cursor-pointer inline-block my-2 disabled:opacity-50" - data-loading-class="animate-pulse" type="submit" + data-loading-class="animate-pulse" type="submit" { "Registrar" } @@ -42,4 +42,3 @@ pub fn register() -> Markup { } }) } -