otter/src/server/gpodder/advanced/auth.rs

72 lines
1.7 KiB
Rust

use axum::{
extract::{Path, State},
routing::post,
Router,
};
use axum_extra::{
extract::{
cookie::{Cookie, Expiration},
CookieJar,
},
headers::{authorization::Basic, Authorization},
TypedHeader,
};
use crate::{
gpodder::AuthRepository,
server::{
error::{AppError, AppResult},
gpodder::SESSION_ID_COOKIE,
Context,
},
};
pub fn router() -> Router<Context> {
Router::new()
.route("/{username}/login.json", post(post_login))
.route("/{username}/logout.json", post(post_logout))
}
async fn post_login(
State(ctx): State<Context>,
Path(username): Path<String>,
jar: CookieJar,
TypedHeader(auth): TypedHeader<Authorization<Basic>>,
) -> AppResult<CookieJar> {
// These should be the same according to the spec
if username != auth.username() {
return Err(AppError::BadRequest);
}
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),
))
}
async fn post_logout(
State(ctx): State<Context>,
Path(username): Path<String>,
jar: CookieJar,
) -> AppResult<CookieJar> {
if let Some(session_id) = jar.get(SESSION_ID_COOKIE) {
let session_id: i64 = session_id
.value()
.parse()
.map_err(|_| AppError::BadRequest)?;
tokio::task::spawn_blocking(move || ctx.repo.remove_session(&username, session_id))
.await
.unwrap()?;
Ok(jar.remove(SESSION_ID_COOKIE))
} else {
Ok(jar)
}
}