diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/Cargo.toml | 4 | ||||
-rw-r--r-- | server/src/config.rs | 2 | ||||
-rw-r--r-- | server/src/routes/api/mod.rs | 24 | ||||
-rw-r--r-- | server/src/routes/stream.rs | 30 | ||||
-rw-r--r-- | server/src/routes/ui/account/mod.rs | 2 | ||||
-rw-r--r-- | server/src/routes/ui/account/session/token.rs | 5 | ||||
-rw-r--r-- | server/src/routes/ui/error.rs | 5 |
7 files changed, 60 insertions, 12 deletions
diff --git a/server/Cargo.toml b/server/Cargo.toml index 13b7aef..4617a18 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -24,10 +24,12 @@ argon2 = "0.5.0" aes-gcm-siv = "0.11.1" async-std = "1.12.0" -rocket = { version = "0.5.0-rc.3", features = ["secrets", "json"] } tokio = { version = "1.28.2", features = ["io-util"] } tokio-util = { version = "0.7.8", features = ["io", "io-util"] } + markup = "0.13.1" +rocket = { version = "0.5.0-rc.3", features = ["secrets", "json"] } +reqwest = "0.11.18" sled = "0.34.7" typed-sled = "0.2.3" diff --git a/server/src/config.rs b/server/src/config.rs index 0417878..05c56bc 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -19,7 +19,7 @@ pub struct GlobalConfig { pub admin_password: String, pub cookie_key: String, pub login_expire: i64, - pub remote_credentials: HashMap<String, (String, String)>, + pub remote_credentials: HashMap<String, (String, String, bool)>, } pub fn load_global_config() -> GlobalConfig { diff --git a/server/src/routes/api/mod.rs b/server/src/routes/api/mod.rs index b39950c..84dd6a8 100644 --- a/server/src/routes/api/mod.rs +++ b/server/src/routes/api/mod.rs @@ -9,6 +9,7 @@ use super::ui::{ error::MyResult, }; use crate::database::Database; +use reqwest::Client; use rocket::{get, post, response::Redirect, serde::json::Json, State}; use serde_json::{json, Value}; @@ -27,3 +28,26 @@ pub fn r_api_account_login(database: &State<Database>, data: Json<LoginForm>) -> let token = login_logic(database, &data.username, &data.password)?; Ok(json!(token)) } +pub async fn c_api_account_login( + host: &str, + tls: bool, + username: String, + password: String, + expire: u64, +) -> MyResult<String> { + Ok(Client::builder() + .build()? + .post(format!( + "{}://{host}/api/account/login", + if tls { "https" } else { "http" } + )) + .body(serde_json::to_string(&LoginForm { + expire, + password, + username, + })?) + .send() + .await? + .json() + .await?) +} diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs index 6e60cc9..19a3f09 100644 --- a/server/src/routes/stream.rs +++ b/server/src/routes/stream.rs @@ -4,7 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use super::ui::{account::session::Session, error::MyError}; -use crate::{database::Database, CONF}; +use crate::{database::Database, routes::api::c_api_account_login, uri, CONF}; use anyhow::{anyhow, Result}; use jellycommon::MediaSource; use jellyremuxer::RemuxerContext; @@ -13,8 +13,8 @@ use rocket::{ get, http::{ContentType, Header, Status}, request::{self, FromRequest}, - response::{self, Responder}, - Request, Response, State, + response::{self, Redirect, Responder}, + Either, Request, Response, State, }; use std::ops::{Deref, Range}; use tokio::io::{duplex, DuplexStream}; @@ -34,7 +34,7 @@ pub fn stream_uri(id: &str, tracks: &[u64], webm: bool) -> String { } #[get("/n/<id>/stream?<tracks>&<webm>")] -pub fn r_stream( +pub async fn r_stream( _sess: Session, id: String, webm: Option<bool>, @@ -42,7 +42,7 @@ pub fn r_stream( remuxer: &State<RemuxerContext>, db: &State<Database>, range: Option<RequestRange>, -) -> Result<StreamResponse, MyError> { +) -> Result<Either<StreamResponse, Redirect>, MyError> { let node = db.node.get(&id)?.ok_or(anyhow!("node does not exist"))?; let source = node .private @@ -51,7 +51,23 @@ pub fn r_stream( let source_tracks = match source { MediaSource::Local { tracks } => tracks, - _ => Err(anyhow!("todo"))?, + MediaSource::Remote { host, remote_id } => { + let (username, password, tls) = CONF + .remote_credentials + .get(&host) + .ok_or(anyhow!("no credentials on the server-side"))?; + let token = + c_api_account_login(&host, false, username.to_owned(), password.to_owned(), 60) + .await?; + + let uri = format!( + "{}://{host}{}&session={}", + if *tls { "https" } else { "http" }, + uri!(r_stream(remote_id, tracks, webm)), + token + ); + return Ok(Either::Right(Redirect::found(uri))); + } }; info!( @@ -94,7 +110,7 @@ pub fn r_stream( } }); debug!("starting stream"); - Ok(StreamResponse { stream: a, range }) + Ok(Either::Left(StreamResponse { stream: a, range })) } pub struct StreamResponse { diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index f1b243c..1d36cd8 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -65,6 +65,8 @@ pub struct LoginForm { pub username: String, #[field(validate = len(..64))] pub password: String, + #[field(default = 604800)] // one week + pub expire: u64, } #[get("/account/login")] diff --git a/server/src/routes/ui/account/session/token.rs b/server/src/routes/ui/account/session/token.rs index d4546aa..f82b475 100644 --- a/server/src/routes/ui/account/session/token.rs +++ b/server/src/routes/ui/account/session/token.rs @@ -24,17 +24,16 @@ pub fn create(username: String, expire: Duration) -> String { let cipher = aes_gcm_siv::Aes256GcmSiv::new_from_slice(&*SESSION_KEY).unwrap(); let nonce = [(); 12].map(|_| rand::random()); - eprintln!("SESSION_KEY={SESSION_KEY:?}"); let mut ciphertext = cipher .encrypt(&GenericArray::from(nonce), plaintext.as_slice()) .unwrap(); ciphertext.extend(nonce); - base64::engine::general_purpose::STANDARD.encode(&ciphertext) + base64::engine::general_purpose::URL_SAFE.encode(&ciphertext) } pub fn validate(token: &str) -> anyhow::Result<String> { - let ciphertext = base64::engine::general_purpose::STANDARD.decode(token)?; + let ciphertext = base64::engine::general_purpose::URL_SAFE.decode(token)?; let cipher = aes_gcm_siv::Aes256GcmSiv::new_from_slice(&*SESSION_KEY).unwrap(); let (ciphertext, nonce) = ciphertext.split_at(ciphertext.len() - 12); let plaintext = cipher diff --git a/server/src/routes/ui/error.rs b/server/src/routes/ui/error.rs index 190650f..d911a41 100644 --- a/server/src/routes/ui/error.rs +++ b/server/src/routes/ui/error.rs @@ -91,3 +91,8 @@ impl From<serde_json::Error> for MyError { MyError(anyhow::anyhow!("{err}")) } } +impl From<reqwest::Error> for MyError { + fn from(err: reqwest::Error) -> Self { + MyError(anyhow::anyhow!("{err}")) + } +} |