diff --git a/desktop/drop-base b/desktop/drop-base index 26698e5b..04125e89 160000 --- a/desktop/drop-base +++ b/desktop/drop-base @@ -1 +1 @@ -Subproject commit 26698e5b069d463b9a02a3dd61e4888d28fa9f88 +Subproject commit 04125e89bef517411e103cdabcfa64a1bb563423 diff --git a/desktop/src-tauri/src/games/collections/commands.rs b/desktop/src-tauri/src/games/collections/commands.rs index 7f815287..bff8928c 100644 --- a/desktop/src-tauri/src/games/collections/commands.rs +++ b/desktop/src-tauri/src/games/collections/commands.rs @@ -1,19 +1,18 @@ -use reqwest::blocking::Client; use serde_json::json; use url::Url; use crate::{ + DB, database::db::DatabaseImpls, error::remote_access_error::RemoteAccessError, - remote::{auth::generate_authorization_header, requests::make_request}, - DB, + remote::{auth::generate_authorization_header, requests::make_request, utils::DROP_CLIENT_SYNC}, }; use super::collection::{Collection, Collections}; #[tauri::command] pub fn fetch_collections() -> Result { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request(&client, &["/api/v1/client/collection"], &[], |r| { r.header("Authorization", generate_authorization_header()) })? @@ -24,7 +23,7 @@ pub fn fetch_collections() -> Result { #[tauri::command] pub fn fetch_collection(collection_id: String) -> Result { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request( &client, &["/api/v1/client/collection/", &collection_id], @@ -38,7 +37,7 @@ pub fn fetch_collection(collection_id: String) -> Result Result { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let base_url = DB.fetch_base_url(); let base_url = Url::parse(&format!("{base_url}api/v1/client/collection/"))?; @@ -57,7 +56,7 @@ pub fn add_game_to_collection( collection_id: String, game_id: String, ) -> Result<(), RemoteAccessError> { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let url = Url::parse(&format!( "{}api/v1/client/collection/{}/entry/", DB.fetch_base_url(), @@ -74,7 +73,7 @@ pub fn add_game_to_collection( #[tauri::command] pub fn delete_collection(collection_id: String) -> Result { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let base_url = Url::parse(&format!( "{}api/v1/client/collection/{}", DB.fetch_base_url(), @@ -93,7 +92,7 @@ pub fn delete_game_in_collection( collection_id: String, game_id: String, ) -> Result<(), RemoteAccessError> { - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let base_url = Url::parse(&format!( "{}api/v1/client/collection/{}/entry", DB.fetch_base_url(), diff --git a/desktop/src-tauri/src/games/downloads/download_agent.rs b/desktop/src-tauri/src/games/downloads/download_agent.rs index cc00a0bf..0f4912b9 100644 --- a/desktop/src-tauri/src/games/downloads/download_agent.rs +++ b/desktop/src-tauri/src/games/downloads/download_agent.rs @@ -15,6 +15,7 @@ use crate::games::downloads::manifest::{DropDownloadContext, DropManifest}; use crate::games::downloads::validate::game_validate_logic; use crate::games::library::{on_game_complete, on_game_incomplete, push_game_update}; use crate::remote::requests::make_request; +use crate::remote::utils::DROP_CLIENT_SYNC; use log::{debug, error, info}; use rayon::ThreadPoolBuilder; use std::collections::HashMap; @@ -135,7 +136,7 @@ impl GameDownloadAgent { fn download_manifest(&self) -> Result<(), ApplicationDownloadError> { let header = generate_authorization_header(); - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request( &client, &["/api/v1/client/game/manifest"], @@ -267,7 +268,7 @@ impl GameDownloadAgent { let contexts = self.contexts.lock().unwrap(); debug!("{contexts:#?}"); pool.scope(|scope| { - let client = &reqwest::blocking::Client::new(); + let client = &DROP_CLIENT_SYNC.clone(); let context_map = self.context_map.lock().unwrap(); for (index, context) in contexts.iter().enumerate() { let client = client.clone(); diff --git a/desktop/src-tauri/src/games/library.rs b/desktop/src-tauri/src/games/library.rs index f7c80d73..08429590 100644 --- a/desktop/src-tauri/src/games/library.rs +++ b/desktop/src-tauri/src/games/library.rs @@ -18,6 +18,7 @@ use crate::games::state::{GameStatusManager, GameStatusWithTransient}; use crate::remote::auth::generate_authorization_header; use crate::remote::cache::{cache_object, get_cached_object, get_cached_object_db}; use crate::remote::requests::make_request; +use crate::remote::utils::DROP_CLIENT_SYNC; use crate::AppState; use bitcode::{Encode, Decode}; @@ -78,7 +79,7 @@ pub fn fetch_library_logic( ) -> Result, RemoteAccessError> { let header = generate_authorization_header(); - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request(&client, &["/api/v1/client/user/library"], &[], |f| { f.header("Authorization", header) })? @@ -177,7 +178,7 @@ pub fn fetch_game_logic( return Ok(data); } - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request(&client, &["/api/v1/client/game/", &id], &[], |r| { r.header("Authorization", generate_authorization_header()) })? @@ -252,7 +253,7 @@ pub fn fetch_game_verion_options_logic( game_id: String, state: tauri::State<'_, Mutex>, ) -> Result, RemoteAccessError> { - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request( &client, @@ -378,7 +379,7 @@ pub fn on_game_incomplete( return Err(RemoteAccessError::GameNotFound(meta.id.clone())); } - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request( &client, &["/api/v1/client/game/version"], @@ -440,7 +441,7 @@ pub fn on_game_complete( let header = generate_authorization_header(); - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request( &client, &["/api/v1/client/game/version"], diff --git a/desktop/src-tauri/src/remote/auth.rs b/desktop/src-tauri/src/remote/auth.rs index 712f3233..e66b3613 100644 --- a/desktop/src-tauri/src/remote/auth.rs +++ b/desktop/src-tauri/src/remote/auth.rs @@ -9,12 +9,10 @@ use tauri::{AppHandle, Emitter, Manager}; use url::Url; use crate::{ - AppState, AppStatus, User, database::{ db::{borrow_db_checked, borrow_db_mut_checked}, models::data::DatabaseAuth, - }, - error::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError}, + }, error::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError}, remote::utils::DROP_CLIENT_SYNC, AppState, AppStatus, User }; use super::{ @@ -66,7 +64,7 @@ pub fn generate_authorization_header() -> String { pub fn fetch_user() -> Result { let header = generate_authorization_header(); - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = make_request(&client, &["/api/v1/client/user"], &[], |f| { f.header("Authorization", header) })? @@ -107,7 +105,7 @@ fn recieve_handshake_logic(app: &AppHandle, path: String) -> Result<(), RemoteAc }; let endpoint = base_url.join("/api/v1/client/auth/handshake")?; - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = client.post(endpoint).json(&body).send()?; debug!("handshake responsded with {}", response.status().as_u16()); if !response.status().is_success() { @@ -186,7 +184,7 @@ pub fn auth_initiate_logic(mode: String) -> Result { mode, }; - let client = reqwest::blocking::Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = client.post(endpoint.to_string()).json(&body).send()?; if response.status() != 200 { diff --git a/desktop/src-tauri/src/remote/commands.rs b/desktop/src-tauri/src/remote/commands.rs index 8b4e98e0..7b1bd6ee 100644 --- a/desktop/src-tauri/src/remote/commands.rs +++ b/desktop/src-tauri/src/remote/commands.rs @@ -2,17 +2,13 @@ use std::sync::Mutex; use futures_lite::StreamExt; use log::{debug, warn}; -use reqwest::blocking::Client; use reqwest_websocket::{Message, RequestBuilderExt}; use serde::Deserialize; use tauri::{AppHandle, Emitter, Manager}; use url::Url; use crate::{ - AppState, AppStatus, - database::db::{borrow_db_checked, borrow_db_mut_checked}, - error::remote_access_error::RemoteAccessError, - remote::{auth::generate_authorization_header, requests::make_request}, + database::db::{borrow_db_checked, borrow_db_mut_checked}, error::remote_access_error::RemoteAccessError, remote::{auth::generate_authorization_header, requests::make_request, utils::DROP_CLIENT_SYNC}, AppState, AppStatus }; use super::{ @@ -45,7 +41,7 @@ pub fn gen_drop_url(path: String) -> Result { #[tauri::command] pub fn fetch_drop_object(path: String) -> Result, RemoteAccessError> { let _drop_url = gen_drop_url(path.clone())?; - let req = make_request(&Client::new(), &[&path], &[], |r| { + let req = make_request(&DROP_CLIENT_SYNC, &[&path], &[], |r| { r.header("Authorization", generate_authorization_header()) })? .send(); diff --git a/desktop/src-tauri/src/remote/fetch_object.rs b/desktop/src-tauri/src/remote/fetch_object.rs index 964769cd..4b5d7fbd 100644 --- a/desktop/src-tauri/src/remote/fetch_object.rs +++ b/desktop/src-tauri/src/remote/fetch_object.rs @@ -2,7 +2,7 @@ use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder}; use log::warn; use tauri::UriSchemeResponder; -use crate::{DB, database::db::DatabaseImpls}; +use crate::{database::db::DatabaseImpls, remote::utils::DROP_CLIENT_ASYNC, DB}; use super::{ auth::generate_authorization_header, @@ -22,7 +22,7 @@ pub async fn fetch_object(request: http::Request>, responder: UriSchemeR } let header = generate_authorization_header(); - let client = reqwest::Client::new(); + let client = DROP_CLIENT_ASYNC.clone(); let url = format!("{}api/v1/client/object/{object_id}", DB.fetch_base_url()); let response = client.get(url).header("Authorization", header).send().await; diff --git a/desktop/src-tauri/src/remote/server_proto.rs b/desktop/src-tauri/src/remote/server_proto.rs index 26c0e154..d3c87afa 100644 --- a/desktop/src-tauri/src/remote/server_proto.rs +++ b/desktop/src-tauri/src/remote/server_proto.rs @@ -1,10 +1,9 @@ use std::str::FromStr; use http::{uri::PathAndQuery, Request, Response, StatusCode, Uri}; -use reqwest::blocking::Client; use tauri::UriSchemeResponder; -use crate::database::db::borrow_db_checked; +use crate::{database::db::borrow_db_checked, remote::utils::DROP_CLIENT_SYNC}; pub fn handle_server_proto_offline(_request: Request>, responder: UriSchemeResponder) { let four_oh_four = Response::builder() @@ -38,7 +37,7 @@ pub fn handle_server_proto(request: Request>, responder: UriSchemeRespon return; } - let client = Client::new(); + let client = DROP_CLIENT_SYNC.clone(); let response = client .request(request.method().clone(), new_uri.to_string()) .header("Authorization", format!("Bearer {web_token}")) diff --git a/desktop/src-tauri/src/remote/utils.rs b/desktop/src-tauri/src/remote/utils.rs index baf8dada..591da9ad 100644 --- a/desktop/src-tauri/src/remote/utils.rs +++ b/desktop/src-tauri/src/remote/utils.rs @@ -1,12 +1,18 @@ -use std::sync::Mutex; +use std::{ + fs::{self, File}, + io::Read, + sync::{LazyLock, Mutex}, +}; -use log::{debug, warn}; +use log::{debug, info, warn}; +use reqwest::Certificate; use serde::Deserialize; use url::Url; use crate::{ - database::db::borrow_db_mut_checked, error::remote_access_error::RemoteAccessError, AppState, - AppStatus, + AppState, AppStatus, + database::db::{DATA_ROOT_DIR, borrow_db_mut_checked}, + error::remote_access_error::RemoteAccessError, }; #[derive(Deserialize)] @@ -15,6 +21,60 @@ struct DropHealthcheck { app_name: String, } +pub static DROP_CLIENT_SYNC: LazyLock = LazyLock::new(get_client_sync); +pub static DROP_CLIENT_ASYNC: LazyLock = LazyLock::new(get_client_async); + +fn fetch_certificates() -> Vec { + let certificate_dir = DATA_ROOT_DIR.join("certificates"); + + let mut certs = Vec::new(); + match fs::read_dir(certificate_dir) { + Ok(c) => { + for entry in c { + match entry { + Ok(c) => { + let mut buf = Vec::new(); + File::open(c.path()).unwrap().read_to_end(&mut buf).unwrap(); + + for cert in Certificate::from_pem_bundle(&buf).unwrap() { + certs.push(cert); + } + info!( + "added {} certificate(s) from {}", + certs.len(), + c.file_name().into_string().unwrap() + ); + } + Err(_) => todo!(), + } + } + } + Err(e) => { + debug!("not loading certificates due to error: {e}"); + } + }; + certs +} + +pub fn get_client_sync() -> reqwest::blocking::Client { + let mut client = reqwest::blocking::ClientBuilder::new(); + + let certs = fetch_certificates(); + for cert in certs { + client = client.add_root_certificate(cert); + } + client.build().unwrap() +} +pub fn get_client_async() -> reqwest::Client { + let mut client = reqwest::ClientBuilder::new(); + + let certs = fetch_certificates(); + for cert in certs { + client = client.add_root_certificate(cert); + } + client.build().unwrap() +} + pub fn use_remote_logic( url: String, state: tauri::State<'_, Mutex>>, @@ -24,7 +84,8 @@ pub fn use_remote_logic( // Test Drop url let test_endpoint = base_url.join("/api/v1")?; - let response = reqwest::blocking::get(test_endpoint.to_string())?; + let client = DROP_CLIENT_SYNC.clone(); + let response = client.get(test_endpoint.to_string()).send()?; let result: DropHealthcheck = response.json()?;