feat: store user agent with sessions

main
Jef Roosens 2025-03-29 15:37:50 +01:00
parent 5112a6ce35
commit 2c44f788d9
No known key found for this signature in database
GPG Key ID: 21FD3D77D56BAF49
9 changed files with 23 additions and 5 deletions

View File

@ -56,6 +56,7 @@ pub struct EpisodeAction {
pub struct Session {
pub id: i64,
pub last_seen: DateTime<Utc>,
pub user_agent: Option<String>,
pub user: User,
}

View File

@ -71,11 +71,16 @@ impl GpodderRepository {
}
}
pub fn create_session(&self, user: &models::User) -> Result<models::Session, AuthErr> {
pub fn create_session(
&self,
user: &models::User,
user_agent: Option<String>,
) -> Result<models::Session, AuthErr> {
let session = models::Session {
id: rand::thread_rng().gen(),
last_seen: Utc::now(),
user: user.clone(),
user_agent,
};
self.store.insert_session(&session)?;

View File

@ -0,0 +1,2 @@
alter table sessions
drop column user_agent;

View File

@ -0,0 +1,2 @@
alter table sessions
add column user_agent text;

View File

@ -10,6 +10,7 @@ pub struct Session {
pub id: i64,
pub user_id: i64,
pub last_seen: i64,
pub user_agent: Option<String>,
}
impl Session {

View File

@ -59,6 +59,7 @@ impl gpodder::AuthStore for SqliteRepository {
id: session.id,
last_seen: DateTime::from_timestamp(session.last_seen, 0).unwrap(),
user: user.into(),
user_agent: session.user_agent.clone(),
})),
Ok(None) => Ok(None),
Err(err) => Err(DbError::from(err).into()),
@ -79,6 +80,7 @@ impl gpodder::AuthStore for SqliteRepository {
id: session.id,
user_id: session.user.id,
last_seen: session.last_seen.timestamp(),
user_agent: session.user_agent.clone(),
}
.insert_into(sessions::table)
.execute(&mut self.pool.get().map_err(DbError::from)?)

View File

@ -43,6 +43,7 @@ diesel::table! {
id -> BigInt,
user_id -> BigInt,
last_seen -> BigInt,
user_agent -> Nullable<Text>,
}
}

View File

@ -1,7 +1,5 @@
use std::time::Duration;
use tracing_subscriber::util::SubscriberInitExt;
use crate::server;
pub fn serve(config: &crate::config::Config) -> u8 {

View File

@ -5,10 +5,11 @@ use axum::{
};
use axum_extra::{
extract::{cookie::Cookie, CookieJar},
headers::{authorization::Basic, Authorization},
headers::{authorization::Basic, Authorization, UserAgent},
TypedHeader,
};
use cookie::time::Duration;
use gpodder::AuthErr;
use crate::server::{
error::{AppError, AppResult},
@ -27,6 +28,7 @@ async fn post_login(
Path(username): Path<String>,
jar: CookieJar,
TypedHeader(auth): TypedHeader<Authorization<Basic>>,
user_agent: Option<TypedHeader<UserAgent>>,
) -> AppResult<CookieJar> {
// These should be the same according to the spec
if username != auth.username() {
@ -62,7 +64,11 @@ async fn post_login(
let user = ctx
.store
.validate_credentials(auth.username(), auth.password())?;
ctx.store.create_session(&user)
let user_agent = user_agent.map(|header| header.to_string());
let session = ctx.store.create_session(&user, user_agent)?;
Ok::<_, AuthErr>(session)
})
.await
.unwrap()?;