aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/Cargo.toml4
-rw-r--r--server/src/config.rs2
-rw-r--r--server/src/routes/api/mod.rs24
-rw-r--r--server/src/routes/stream.rs30
-rw-r--r--server/src/routes/ui/account/mod.rs2
-rw-r--r--server/src/routes/ui/account/session/token.rs5
-rw-r--r--server/src/routes/ui/error.rs5
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}"))
+ }
+}