diff options
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/config.rs | 4 | ||||
-rw-r--r-- | server/src/routes/mod.rs | 4 | ||||
-rw-r--r-- | server/src/routes/ui/account/mod.rs | 11 | ||||
-rw-r--r-- | server/src/routes/ui/account/session.rs | 32 | ||||
-rw-r--r-- | server/src/routes/ui/error.rs | 5 | ||||
-rw-r--r-- | server/src/routes/ui/home.rs | 2 | ||||
-rw-r--r-- | server/src/routes/ui/player.rs | 6 |
7 files changed, 52 insertions, 12 deletions
diff --git a/server/src/config.rs b/server/src/config.rs index 4b61960..0de7e90 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -10,13 +10,15 @@ use std::{fs::File, path::PathBuf}; pub struct GlobalConfig { pub brand: String, pub slogan: String, - pub asset_dir: PathBuf, + pub asset_path: PathBuf, pub database_path: PathBuf, pub library_path: PathBuf, + pub admin_username: String, pub admin_password: String, pub cookie_key: String, + pub login_expire: i64, } pub fn load_global_config() -> GlobalConfig { diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index d1bf7fc..c567d94 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -48,7 +48,7 @@ pub fn build_rocket( Box::pin(async {}) })) .register("/", catchers![r_catch]) - .mount("/assets", FileServer::from(&CONF.asset_dir)) + .mount("/assets", FileServer::from(&CONF.asset_path)) .mount( "/", routes![ @@ -77,5 +77,5 @@ pub fn build_rocket( #[get("/favicon.ico")] fn r_favicon() -> MyResult<File> { - Ok(File::open(CONF.asset_dir.join("favicon.ico"))?) + Ok(File::open(CONF.asset_path.join("favicon.ico"))?) } diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index e7031ff..63c01c5 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -6,6 +6,8 @@ pub mod admin; pub mod session; +use self::session::SessionCookie; + use super::{error::MyError, layout::LayoutPage}; use crate::{ database::{Database, User}, @@ -157,7 +159,14 @@ pub fn r_account_login_post( Err(anyhow!("invalid password"))? } - jar.add_private(Cookie::build("user", user.name).permanent().finish()); + jar.add_private( + Cookie::build( + "user", + serde_json::to_string(&SessionCookie::new(user.name)).unwrap(), + ) + .permanent() + .finish(), + ); Ok(Redirect::found(uri!(r_home()))) } diff --git a/server/src/routes/ui/account/session.rs b/server/src/routes/ui/account/session.rs index 6059311..6795c06 100644 --- a/server/src/routes/ui/account/session.rs +++ b/server/src/routes/ui/account/session.rs @@ -5,19 +5,36 @@ */ use crate::{ database::{Database, User}, - routes::ui::error::MyError, + routes::ui::error::MyError, CONF, }; use anyhow::anyhow; +use chrono::{DateTime, Duration, Utc}; use rocket::{ outcome::Outcome, request::{self, FromRequest}, Request, State, }; +use serde::{Deserialize, Serialize}; pub struct Session { pub user: User, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SessionCookie { + name: String, + expire: DateTime<Utc>, +} + +impl SessionCookie { + pub fn new(name: String) -> Self { + Self { + name, + expire: Utc::now() + Duration::days(CONF.login_expire), + } + } +} + impl Session { pub async fn from_request_ut(req: &Request<'_>) -> Result<Self, MyError> { #[cfg(not(feature = "bypass-auth"))] @@ -26,14 +43,21 @@ impl Session { .get_private("user") .ok_or(anyhow!("login required"))?; #[cfg(not(feature = "bypass-auth"))] - let username = cookie.value(); + let cookie = serde_json::from_str::<SessionCookie>(cookie.value())?; #[cfg(feature = "bypass-auth")] - let username = crate::CONF.admin_username.to_string(); + let cookie = SessionCookie { + name: crate::CONF.admin_username.to_string(), + expire: Utc::now() + Duration::days(CONF.login_expire), + }; + + if cookie.expire < Utc::now() { + Err(anyhow!("cookie expired"))?; + } let db = req.guard::<&State<Database>>().await.unwrap(); let user = db .users - .get(&username.to_string())? + .get(&cookie.name.to_string())? .ok_or(anyhow!("user not found"))?; Ok(Session { user }) diff --git a/server/src/routes/ui/error.rs b/server/src/routes/ui/error.rs index 59e322a..7913e1a 100644 --- a/server/src/routes/ui/error.rs +++ b/server/src/routes/ui/error.rs @@ -70,3 +70,8 @@ impl From<sled::Error> for MyError { MyError(anyhow::anyhow!("{err}")) } } +impl From<serde_json::Error> for MyError { + fn from(err: serde_json::Error) -> Self { + MyError(anyhow::anyhow!("{err}")) + } +} diff --git a/server/src/routes/ui/home.rs b/server/src/routes/ui/home.rs index a8d9c65..f81e04f 100644 --- a/server/src/routes/ui/home.rs +++ b/server/src/routes/ui/home.rs @@ -25,7 +25,7 @@ pub fn r_home(_sess: Session, library: &State<Library>) -> DynLayoutPage { #[get("/", rank = 2)] pub async fn r_home_unpriv() -> MyResult<DynLayoutPage<'static>> { - let front = read_to_string(CONF.asset_dir.join("front.htm")).await?; + let front = read_to_string(CONF.asset_path.join("front.htm")).await?; Ok(LayoutPage { title: "Home".to_string(), content: markup::new! { diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs index 866787a..20b451f 100644 --- a/server/src/routes/ui/player.rs +++ b/server/src/routes/ui/player.rs @@ -95,11 +95,11 @@ pub fn player_conf<'a>(item: Arc<Item>) -> MyResult<DynLayoutPage<'a>> { fieldset.subtitles { legend { "Subtitles" } - @for (i, (tid, track)) in sub_tracks.iter().enumerate() { - input[type="radio", id=tid, name="s", value=tid, checked=i==0]; + @for (_i, (tid, track)) in sub_tracks.iter().enumerate() { + input[type="radio", id=tid, name="s", value=tid]; label[for=tid] { @format!("{track}") } br; } - input[type="radio", id="s-none", name="s", value=""]; + input[type="radio", id="s-none", name="s", value="", checked=true]; label[for="s-none"] { "No subtitles" } } |