/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2024 metamuffin */ use super::{AdminSession, Session}; use crate::{database::DataAcid, routes::ui::error::MyError}; use anyhow::anyhow; use jellybase::database::T_USER; use log::warn; use rocket::{ async_trait, http::Status, outcome::Outcome, request::{self, FromRequest}, Request, State, }; impl Session { pub async fn from_request_ut(req: &Request<'_>) -> Result { let username; #[cfg(not(feature = "bypass-auth"))] { let token = req .query_value("session") .map(|e| e.expect("str parse should not fail, right?")) .or(req.cookies().get("session").map(|cookie| cookie.value())) .ok_or(anyhow!("not logged in"))?; username = super::token::validate(token)?; }; #[cfg(feature = "bypass-auth")] { username = "admin".to_string(); } let db = req.guard::<&State>().await.unwrap(); let user = { let txn = db.inner.begin_read()?; let table = txn.open_table(T_USER)?; let user = table .get(&*username)? .ok_or(anyhow!("user not found"))? .value() .0; drop(table); user }; Ok(Session { user }) } } #[async_trait] impl<'r> FromRequest<'r> for Session { type Error = MyError; async fn from_request<'life0>( request: &'r Request<'life0>, ) -> request::Outcome { match Session::from_request_ut(request).await { Ok(x) => Outcome::Success(x), Err(e) => { warn!("authentificated route rejected: {e:?}"); Outcome::Forward(Status::Unauthorized) } } } } #[async_trait] impl<'r> FromRequest<'r> for AdminSession { type Error = MyError; async fn from_request<'life0>( request: &'r Request<'life0>, ) -> request::Outcome { match Session::from_request_ut(request).await { Ok(x) => { if x.user.admin { Outcome::Success(AdminSession(x)) } else { Outcome::Error(( Status::Unauthorized, MyError(anyhow!("you are not an admin")), )) } } Err(e) => { warn!("authentificated route rejected: {e:?}"); Outcome::Forward(Status::Unauthorized) } } } }