From 588520914cc705f8596149681ce6fc17d5d883e6 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Wed, 16 Apr 2025 10:18:27 +0200 Subject: [PATCH 1/6] add nextcloud auth route --- src/tera/mod.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 486661e..1396a76 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -7,7 +7,7 @@ use rocket::{ form::Form, fs::FileServer, get, - http::Cookie, + http::{Cookie, Status}, post, request::FlashMessage, response::{Flash, Redirect}, @@ -123,11 +123,23 @@ async fn wikiauth(db: &State, login: Form>) -> String "FAIL".into() } +#[get("/?&")] +async fn nextcloud_auth(db: &State, username: String, password: String) -> Status { + if let Ok(user) = User::login(db, &username, &password).await { + if user.has_role(db, "admin").await { + return Status::Ok; + } + if user.has_role(db, "Vorstand").await { + return Status::Ok; + } + } + Status::Unauthorized +} + #[catch(401)] //Unauthorized fn unauthorized_error(req: &Request) -> Redirect { // Save the URL the user tried to access, to be able to go there once logged in let mut redirect_cookie = Cookie::new("redirect_url", format!("{}", req.uri())); - println!("{}", req.uri()); redirect_cookie.set_expires(OffsetDateTime::now_utc() + Duration::hours(1)); req.cookies().add_private(redirect_cookie); @@ -265,6 +277,7 @@ pub fn config(rocket: Rocket) -> Rocket { .mount("/", routes![index, steering, impressum]) .mount("/auth", auth::routes()) .mount("/wikiauth", routes![wikiauth]) + .mount("/nxauth", routes![nextcloud_auth]) .mount("/new-blogpost", routes![new_blogpost]) .mount("/blogpost-unpublished", routes![blogpost_unpublished]) .mount("/log", log::routes()) From 2b79df8e4290c6d7f2800c7086cf815aae54bf83 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Wed, 16 Apr 2025 10:46:19 +0200 Subject: [PATCH 2/6] no funny business w/ get params --- Cargo.lock | 1 + Cargo.toml | 1 + src/tera/mod.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3f3426..ea63be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2544,6 +2544,7 @@ name = "rot" version = "0.1.0" dependencies = [ "argon2", + "base64", "chrono", "chrono-tz 0.10.3", "csv", diff --git a/Cargo.toml b/Cargo.toml index 4a16639..921b158 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ job_scheduler_ng = "2.0" ureq = { version = "3.0", features = ["json"] } regex = "1.10" urlencoding = "2.1" +base64 = "0.22" [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10", features = [ "vendored" ] } diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 1396a76..44d0890 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -9,7 +9,7 @@ use rocket::{ get, http::{Cookie, Status}, post, - request::FlashMessage, + request::{FlashMessage, FromRequest, Outcome}, response::{Flash, Redirect}, routes, time::{Duration, OffsetDateTime}, @@ -123,9 +123,57 @@ async fn wikiauth(db: &State, login: Form>) -> String "FAIL".into() } -#[get("/?&")] -async fn nextcloud_auth(db: &State, username: String, password: String) -> Status { - if let Ok(user) = User::login(db, &username, &password).await { +struct BasicAuth { + username: String, + password: String, +} + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for BasicAuth { + type Error = (); + + async fn from_request(request: &'r Request<'_>) -> Outcome { + // Get the Authorization header + let auth_header = match request.headers().get_one("Authorization") { + Some(h) => h, + None => return Outcome::Failure((Status::Unauthorized, ())), + }; + + // Check if it's a Basic auth header + if !auth_header.starts_with("Basic ") { + return Outcome::Failure((Status::Unauthorized, ())); + } + + // Decode the base64 credentials + let credentials = match BASE64.decode(auth_header[6..].as_bytes()) { + Ok(c) => c, + Err(_) => return Outcome::Failure((Status::Unauthorized, ())), + }; + + // Convert to UTF-8 string + let credentials_str = match str::from_utf8(&credentials) { + Ok(s) => s, + Err(_) => return Outcome::Failure((Status::Unauthorized, ())), + }; + + // Split into username and password + let mut parts = credentials_str.splitn(2, ':'); + let username = match parts.next() { + Some(u) => u.to_string(), + None => return Outcome::Failure((Status::Unauthorized, ())), + }; + let password = match parts.next() { + Some(p) => p.to_string(), + None => return Outcome::Failure((Status::Unauthorized, ())), + }; + + Outcome::Success(BasicAuth { username, password }) + } +} + +#[get("/")] +async fn nextcloud_auth(db: &State, auth: BasicAuth) -> Status { + if let Ok(user) = User::login(db, &auth.username, &auth.password).await { if user.has_role(db, "admin").await { return Status::Ok; } From dc2ee38aa024816b1f9892d1cab333e0e496ae14 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Wed, 16 Apr 2025 10:56:57 +0200 Subject: [PATCH 3/6] no funny business w/ get params --- src/tera/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 44d0890..44cba1a 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -30,6 +30,7 @@ use crate::{ }, SCHECKBUCH, }; +use base64::alphabet::STANDARD; pub(crate) mod admin; mod auth; @@ -136,35 +137,35 @@ impl<'r> FromRequest<'r> for BasicAuth { // Get the Authorization header let auth_header = match request.headers().get_one("Authorization") { Some(h) => h, - None => return Outcome::Failure((Status::Unauthorized, ())), + None => return Outcome::Error((Status::Unauthorized, ())), }; // Check if it's a Basic auth header if !auth_header.starts_with("Basic ") { - return Outcome::Failure((Status::Unauthorized, ())); + return Outcome::Error((Status::Unauthorized, ())); } // Decode the base64 credentials - let credentials = match BASE64.decode(auth_header[6..].as_bytes()) { + let credentials = match base64::decode(&auth_header[6..]) { Ok(c) => c, - Err(_) => return Outcome::Failure((Status::Unauthorized, ())), + Err(_) => return Outcome::Error((Status::Unauthorized, ())), }; // Convert to UTF-8 string - let credentials_str = match str::from_utf8(&credentials) { + let credentials_str = match std::str::from_utf8(&credentials) { Ok(s) => s, - Err(_) => return Outcome::Failure((Status::Unauthorized, ())), + Err(_) => return Outcome::Error((Status::Unauthorized, ())), }; // Split into username and password let mut parts = credentials_str.splitn(2, ':'); let username = match parts.next() { Some(u) => u.to_string(), - None => return Outcome::Failure((Status::Unauthorized, ())), + None => return Outcome::Error((Status::Unauthorized, ())), }; let password = match parts.next() { Some(p) => p.to_string(), - None => return Outcome::Failure((Status::Unauthorized, ())), + None => return Outcome::Error((Status::Unauthorized, ())), }; Outcome::Success(BasicAuth { username, password }) From 4ce9a573fe9087f6a29ef25664360182168e056e Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Wed, 16 Apr 2025 11:31:46 +0200 Subject: [PATCH 4/6] 400 instead of 303 --- src/tera/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 44cba1a..3e403fa 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -182,7 +182,7 @@ async fn nextcloud_auth(db: &State, auth: BasicAuth) -> Status { return Status::Ok; } } - Status::Unauthorized + Status::BadRequest } #[catch(401)] //Unauthorized From 0059dfe96ff6227bbf29acfa71bab90efe3887f0 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Fri, 18 Apr 2025 17:04:10 +0200 Subject: [PATCH 5/6] simple nx auth --- src/tera/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tera/mod.rs b/src/tera/mod.rs index ac3a130..91f6ecb 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -123,6 +123,19 @@ async fn wikiauth(db: &State, login: Form>) -> String "FAIL".into() } +#[post("/", data = "")] +async fn nextcloud_auth(db: &State, login: Form>) -> String { + if let Ok(user) = User::login(db, login.name, login.password).await { + if user.has_role(db, "admin").await { + return String::from("SUCC"); + } + if user.has_role(db, "Vorstand").await { + return String::from("SUCC"); + } + } + "FAIL".into() +} + #[catch(401)] //Unauthorized fn unauthorized_error(req: &Request) -> Redirect { // Save the URL the user tried to access, to be able to go there once logged in @@ -264,6 +277,7 @@ pub fn config(rocket: Rocket) -> Rocket { .mount("/", routes![index, steering, impressum]) .mount("/auth", auth::routes()) .mount("/wikiauth", routes![wikiauth]) + .mount("/nxauth", routes![nextcloud_auth]) .mount("/new-blogpost", routes![new_blogpost]) .mount("/blogpost-unpublished", routes![blogpost_unpublished]) .mount("/log", log::routes()) From 37b6ea60574c928d70ee50026fabd2805fb4e3f6 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Fri, 18 Apr 2025 17:44:21 +0200 Subject: [PATCH 6/6] remove unused dep; cargo clippy --- Cargo.lock | 1 - Cargo.toml | 1 - src/model/tripdetails.rs | 2 +- src/tera/mod.rs | 5 ++--- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea63be2..b3f3426 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2544,7 +2544,6 @@ name = "rot" version = "0.1.0" dependencies = [ "argon2", - "base64", "chrono", "chrono-tz 0.10.3", "csv", diff --git a/Cargo.toml b/Cargo.toml index 921b158..4a16639 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ job_scheduler_ng = "2.0" ureq = { version = "3.0", features = ["json"] } regex = "1.10" urlencoding = "2.1" -base64 = "0.22" [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10", features = [ "vendored" ] } diff --git a/src/model/tripdetails.rs b/src/model/tripdetails.rs index ff813cb..eebafce 100644 --- a/src/model/tripdetails.rs +++ b/src/model/tripdetails.rs @@ -196,7 +196,7 @@ WHERE day = ? AND planned_starting_time = ? .fetch_one(db) .await .unwrap(); //TODO: fixme - let amount_currently_registered = i64::from(amount_currently_registered.count); + let amount_currently_registered = amount_currently_registered.count; amount_currently_registered >= self.max_people } diff --git a/src/tera/mod.rs b/src/tera/mod.rs index b9e8dcb..91f6ecb 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -7,9 +7,9 @@ use rocket::{ form::Form, fs::FileServer, get, - http::{Cookie, Status}, + http::Cookie, post, - request::{FlashMessage, FromRequest, Outcome}, + request::FlashMessage, response::{Flash, Redirect}, routes, time::{Duration, OffsetDateTime}, @@ -30,7 +30,6 @@ use crate::{ }, SCHECKBUCH, }; -use base64::alphabet::STANDARD; pub(crate) mod admin; mod auth;