/* 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) 2023 metamuffin */ use crate::{ database::{Database, User}, routes::ui::error::MyError, CONF, }; use anyhow::anyhow; use chrono::{DateTime, Duration, Utc}; use rocket::{ outcome::Outcome, request::{self, FromRequest}, Request, State, }; use serde::{Deserialize, Serialize}; pub struct Session { pub user: User, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SessionCookie { name: String, expire: DateTime, } impl SessionCookie { pub fn new(name: String) -> Self { Self { name, expire: Utc::now() + Duration::days(CONF.login_expire), } } } impl Session { pub async fn from_request_ut(req: &Request<'_>) -> Result { #[cfg(not(feature = "bypass-auth"))] let cookie = req .cookies() .get_private("user") .ok_or(anyhow!("login required"))?; #[cfg(not(feature = "bypass-auth"))] let cookie = serde_json::from_str::(cookie.value())?; #[cfg(feature = "bypass-auth")] let cookie = SessionCookie { name: crate::CONF.admin_username.to_string(), expire: Utc::now() + Duration::days(CONF.login_expire), }; if cookie.expire < Utc::now() { Err(anyhow!("cookie expired"))?; } let db = req.guard::<&State>().await.unwrap(); let user = db .users .get(&cookie.name.to_string())? .ok_or(anyhow!("user not found"))?; Ok(Session { user }) } } impl<'r> FromRequest<'r> for Session { type Error = MyError; fn from_request<'life0, 'async_trait>( request: &'r Request<'life0>, ) -> core::pin::Pin< Box< dyn core::future::Future> + core::marker::Send + 'async_trait, >, > where 'r: 'async_trait, 'life0: 'async_trait, Self: 'async_trait, { Box::pin(async move { match Self::from_request_ut(request).await { Ok(x) => Outcome::Success(x), Err(_) => Outcome::Forward(()), } }) } }