use diesel::prelude::*; use rand::Rng; use super::SqliteRepository; use crate::{ db::{self, schema::*}, gpodder::{self, AuthErr}, }; impl From for gpodder::AuthErr { fn from(value: diesel::r2d2::PoolError) -> Self { Self::Other(Box::new(value)) } } impl From for gpodder::AuthErr { fn from(value: diesel::result::Error) -> Self { Self::Other(Box::new(value)) } } impl gpodder::AuthRepository for SqliteRepository { fn validate_credentials( &self, username: &str, password: &str, ) -> Result { if let Some(user) = users::table .select(db::User::as_select()) .filter(users::username.eq(username)) .first(&mut self.pool.get()?) .optional()? { if user.verify_password(password) { Ok(gpodder::User { id: user.id, username: user.username, }) } else { Err(gpodder::AuthErr::InvalidPassword) } } else { Err(gpodder::AuthErr::UnknownUser) } } fn validate_session(&self, session_id: i64) -> Result { match sessions::dsl::sessions .inner_join(users::table) .filter(sessions::id.eq(session_id)) .select(db::User::as_select()) .get_result(&mut self.pool.get()?) { Ok(user) => Ok(gpodder::User { id: user.id, username: user.username, }), Err(diesel::result::Error::NotFound) => Err(gpodder::AuthErr::UnknownSession), Err(err) => Err(gpodder::AuthErr::Other(Box::new(err))), } } fn create_session( &self, username: &str, password: &str, ) -> Result<(i64, gpodder::models::User), gpodder::AuthErr> { if let Some(user) = users::table .select(db::User::as_select()) .filter(users::username.eq(username)) .first(&mut self.pool.get()?) .optional()? { if user.verify_password(password) { let id: i64 = rand::thread_rng().gen(); let session_id = db::Session { id, user_id: user.id, last_seen: chrono::Utc::now().timestamp(), } .insert_into(sessions::table) .returning(sessions::id) .get_result(&mut self.pool.get()?)?; Ok(( session_id, gpodder::User { id: user.id, username: user.username, }, )) } else { Err(gpodder::AuthErr::InvalidPassword) } } else { Err(gpodder::AuthErr::UnknownUser) } } fn remove_session(&self, username: &str, session_id: i64) -> Result<(), gpodder::AuthErr> { let conn = &mut self.pool.get()?; if let Some(user) = sessions::table .inner_join(users::table) .filter(sessions::id.eq(session_id)) .select(db::User::as_select()) .get_result(conn) .optional()? { if user.username == username { Ok( diesel::delete(sessions::table.filter(sessions::id.eq(session_id))) .execute(conn) .map(|_| ())?, ) } else { Err(AuthErr::UnknownUser) } } else { Ok(()) } } }