feat: store user agent with sessions
parent
5112a6ce35
commit
2c44f788d9
|
@ -56,6 +56,7 @@ pub struct EpisodeAction {
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub last_seen: DateTime<Utc>,
|
pub last_seen: DateTime<Utc>,
|
||||||
|
pub user_agent: Option<String>,
|
||||||
pub user: User,
|
pub user: User,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
let session = models::Session {
|
||||||
id: rand::thread_rng().gen(),
|
id: rand::thread_rng().gen(),
|
||||||
last_seen: Utc::now(),
|
last_seen: Utc::now(),
|
||||||
user: user.clone(),
|
user: user.clone(),
|
||||||
|
user_agent,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.store.insert_session(&session)?;
|
self.store.insert_session(&session)?;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
alter table sessions
|
||||||
|
drop column user_agent;
|
|
@ -0,0 +1,2 @@
|
||||||
|
alter table sessions
|
||||||
|
add column user_agent text;
|
|
@ -10,6 +10,7 @@ pub struct Session {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub user_id: i64,
|
pub user_id: i64,
|
||||||
pub last_seen: i64,
|
pub last_seen: i64,
|
||||||
|
pub user_agent: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl gpodder::AuthStore for SqliteRepository {
|
||||||
id: session.id,
|
id: session.id,
|
||||||
last_seen: DateTime::from_timestamp(session.last_seen, 0).unwrap(),
|
last_seen: DateTime::from_timestamp(session.last_seen, 0).unwrap(),
|
||||||
user: user.into(),
|
user: user.into(),
|
||||||
|
user_agent: session.user_agent.clone(),
|
||||||
})),
|
})),
|
||||||
Ok(None) => Ok(None),
|
Ok(None) => Ok(None),
|
||||||
Err(err) => Err(DbError::from(err).into()),
|
Err(err) => Err(DbError::from(err).into()),
|
||||||
|
@ -79,6 +80,7 @@ impl gpodder::AuthStore for SqliteRepository {
|
||||||
id: session.id,
|
id: session.id,
|
||||||
user_id: session.user.id,
|
user_id: session.user.id,
|
||||||
last_seen: session.last_seen.timestamp(),
|
last_seen: session.last_seen.timestamp(),
|
||||||
|
user_agent: session.user_agent.clone(),
|
||||||
}
|
}
|
||||||
.insert_into(sessions::table)
|
.insert_into(sessions::table)
|
||||||
.execute(&mut self.pool.get().map_err(DbError::from)?)
|
.execute(&mut self.pool.get().map_err(DbError::from)?)
|
||||||
|
|
|
@ -43,6 +43,7 @@ diesel::table! {
|
||||||
id -> BigInt,
|
id -> BigInt,
|
||||||
user_id -> BigInt,
|
user_id -> BigInt,
|
||||||
last_seen -> BigInt,
|
last_seen -> BigInt,
|
||||||
|
user_agent -> Nullable<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
|
||||||
|
|
||||||
use crate::server;
|
use crate::server;
|
||||||
|
|
||||||
pub fn serve(config: &crate::config::Config) -> u8 {
|
pub fn serve(config: &crate::config::Config) -> u8 {
|
||||||
|
|
|
@ -5,10 +5,11 @@ use axum::{
|
||||||
};
|
};
|
||||||
use axum_extra::{
|
use axum_extra::{
|
||||||
extract::{cookie::Cookie, CookieJar},
|
extract::{cookie::Cookie, CookieJar},
|
||||||
headers::{authorization::Basic, Authorization},
|
headers::{authorization::Basic, Authorization, UserAgent},
|
||||||
TypedHeader,
|
TypedHeader,
|
||||||
};
|
};
|
||||||
use cookie::time::Duration;
|
use cookie::time::Duration;
|
||||||
|
use gpodder::AuthErr;
|
||||||
|
|
||||||
use crate::server::{
|
use crate::server::{
|
||||||
error::{AppError, AppResult},
|
error::{AppError, AppResult},
|
||||||
|
@ -27,6 +28,7 @@ async fn post_login(
|
||||||
Path(username): Path<String>,
|
Path(username): Path<String>,
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
TypedHeader(auth): TypedHeader<Authorization<Basic>>,
|
TypedHeader(auth): TypedHeader<Authorization<Basic>>,
|
||||||
|
user_agent: Option<TypedHeader<UserAgent>>,
|
||||||
) -> AppResult<CookieJar> {
|
) -> AppResult<CookieJar> {
|
||||||
// These should be the same according to the spec
|
// These should be the same according to the spec
|
||||||
if username != auth.username() {
|
if username != auth.username() {
|
||||||
|
@ -62,7 +64,11 @@ async fn post_login(
|
||||||
let user = ctx
|
let user = ctx
|
||||||
.store
|
.store
|
||||||
.validate_credentials(auth.username(), auth.password())?;
|
.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
|
.await
|
||||||
.unwrap()?;
|
.unwrap()?;
|
||||||
|
|
Loading…
Reference in New Issue