diff --git a/src/cli/serve.rs b/src/cli/serve.rs index 67cf6e7..664a1e0 100644 --- a/src/cli/serve.rs +++ b/src/cli/serve.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use crate::{db, server}; pub fn serve(config: &crate::config::Config) -> u8 { @@ -13,7 +11,7 @@ pub fn serve(config: &crate::config::Config) -> u8 { let ctx = server::Context { store: crate::gpodder::GpodderRepository::new(repo), }; - let app = server::app(ctx.clone()); + let app = server::app(ctx); let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() @@ -23,28 +21,7 @@ pub fn serve(config: &crate::config::Config) -> u8 { let address = format!("{}:{}", config.domain, config.port); tracing::info!("Starting server on {address}"); - let session_removal_duration = Duration::from_secs(config.session_cleanup_interval); - rt.block_on(async { - tokio::task::spawn(async move { - let mut interval = tokio::time::interval(session_removal_duration); - - loop { - interval.tick().await; - - tracing::info!("Performing session cleanup"); - - match ctx.store.remove_old_sessions() { - Ok(n) => { - tracing::info!("Removed {} old sessions", n); - } - Err(err) => { - tracing::error!("Error occured during session cleanup: {}", err); - } - } - } - }); - let listener = tokio::net::TcpListener::bind(address).await.unwrap(); axum::serve(listener, app.into_make_service()) .await diff --git a/src/config.rs b/src/config.rs index 67bc59a..0f7df52 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,8 +10,6 @@ pub struct Config { pub domain: String, #[serde(default = "default_port")] pub port: u16, - #[serde(default = "default_session_cleanup_interval")] - pub session_cleanup_interval: u64, } fn default_data_dir() -> PathBuf { @@ -25,8 +23,3 @@ fn default_domain() -> String { fn default_port() -> u16 { 8080 } - -fn default_session_cleanup_interval() -> u64 { - // Default is once a day - 60 * 60 * 24 -} diff --git a/src/db/repository/auth.rs b/src/db/repository/auth.rs index 8bd7905..e65f046 100644 --- a/src/db/repository/auth.rs +++ b/src/db/repository/auth.rs @@ -181,29 +181,4 @@ impl gpodder::AuthStore for SqliteRepository { .execute(&mut self.pool.get()?) .map(|_| ())?) } - - fn refresh_session( - &self, - session: &gpodder::Session, - timestamp: DateTime, - ) -> Result<(), AuthErr> { - if diesel::update(sessions::table.filter(sessions::id.eq(session.id))) - .set(sessions::last_seen.eq(timestamp.timestamp())) - .execute(&mut self.pool.get()?)? - == 0 - { - Err(AuthErr::UnknownSession) - } else { - Ok(()) - } - } - - fn remove_old_sessions(&self, min_last_seen: DateTime) -> Result { - let min_last_seen = min_last_seen.timestamp(); - - Ok( - diesel::delete(sessions::table.filter(sessions::last_seen.lt(min_last_seen))) - .execute(&mut self.pool.get()?)?, - ) - } } diff --git a/src/gpodder/mod.rs b/src/gpodder/mod.rs index d8ff790..8336de1 100644 --- a/src/gpodder/mod.rs +++ b/src/gpodder/mod.rs @@ -1,13 +1,10 @@ pub mod models; mod repository; -use std::fmt::Display; - use chrono::{DateTime, Utc}; pub use models::*; pub use repository::GpodderRepository; -#[derive(Debug)] pub enum AuthErr { UnknownSession, UnknownUser, @@ -15,19 +12,6 @@ pub enum AuthErr { Other(Box), } -impl Display for AuthErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::UnknownUser => write!(f, "unknown user"), - Self::UnknownSession => write!(f, "unknown session"), - Self::InvalidPassword => write!(f, "invalid password"), - Self::Other(err) => err.fmt(f), - } - } -} - -impl std::error::Error for AuthErr {} - pub trait Store: AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository { @@ -68,12 +52,6 @@ pub trait AuthStore { /// Remove the session with the given session ID fn remove_session(&self, session_id: i64) -> Result<(), AuthErr>; - - /// Update the session's timestamp - fn refresh_session(&self, session: &Session, timestamp: DateTime) -> Result<(), AuthErr>; - - /// Remove any sessions whose last_seen timestamp is before the given minimum value - fn remove_old_sessions(&self, min_last_seen: DateTime) -> Result; } pub trait DeviceRepository { diff --git a/src/gpodder/repository.rs b/src/gpodder/repository.rs index e55d010..411f9cf 100644 --- a/src/gpodder/repository.rs +++ b/src/gpodder/repository.rs @@ -20,7 +20,7 @@ impl GpodderRepository { } } - pub fn get_session(&self, session_id: i64) -> Result { + pub fn validate_session(&self, session_id: i64) -> Result { let session = self .store .get_session(session_id)? @@ -65,22 +65,10 @@ impl GpodderRepository { Ok(session) } - pub fn refresh_session(&self, session: &models::Session) -> Result<(), AuthErr> { - let now = Utc::now(); - - self.store.refresh_session(session, now) - } - pub fn remove_session(&self, session_id: i64) -> Result<(), AuthErr> { self.store.remove_session(session_id) } - pub fn remove_old_sessions(&self) -> Result { - let min_last_seen = Utc::now() - TimeDelta::seconds(MAX_SESSION_AGE); - - self.store.remove_old_sessions(min_last_seen) - } - pub fn devices_for_user(&self, user: &models::User) -> Result, AuthErr> { self.store.devices_for_user(user) } diff --git a/src/server/gpodder/advanced/auth.rs b/src/server/gpodder/advanced/auth.rs index 242082a..ac5cbe6 100644 --- a/src/server/gpodder/advanced/auth.rs +++ b/src/server/gpodder/advanced/auth.rs @@ -4,11 +4,13 @@ use axum::{ Router, }; use axum_extra::{ - extract::{cookie::Cookie, CookieJar}, + extract::{ + cookie::{Cookie, Expiration}, + CookieJar, + }, headers::{authorization::Basic, Authorization}, TypedHeader, }; -use cookie::time::Duration; use crate::server::{ error::{AppError, AppResult}, @@ -43,7 +45,7 @@ async fn post_login( .unwrap()?; Ok(jar.add( - Cookie::build((SESSION_ID_COOKIE, session.id.to_string())).max_age(Duration::days(365)), + Cookie::build((SESSION_ID_COOKIE, session.id.to_string())).expires(Expiration::Session), )) } diff --git a/src/server/gpodder/mod.rs b/src/server/gpodder/mod.rs index 4746323..776100e 100644 --- a/src/server/gpodder/mod.rs +++ b/src/server/gpodder/mod.rs @@ -47,15 +47,10 @@ pub async fn auth_middleware(State(ctx): State, mut req: Request, next: .get(SESSION_ID_COOKIE) .and_then(|c| c.value().parse::().ok()) { - let ctx = ctx.clone(); - match tokio::task::spawn_blocking(move || { - let session = ctx.store.get_session(session_id)?; - ctx.store.refresh_session(&session)?; - - Ok(session) - }) - .await - .unwrap() + let ctx_clone = ctx.clone(); + match tokio::task::spawn_blocking(move || ctx_clone.store.validate_session(session_id)) + .await + .unwrap() { Ok(session) => { auth_user = Some(session.user);