diff --git a/core/src/crypto/cert.rs b/core/src/crypto/cert.rs index cbf3186b..507b6ea6 100644 --- a/core/src/crypto/cert.rs +++ b/core/src/crypto/cert.rs @@ -51,6 +51,8 @@ pub fn public_key_from_cert_pem(cert: String) -> anyhow::Result { public_key_from_cert(parsed_cert) } +/// Extracts the public key from the certificate which is in DER format. +/// Encodes the public key in PEM format. pub fn public_key_from_cert_der(cert: &[u8]) -> anyhow::Result { let (_, parsed_cert) = X509Certificate::from_der(&cert)?; public_key_from_cert(parsed_cert) diff --git a/core/src/http/client/mod.rs b/core/src/http/client/mod.rs index 2cd0dcd1..5fdddae2 100644 --- a/core/src/http/client/mod.rs +++ b/core/src/http/client/mod.rs @@ -1,8 +1,9 @@ mod url; -use crate::http::{dto, StatusCodeError}; -use crate::model::discovery::{ProtocolType, RegisterDto, RegisterResponseDto}; -use crate::model::transfer::{PrepareUploadRequestDto, PrepareUploadResponseDto}; +use crate::http; +use crate::http::client::url::{ApiVersion, TargetUrl}; +use crate::http::dto::ProtocolType; +use crate::http::StatusCodeError; use crate::{crypto, util}; use futures_util::StreamExt; use lru::LruCache; @@ -12,7 +13,6 @@ use std::num::NonZeroUsize; use std::sync::Arc; use tokio::sync::{mpsc, Mutex}; use tokio_stream::wrappers::ReceiverStream; -use crate::http::client::url::{ApiVersion, TargetUrl}; const BASE_PATH: &str = "/api/localsend/v3"; @@ -33,7 +33,7 @@ pub struct RegisterResult { pub public_key: Option, /// The response body from the register request. - pub body: RegisterResponseDto, + pub body: http::dto::RegisterResponseDto, } impl LsHttpClient { @@ -73,19 +73,22 @@ impl LsHttpClient { let generated_nonce = crypto::nonce::generate_nonce(); let generated_nonce_base64 = util::base64::encode(&generated_nonce); - let request_body = dto::NonceRequest { + let request_body = http::dto::NonceRequest { nonce: generated_nonce_base64, }; let res = self .client - .post(TargetUrl { - version: ApiVersion::V3, - protocol: protocol.clone(), - host: ip.to_string(), - port, - path: "/nonce", - }.to_string()) + .post( + TargetUrl { + version: ApiVersion::V3, + protocol: protocol.clone(), + host: ip.to_string(), + port, + path: "/nonce", + } + .to_string(), + ) .body(serde_json::to_string(&request_body)?) .send() .await?; @@ -94,8 +97,8 @@ impl LsHttpClient { return Err(status_code_error_from_res(res).await?); } - let remote_key = to_remote_key(&res, protocol == &ProtocolType::Https, None)?; - let body = res.json::().await?; + let remote_key = to_identifier(&res, protocol == &ProtocolType::Https, None)?; + let body = res.json::().await?; // Save the response nonce and our generated nonce let response_nonce = util::base64::decode(&body.nonce)?; @@ -125,7 +128,7 @@ impl LsHttpClient { protocol: &ProtocolType, ip: &str, port: u16, - payload: RegisterDto, + payload: http::dto::RegisterDto, ) -> anyhow::Result { let res = self .client @@ -145,7 +148,7 @@ impl LsHttpClient { _ => None, }; - let body = res.json::().await?; + let body = res.json::().await?; Ok(RegisterResult { public_key, body }) } @@ -156,8 +159,8 @@ impl LsHttpClient { ip: &str, port: u16, public_key: Option, - payload: PrepareUploadRequestDto, - ) -> anyhow::Result { + payload: http::dto::PrepareUploadRequestDto, + ) -> anyhow::Result { let res = self .client .post(format!( @@ -179,7 +182,7 @@ impl LsHttpClient { return Err(status_code_error_from_res(res).await?); } - let body = res.json::().await?; + let body = res.json::().await?; Ok(body) } @@ -266,12 +269,17 @@ async fn status_code_error_from_res(response: Response) -> anyhow::Result) -> anyhow::Result { +fn to_identifier( + response: &Response, + require_cert: bool, + public_key: Option, +) -> anyhow::Result { match require_cert { true => verify_cert_from_res(response, public_key), - false => response.remote_addr().map(|addr| addr.ip().to_string()).ok_or_else(|| { - anyhow::anyhow!("Remote address not found in response") - }), + false => response + .remote_addr() + .map(|addr| addr.ip().to_string()) + .ok_or_else(|| anyhow::anyhow!("Remote address not found in response")), } } diff --git a/core/src/http/client/url.rs b/core/src/http/client/url.rs index 4db0871a..33ffe090 100644 --- a/core/src/http/client/url.rs +++ b/core/src/http/client/url.rs @@ -1,4 +1,4 @@ -use crate::model::discovery::ProtocolType; +use crate::http::dto::ProtocolType; use std::borrow::Cow; pub struct TargetUrl { diff --git a/core/src/http/dto.rs b/core/src/http/dto.rs index 40359913..c1598b3c 100644 --- a/core/src/http/dto.rs +++ b/core/src/http/dto.rs @@ -1,5 +1,7 @@ -use crate::model::discovery::{RegisterDto, RegisterResponseDto}; +use crate::model::discovery::DeviceType; +use crate::model::transfer::FileDto; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct NonceRequest { @@ -13,12 +15,85 @@ pub struct NonceResponse { pub nonce: String, } -pub type RegisterRequest = RegisterDto; - -pub type RegisterResponse = RegisterResponseDto; - #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct ErrorResponse { /// The error message. pub message: String, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RegisterDto { + pub alias: String, + + pub version: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub device_model: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub device_type: Option, + + pub token: String, + + pub port: u16, + + pub protocol: ProtocolType, + + #[serde(default, skip_serializing_if = "is_default")] + pub has_web_interface: bool, +} + +#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum ProtocolType { + Http, + Https, +} + +impl ProtocolType { + pub fn as_str(&self) -> &str { + match self { + ProtocolType::Http => "http", + ProtocolType::Https => "https", + } + } +} + +/// Similar to `RegisterDto`, but without `port` and `protocol` (those are already known). +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RegisterResponseDto { + pub alias: String, + + pub version: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub device_model: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub device_type: Option, + + pub token: String, + + #[serde(default, skip_serializing_if = "is_default")] + pub has_web_interface: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrepareUploadRequestDto { + pub info: RegisterDto, + pub files: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrepareUploadResponseDto { + pub session_id: String, + pub files: HashMap, +} + +fn is_default(t: &T) -> bool { + t == &T::default() +} diff --git a/core/src/http/mod.rs b/core/src/http/mod.rs index 43479ba8..9b450b64 100644 --- a/core/src/http/mod.rs +++ b/core/src/http/mod.rs @@ -1,9 +1,9 @@ -use serde::{Deserialize, Serialize}; use thiserror::Error; pub mod client; -pub mod server; pub mod dto; +pub mod server; +pub mod state; #[derive(Debug, Error)] #[error("{status};{message:?}")] diff --git a/core/src/http/server/collect_to_json.rs b/core/src/http/server/collect_to_json.rs index 1e2b63cc..f1569996 100644 --- a/core/src/http/server/collect_to_json.rs +++ b/core/src/http/server/collect_to_json.rs @@ -11,17 +11,9 @@ pub(crate) trait CollectToJson { impl CollectToJson for Incoming { async fn collect_to_json(self) -> Result { let bytes = self.collect().await?.to_bytes(); - let request = match serde_json::from_slice::(&bytes) { - Ok(json) => json, - Err(err) => { - tracing::warn!("Failed to parse JSON body: {err:#}"); - return Err(AppError::status( - StatusCode::BAD_REQUEST, - Some("Invalid JSON body".to_string()), - )); - } - }; - - Ok(request) + serde_json::from_slice::(&bytes).map_err(|err| { + tracing::warn!("Failed to parse JSON body: {err:#}"); + AppError::status(StatusCode::BAD_REQUEST, Some("Invalid JSON body".to_string())) + }) } } diff --git a/core/src/http/server/controller/mod.rs b/core/src/http/server/controller/mod.rs new file mode 100644 index 00000000..d6560b80 --- /dev/null +++ b/core/src/http/server/controller/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod v3; +pub(crate) mod web; diff --git a/core/src/http/server/controller/v3.rs b/core/src/http/server/controller/v3.rs new file mode 100644 index 00000000..3be98f03 --- /dev/null +++ b/core/src/http/server/controller/v3.rs @@ -0,0 +1,78 @@ +use hyper::body::Incoming; +use hyper::StatusCode; +use crate::http::dto::{NonceRequest, NonceResponse, RegisterDto, RegisterResponseDto}; +use crate::http::server::{AppState, RequestClientInfo, JsonResponse}; +use crate::http::server::error::AppError; +use crate::{crypto, util}; +use crate::http::server::collect_to_json::CollectToJson; + +pub(crate) async fn nonce_exchange( + body: Incoming, + state: AppState, + client_info: RequestClientInfo, +) -> Result, AppError> { + let payload = body.collect_to_json::().await?; + + let nonce = util::base64::decode(&payload.nonce).map_err(|_| { + tracing::warn!("Failed to decode nonce from base64"); + AppError::status( + StatusCode::BAD_REQUEST, + Some("Invalid nonce format".to_string()), + ) + })?; + + if !crypto::nonce::validate_nonce(&nonce) { + tracing::warn!("Invalid nonce received"); + return Err(AppError::status( + StatusCode::BAD_REQUEST, + Some("Invalid nonce".to_string()), + )); + } + + // Save the nonce + let remote_key = client_info.identifier(); + let mut received_nonce_map = state.received_nonce_map.lock().await; + received_nonce_map.put(remote_key.clone(), nonce); + + // Generate new nonce for the client + let new_nonce = crypto::nonce::generate_nonce(); + let new_nonce_base64 = util::base64::encode(&new_nonce); + let mut generated_nonce_map = state.generated_nonce_map.lock().await; + generated_nonce_map.put(remote_key.clone(), new_nonce); + + tracing::info!( + "Nonce exchange successful for client: {} (ID: {})", + client_info.ip, + remote_key + ); + + Ok(JsonResponse { + status: StatusCode::OK, + body: NonceResponse { + nonce: new_nonce_base64, + }, + }) +} + +pub(crate) async fn register( + body: Incoming, + state: AppState, + client_info: RequestClientInfo, +) -> Result, AppError> { + let payload = body.collect_to_json::().await?; + + let info = state.info.lock().await.clone(); + let has_web_interface = state.web.lock().await.is_some(); + + Ok(JsonResponse { + status: StatusCode::OK, + body: RegisterResponseDto { + alias: info.alias, + version: info.version, + device_model: info.device_model, + device_type: info.device_type, + token: info.token, + has_web_interface, + }, + }) +} diff --git a/core/src/http/server/controller/web.rs b/core/src/http/server/controller/web.rs new file mode 100644 index 00000000..1b524fdf --- /dev/null +++ b/core/src/http/server/controller/web.rs @@ -0,0 +1,2 @@ +#[derive(Clone, Debug)] +pub struct WebPageState; diff --git a/core/src/http/server/mod.rs b/core/src/http/server/mod.rs index 248ceb21..ab184289 100644 --- a/core/src/http/server/mod.rs +++ b/core/src/http/server/mod.rs @@ -1,34 +1,39 @@ mod client_cert_verifier; -mod error; mod collect_to_json; +mod controller; +mod error; use crate::crypto::cert::public_key_from_cert_der; -use crate::http::dto::{ErrorResponse, NonceRequest, NonceResponse, RegisterRequest, RegisterResponse}; +use crate::http::dto::ErrorResponse; use crate::http::server::client_cert_verifier::CustomClientCertVerifier; use crate::http::server::error::AppError; -use crate::{crypto, util}; +use crate::http::state::ClientInfo; use bytes::Bytes; use http_body_util::Full; -use hyper::body::{Body, Incoming}; +use hyper::body::Incoming; use hyper::{http, Method, Request, Response, StatusCode}; use hyper_util::rt::{TokioExecutor, TokioIo}; use hyper_util::server::conn::auto::Builder; use lru::LruCache; use rustls::pki_types::pem::PemObject; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use std::fmt::Debug; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::num::NonZeroUsize; use std::ops::Deref; use std::sync::Arc; use tokio::sync::{oneshot, Mutex}; -use uuid::Uuid; -use x509_parser::nom::Parser; -use crate::http::server::collect_to_json::CollectToJson; +use crate::http::server::controller::web::WebPageState; #[derive(Clone)] struct AppState { + /// Information about server's device. + info: Arc>, + + /// State for serving web pages. + web: Arc>>, + /// Maps client identifiers to nonces that have been received from remote. received_nonce_map: Arc>>>, @@ -37,8 +42,10 @@ struct AppState { } impl AppState { - fn new() -> Self { + fn new(info: Arc>) -> Self { Self { + info, + web: Arc::new(Mutex::new(None)), received_nonce_map: Arc::new(Mutex::new(LruCache::new( NonZeroUsize::new(200).unwrap(), ))), @@ -50,37 +57,46 @@ impl AppState { } pub struct LsHttpServer { + state: AppState, stop_tx: Arc>>>, } impl LsHttpServer { + /// Binds the server to the specified port on both IPv4 and IPv6 addresses. pub async fn start_with_port( port: u16, tls_config: Option, + info: ClientInfo, ) -> anyhow::Result { let ipv4_socket_addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port); let ipv6_socket_addr = SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), port); + let info = Arc::new(Mutex::new(info)); + let state = AppState::new(info.clone()); let (stop_tx, stop_rx) = oneshot::channel::<()>(); - tokio::spawn(async move { - tokio::select! { - result = start_server_with_addr(ipv4_socket_addr, tls_config.clone()) => { - tracing::info!("Server stopped on: {}, {:?}", ipv4_socket_addr, result); - } - _ = async { - if start_server_with_addr(ipv6_socket_addr, tls_config).await.is_err() { - tracing::warn!("Failed to start server on: {}", ipv6_socket_addr); - - // Keep the future running forever, so we continue using ipv4 only even if ipv6 fails. - tokio::time::sleep(std::time::Duration::from_secs(u64::MAX)).await; + tokio::spawn({ + let state = state.clone(); + async move { + tokio::select! { + _ = start_server_with_addr(ipv4_socket_addr, tls_config.clone(), state.clone()) => { + tracing::info!("Server stopped on: {}", ipv4_socket_addr); } - } => {} - _ = stop_rx => {} + _ = async { + if start_server_with_addr(ipv6_socket_addr, tls_config, state).await.is_err() { + tracing::warn!("Failed to start server on: {}", ipv6_socket_addr); + + // Keep the future running forever, so we continue using "ipv4 only" even if ipv6 fails. + tokio::time::sleep(std::time::Duration::from_secs(u64::MAX)).await; + } + } => {} + _ = stop_rx => {} + } } }); Ok(LsHttpServer { + state, stop_tx: Arc::new(Mutex::new(Some(stop_tx))), }) } @@ -107,11 +123,11 @@ pub struct TlsConfig { async fn start_server_with_addr( socket_addr: SocketAddr, tls_config: Option, + app_state: AppState, ) -> anyhow::Result<()> { let _ = rustls::crypto::ring::default_provider().install_default(); let incoming = tokio::net::TcpListener::bind(socket_addr).await?; - let app_state = AppState::new(); let tls_acceptor = match tls_config { Some(tls_config) => Some(create_tls_config(&tls_config).inspect_err(|err| { @@ -144,7 +160,7 @@ async fn start_server_with_addr( let client_info = { let (_, server_connection) = tls_stream.get_ref(); - ClientInfo { + RequestClientInfo { ip: remote_addr.ip(), cert: server_connection .deref() @@ -159,7 +175,7 @@ async fn start_server_with_addr( TokioIo::new(tls_stream), hyper::service::service_fn(move |mut req: Request| { req.extensions_mut() - .insert::(client_info.clone()); + .insert::(client_info.clone()); req.extensions_mut().insert::(app_state.clone()); handle_request(req) }), @@ -171,10 +187,12 @@ async fn start_server_with_addr( .serve_connection( TokioIo::new(tcp_stream), hyper::service::service_fn(move |mut req: Request| { - req.extensions_mut().insert::(ClientInfo { - ip: remote_addr.ip(), - cert: None, - }); + req.extensions_mut().insert::( + RequestClientInfo { + ip: remote_addr.ip(), + cert: None, + }, + ); req.extensions_mut().insert::(app_state.clone()); handle_request(req) }), @@ -205,7 +223,7 @@ fn create_tls_config(tls_config: &TlsConfig) -> anyhow::Result>, } -impl ClientInfo { +impl RequestClientInfo { fn extract_public_key(&self) -> Option { match &self.cert { Some(cert) => match public_key_from_cert_der(cert) { @@ -227,7 +245,7 @@ impl ClientInfo { } } - fn to_remote_key(&self) -> String { + fn identifier(&self) -> String { self.extract_public_key() .unwrap_or_else(|| self.ip.to_string()) } @@ -278,21 +296,25 @@ async fn handle_request_inner( return Err(AppError::status(StatusCode::INTERNAL_SERVER_ERROR, None)); }; - let Some(client_info) = req.extensions_mut().remove::() else { + let Some(client_info) = req.extensions_mut().remove::() else { return Err(AppError::status(StatusCode::INTERNAL_SERVER_ERROR, None)); }; match (req.method(), req.uri().path()) { (&Method::POST, "/api/localsend/v3/nonce") => { - Ok(nonce_exchange(req.into_body(), state, client_info) - .await? - .into_response()) + Ok( + controller::v3::nonce_exchange(req.into_body(), state, client_info) + .await? + .into_response(), + ) + } + (&Method::POST, "/api/localsend/v3/register") => { + Ok( + controller::v3::register(req.into_body(), state, client_info) + .await? + .into_response(), + ) } - // (&Method::POST, "/api/localsend/v3/register") => { - // Ok(register(req.into_body(), state, client_info) - // .await? - // .into_response()) - // } _ => { let mut res = Response::new(Full::default()); *res.status_mut() = StatusCode::NOT_FOUND; @@ -300,66 +322,3 @@ async fn handle_request_inner( } } } - -async fn nonce_exchange( - body: Incoming, - state: AppState, - client_info: ClientInfo, -) -> Result, AppError> { - let payload = body.collect_to_json::().await?; - - let nonce = util::base64::decode(&payload.nonce).map_err(|_| { - tracing::warn!("Failed to decode nonce from base64"); - AppError::status( - StatusCode::BAD_REQUEST, - Some("Invalid nonce format".to_string()), - ) - })?; - - if !crypto::nonce::validate_nonce(&nonce) { - tracing::warn!("Invalid nonce received"); - return Err(AppError::status( - StatusCode::BAD_REQUEST, - Some("Invalid nonce".to_string()), - )); - } - - // Save the nonce - let remote_key = client_info.to_remote_key(); - let mut received_nonce_map = state.received_nonce_map.lock().await; - received_nonce_map.put(remote_key.clone(), nonce); - - // Generate new nonce for the client - let new_nonce = crypto::nonce::generate_nonce(); - let new_nonce_base64 = util::base64::encode(&new_nonce); - let mut generated_nonce_map = state.generated_nonce_map.lock().await; - generated_nonce_map.put(remote_key.clone(), new_nonce); - - tracing::info!( - "Nonce exchange successful for client: {} (ID: {})", - client_info.ip, - remote_key - ); - - Ok(JsonResponse { - status: StatusCode::OK, - body: NonceResponse { - nonce: new_nonce_base64, - }, - }) -} - -// async fn register( -// body: Incoming, -// state: AppState, -// client_info: ClientInfo, -// ) -> Result, AppError> { -// let payload = body.collect_to_json::().await?; -// -// Ok(JsonResponse { -// status: StatusCode::OK, -// body: RegisterResponse { -// token: payload.token, -// }, -// }) -// } diff --git a/core/src/http/state.rs b/core/src/http/state.rs new file mode 100644 index 00000000..bfb8efd9 --- /dev/null +++ b/core/src/http/state.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; +use crate::model::discovery::DeviceType; + +#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct ClientInfo { + /// The name of the peer. + pub alias: String, + + /// Client Protocol Version (major.minor) + pub version: String, + + /// The device model of the peer. + /// Windows, macOS, iPhone, Samsung, etc. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_model: Option, + + /// The device type of the peer. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_type: Option, + + /// A token generated by the client. + /// Used to merge the same peers detected on different channels (LAN, WebRTC, etc.). + pub token: String, +} diff --git a/core/src/main.rs b/core/src/main.rs index f887a806..678bf7d9 100644 --- a/core/src/main.rs +++ b/core/src/main.rs @@ -7,8 +7,7 @@ mod webrtc; use crate::crypto::token; use crate::http::client::LsHttpClient; use crate::http::server::TlsConfig; -use crate::model::discovery::{DeviceType, ProtocolType, RegisterDto}; -use crate::model::transfer::PrepareUploadRequestDto; +use crate::model::discovery::DeviceType; use crate::webrtc::signaling::{ClientInfo, WsServerMessage}; use crate::webrtc::webrtc::{PinConfig, RTCFile, RTCFileError, RTCSendFileResponse, RTCStatus}; use anyhow::Result; @@ -20,6 +19,7 @@ use tokio::io; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::sync::{mpsc, oneshot}; use tracing::Level; +use crate::http::dto::{PrepareUploadRequestDto, ProtocolType, RegisterDto}; #[tokio::main] #[cfg(feature = "full")] @@ -127,12 +127,20 @@ MCowBQYDK2VwAyEAZmdXP230oqK92o65ra3XaF2F8r3+fK5DEBK4c40qVts= } async fn server_test() -> Result<()> { + let client_info = http::state::ClientInfo { + alias: "Server-Test".to_string(), + version: "1.2.3".to_string(), + device_model: None, + device_type: None, + token: "456".to_string(), + }; let server = http::server::LsHttpServer::start_with_port( 53317, Some(TlsConfig { cert: CERT.to_string(), private_key: PRIVATE_KEY.to_string(), }), + client_info, ) .await?; tokio::time::sleep(std::time::Duration::from_secs(u64::MAX)).await; @@ -156,10 +164,10 @@ async fn client_test() -> Result<()> { version: "2.3".to_string(), device_model: Some("test".to_string()), device_type: Some(DeviceType::Headless), - fingerprint: "test".to_string(), + token: "test".to_string(), port: 53317, protocol: ProtocolType::Https, - download: false, + has_web_interface: false, }; let response = client @@ -179,7 +187,7 @@ async fn client_test() -> Result<()> { files: { let mut map = HashMap::new(); let id = "test-123-id".to_string(); - let file = crate::model::transfer::FileDto { + let file = model::transfer::FileDto { id: id.clone(), file_name: "test.mp4".to_string(), size: 1000, diff --git a/core/src/model/discovery.rs b/core/src/model/discovery.rs index 0bd07fd4..e95afa51 100644 --- a/core/src/model/discovery.rs +++ b/core/src/model/discovery.rs @@ -1,34 +1,5 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RegisterDto { - pub alias: String, - pub version: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub device_model: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub device_type: Option, - pub fingerprint: String, - pub port: u16, - pub protocol: ProtocolType, - pub download: bool, -} - -/// Similar to `RegisterDto`, but without `port` and `protocol` (those are already known). -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RegisterResponseDto { - pub alias: String, - pub version: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub device_model: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub device_type: Option, - pub fingerprint: String, - pub download: bool, -} - #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum DeviceType { @@ -38,19 +9,3 @@ pub enum DeviceType { Headless, Server, } - -#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] -pub enum ProtocolType { - Http, - Https, -} - -impl ProtocolType { - pub fn as_str(&self) -> &str { - match self { - ProtocolType::Http => "http", - ProtocolType::Https => "https", - } - } -} diff --git a/core/src/model/transfer.rs b/core/src/model/transfer.rs index 24610555..0f9d25ed 100644 --- a/core/src/model/transfer.rs +++ b/core/src/model/transfer.rs @@ -1,6 +1,4 @@ -use crate::model::discovery::RegisterDto; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -24,17 +22,3 @@ pub struct FileMetadata { #[serde(skip_serializing_if = "Option::is_none")] pub accessed: Option, } - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PrepareUploadRequestDto { - pub info: RegisterDto, - pub files: HashMap, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PrepareUploadResponseDto { - pub session_id: String, - pub files: HashMap, -}