feat: migrate auth to repository system
parent
adda030c3b
commit
2be126a7b3
|
@ -4,7 +4,7 @@ use rand::Rng;
|
|||
use super::SqliteRepository;
|
||||
use crate::{
|
||||
db::{self, schema::*},
|
||||
gpodder,
|
||||
gpodder::{self, AuthErr},
|
||||
};
|
||||
|
||||
impl From<diesel::r2d2::PoolError> for gpodder::AuthErr {
|
||||
|
@ -72,4 +72,28 @@ impl gpodder::AuthRepository for SqliteRepository {
|
|||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ pub trait AuthRepository: Send + Sync {
|
|||
username: &str,
|
||||
password: &str,
|
||||
) -> Result<(i64, models::User), AuthErr>;
|
||||
|
||||
fn remove_session(&self, username: &str, session_id: i64) -> Result<(), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait DeviceRepository: Send + Sync {
|
||||
|
|
|
@ -13,7 +13,7 @@ use axum_extra::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
db::{Session, User},
|
||||
gpodder::AuthRepository,
|
||||
server::{
|
||||
error::{AppError, AppResult},
|
||||
gpodder::SESSION_ID_COOKIE,
|
||||
|
@ -38,20 +38,14 @@ async fn post_login(
|
|||
return Err(AppError::BadRequest);
|
||||
}
|
||||
|
||||
let session = tokio::task::spawn_blocking(move || {
|
||||
let user = User::by_username(&ctx.pool, auth.username())?.ok_or(AppError::NotFound)?;
|
||||
|
||||
if user.verify_password(auth.password()) {
|
||||
Ok(Session::new_for_user(&ctx.pool, user.id)?)
|
||||
} else {
|
||||
Err(AppError::Unauthorized)
|
||||
}
|
||||
let (session_id, _) = tokio::task::spawn_blocking(move || {
|
||||
ctx.repo.create_session(auth.username(), auth.password())
|
||||
})
|
||||
.await
|
||||
.unwrap()?;
|
||||
|
||||
Ok(jar.add(
|
||||
Cookie::build((SESSION_ID_COOKIE, session.id.to_string())).expires(Expiration::Session),
|
||||
Cookie::build((SESSION_ID_COOKIE, session_id.to_string())).expires(Expiration::Session),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -66,21 +60,7 @@ async fn post_logout(
|
|||
.parse()
|
||||
.map_err(|_| AppError::BadRequest)?;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
if let Some(session) = Session::by_id(&ctx.pool, session_id)? {
|
||||
let user = session.user(&ctx.pool)?.ok_or(AppError::NotFound)?;
|
||||
|
||||
// The requested user to logout should be the same as the one linked to the session
|
||||
// ID
|
||||
if username == user.username {
|
||||
Ok(session.remove(&ctx.pool)?)
|
||||
} else {
|
||||
Err(AppError::BadRequest)
|
||||
}
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
})
|
||||
tokio::task::spawn_blocking(move || ctx.repo.remove_session(&username, session_id))
|
||||
.await
|
||||
.unwrap()?;
|
||||
|
||||
|
|
|
@ -20,7 +20,10 @@ use axum_extra::{
|
|||
};
|
||||
use tower_http::set_header::SetResponseHeaderLayer;
|
||||
|
||||
use crate::{db, gpodder, server::error::AppError};
|
||||
use crate::{
|
||||
gpodder::{self, AuthRepository},
|
||||
server::error::AppError,
|
||||
};
|
||||
|
||||
use super::Context;
|
||||
|
||||
|
@ -50,13 +53,13 @@ pub async fn auth_middleware(State(ctx): State<Context>, mut req: Request, next:
|
|||
.get(SESSION_ID_COOKIE)
|
||||
.and_then(|c| c.value().parse::<i64>().ok())
|
||||
{
|
||||
match tokio::task::spawn_blocking(move || db::Session::user_from_id(&ctx.pool, session_id))
|
||||
match tokio::task::spawn_blocking(move || ctx.repo.validate_session(session_id))
|
||||
.await
|
||||
.unwrap()
|
||||
.map_err(AppError::Db)
|
||||
.map_err(AppError::from)
|
||||
{
|
||||
Ok(user) => {
|
||||
auth_user = user;
|
||||
auth_user = Some(user);
|
||||
}
|
||||
Err(err) => {
|
||||
return err.into_response();
|
||||
|
@ -67,21 +70,15 @@ pub async fn auth_middleware(State(ctx): State<Context>, mut req: Request, next:
|
|||
.await
|
||||
{
|
||||
match tokio::task::spawn_blocking(move || {
|
||||
let user =
|
||||
db::User::by_username(&ctx.pool, auth.username())?.ok_or(AppError::NotFound)?;
|
||||
|
||||
if user.verify_password(auth.password()) {
|
||||
Ok((db::Session::new_for_user(&ctx.pool, user.id)?, user))
|
||||
} else {
|
||||
Err(AppError::Unauthorized)
|
||||
}
|
||||
ctx.repo.create_session(auth.username(), auth.password())
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.map_err(AppError::from)
|
||||
{
|
||||
Ok((session, user)) => {
|
||||
Ok((session_id, user)) => {
|
||||
auth_user = Some(user);
|
||||
new_session_id = Some(session.id);
|
||||
new_session_id = Some(session_id);
|
||||
}
|
||||
Err(err) => {
|
||||
return err.into_response();
|
||||
|
@ -90,11 +87,8 @@ pub async fn auth_middleware(State(ctx): State<Context>, mut req: Request, next:
|
|||
}
|
||||
|
||||
if let Some(user) = auth_user {
|
||||
req.extensions_mut().insert(user.clone());
|
||||
req.extensions_mut().insert(gpodder::User {
|
||||
username: user.username,
|
||||
id: user.id,
|
||||
});
|
||||
req.extensions_mut().insert(user);
|
||||
|
||||
let res = next.run(req).await;
|
||||
|
||||
if let Some(session_id) = new_session_id {
|
||||
|
|
Loading…
Reference in New Issue