use crate::{
handlers::{handle_torrent_add, handle_torrent_get, handle_torrent_remove},
transmission::{TransmissionConfig, TransmissionRequest, TransmissionResponse},
AppData,
};
use actix_web::{
get,
http::header::{ContentType, Header},
post, web, HttpRequest, HttpResponse,
};
use actix_web_httpauth::headers::authorization::{Authorization, Basic};
use anyhow::{Context, Result, bail};
use serde_json::json;
const SESSION_ID: &str = "useless-session-id";
#[post("/transmission/rpc")]
pub(crate) async fn rpc_post(
payload: web::Json<TransmissionRequest>,
req: HttpRequest,
app_data: web::Data<AppData>,
) -> HttpResponse {
let putio_api_token = &app_data.config.putio.api_key;
if validate_user(req, &app_data).await.is_err() {
return HttpResponse::Conflict()
.content_type(ContentType::json())
.insert_header(("X-Transmission-Session-Id", SESSION_ID))
.body("");
}
let arguments = match payload.method.as_str() {
"session-get" => Some(json!(TransmissionConfig {
download_dir: app_data.config.download_directory.clone(),
..Default::default()
})),
"torrent-get" => handle_torrent_get(putio_api_token, &app_data).await,
"torrent-set" => None, "queue-move-top" => None,
"torrent-remove" => handle_torrent_remove(putio_api_token, &payload).await,
"torrent-add" => handle_torrent_add(putio_api_token, &payload).await,
_ => panic!("Unknwon method {}", payload.method),
};
let response = TransmissionResponse {
result: String::from("success"),
arguments,
};
HttpResponse::Ok()
.content_type(ContentType::json())
.json(response)
}
#[get("/transmission/rpc")]
async fn rpc_get(req: HttpRequest, app_data: web::Data<AppData>) -> HttpResponse {
if validate_user(req, &app_data).await.is_err() {
return HttpResponse::Forbidden().body("forbidden");
}
HttpResponse::Conflict()
.content_type(ContentType::json())
.insert_header(("X-Transmission-Session-Id", SESSION_ID))
.body("")
}
async fn validate_user(req: HttpRequest, app_data: &web::Data<AppData>) -> Result<()> {
let auth = Authorization::<Basic>::parse(&req)?;
let user_username = auth.as_ref().user_id();
let user_password = auth.as_ref().password().context("No password given")?;
if user_username == app_data.config.username && user_password == app_data.config.password {
Ok(())
} else {
bail!("Username or password mismatch")
}
}