aboutsummaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-05 13:26:52 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-05 13:26:52 +0100
commit6b70b59d1c1e253d1837fa150460b61ab361aa13 (patch)
tree875e26916bb579bd8fb6e6d358549f0a6e6ef06a /server/src
parent51ba936859f14c2b39e2b181c16e4c024b93e71b (diff)
downloadjellything-6b70b59d1c1e253d1837fa150460b61ab361aa13.tar
jellything-6b70b59d1c1e253d1837fa150460b61ab361aa13.tar.bz2
jellything-6b70b59d1c1e253d1837fa150460b61ab361aa13.tar.zst
fix jellyfin auth
Diffstat (limited to 'server/src')
-rw-r--r--server/src/routes/compat/jellyfin/mod.rs30
-rw-r--r--server/src/routes/ui/account/session/guard.rs21
2 files changed, 42 insertions, 9 deletions
diff --git a/server/src/routes/compat/jellyfin/mod.rs b/server/src/routes/compat/jellyfin/mod.rs
index 08c8a7b..1ea83f9 100644
--- a/server/src/routes/compat/jellyfin/mod.rs
+++ b/server/src/routes/compat/jellyfin/mod.rs
@@ -26,7 +26,14 @@ use jellycommon::{
MediaInfo, Node, NodeID, NodeKind, SourceTrack, SourceTrackKind, Visibility,
};
use models::*;
-use rocket::{get, post, response::Redirect, serde::json::Json, FromForm, State};
+use rocket::{
+ get,
+ http::{Cookie, CookieJar},
+ post,
+ response::Redirect,
+ serde::json::Json,
+ FromForm, State,
+};
use serde::Deserialize;
use serde_json::{json, Value};
use std::{collections::BTreeMap, net::IpAddr};
@@ -68,8 +75,13 @@ pub fn r_jellyfin_users_public() -> Json<Value> {
Json(json!([]))
}
+#[get("/Branding/Css")]
+pub fn r_jellyfin_branding_css() -> String {
+ "".to_string()
+}
+
#[get("/QuickConnect/Enabled")]
-pub fn r_jellyfin_quickconnect_enabled(_session: Session) -> Json<Value> {
+pub fn r_jellyfin_quickconnect_enabled() -> Json<Value> {
Json(json!(false))
}
@@ -473,11 +485,6 @@ pub fn r_jellyfin_playback_bitratetest(_session: Session, Size: usize) -> Vec<u8
vec![0; Size.min(1_000_000)]
}
-#[get("/Branding/Css")]
-pub fn r_jellyfin_branding_css(_session: Session) -> String {
- "".to_string()
-}
-
#[post("/Sessions/Capabilities/Full")]
pub fn r_jellyfin_sessions_capabilities_full(_session: Session) -> () {
()
@@ -496,9 +503,18 @@ pub fn r_jellyfin_users_authenticatebyname(
client_addr: IpAddr,
database: &State<Database>,
data: Json<AuthData>,
+ jar: &CookieJar,
) -> MyResult<Json<Value>> {
let token = login_logic(database, &data.username, &data.pw, None, None)?;
+ // setting the session cookie too because image requests carry no auth headers for some reason.
+ // TODO find alternative, non-web clients might not understand cookies
+ jar.add(
+ Cookie::build(("session", token.clone()))
+ .permanent()
+ .build(),
+ );
+
Ok(Json(json!({
"User": user_object(data.username.clone()),
"SessionInfo": {
diff --git a/server/src/routes/ui/account/session/guard.rs b/server/src/routes/ui/account/session/guard.rs
index 3a3f6d7..f85dace 100644
--- a/server/src/routes/ui/account/session/guard.rs
+++ b/server/src/routes/ui/account/session/guard.rs
@@ -23,8 +23,14 @@ impl Session {
{
let token = req
.query_value("session")
- .or(req.query_value("api_key"))
- .or(req.headers().get_one("X-MediaBrowser-Token").map(Ok)) // for jellyfin compat
+ .or_else(|| req.query_value("api_key"))
+ .or_else(|| req.headers().get_one("X-MediaBrowser-Token").map(Ok))
+ .or_else(|| {
+ req.headers()
+ .get_one("Authorization")
+ .and_then(parse_jellyfin_auth)
+ .map(Ok)
+ }) // for jellyfin compat
.map(|e| e.expect("str parse should not fail, right?"))
.or(req.cookies().get("session").map(|cookie| cookie.value()))
.ok_or(anyhow!("not logged in"))?;
@@ -45,6 +51,17 @@ impl Session {
}
}
+fn parse_jellyfin_auth(h: &str) -> Option<&str> {
+ for tok in h.split(" ") {
+ if let Some(tok) = tok.strip_prefix("Token=\"") {
+ if let Some(tok) = tok.strip_suffix("\"") {
+ return Some(tok);
+ }
+ }
+ }
+ None
+}
+
#[async_trait]
impl<'r> FromRequest<'r> for Session {
type Error = MyError;