From 525f458a859a3bc132c0e6acf11d9ed3727c2d13 Mon Sep 17 00:00:00 2001 From: Huakun Shen Date: Mon, 9 Dec 2024 02:52:22 -0500 Subject: [PATCH] feat(upload): added ssl cert options to upload and download function --- plugins/upload/api-iife.js | 2 +- plugins/upload/guest-js/index.ts | 20 ++++++++++++++++---- plugins/upload/src/lib.rs | 29 ++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/plugins/upload/api-iife.js b/plugins/upload/api-iife.js index 5918901f7..4d164ca16 100644 --- a/plugins/upload/api-iife.js +++ b/plugins/upload/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_PLUGIN_UPLOAD__=function(t){"use strict";function e(t,e,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!o:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(t):o?o.value:e.get(t)}function n(t,e,n,o,s){if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,n),n}var o,s,r;"function"==typeof SuppressedError&&SuppressedError;const i="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,o.set(this,(()=>{})),s.set(this,0),r.set(this,{}),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:i})=>{if(i===e(this,s,"f")){n(this,s,i+1),e(this,o,"f").call(this,t);const a=Object.keys(e(this,r,"f"));if(a.length>0){let t=i+1;for(const n of a.sort()){if(parseInt(n)!==t)break;{const s=e(this,r,"f")[n];delete e(this,r,"f")[n],e(this,o,"f").call(this,s),t+=1}}n(this,s,t)}}else e(this,r,"f")[i.toString()]=t}))}set onmessage(t){n(this,o,t)}get onmessage(){return e(this,o,"f")}[(o=new WeakMap,s=new WeakMap,r=new WeakMap,i)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[i]()}}async function _(t,e={},n){return window.__TAURI_INTERNALS__.invoke(t,e,n)}return t.download=async function(t,e,n,o,s){const r=new Uint32Array(1);window.crypto.getRandomValues(r);const i=r[0],c=new a;n&&(c.onmessage=n),await _("plugin:upload|download",{id:i,url:t,filePath:e,headers:o??{},onProgress:c,body:s})},t.upload=async function(t,e,n,o){const s=new Uint32Array(1);window.crypto.getRandomValues(s);const r=s[0],i=new a;return n&&(i.onmessage=n),await _("plugin:upload|upload",{id:r,url:t,filePath:e,headers:o??{},onProgress:i})},t}({});Object.defineProperty(window.__TAURI__,"upload",{value:__TAURI_PLUGIN_UPLOAD__})} +if("__TAURI__"in window){var __TAURI_PLUGIN_UPLOAD__=function(t){"use strict";function e(t,e,s,r){if("a"===s&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!r:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?r:"a"===s?r.call(t):r?r.value:e.get(t)}function s(t,e,s,r,n){if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,s),s}var r,n,o;"function"==typeof SuppressedError&&SuppressedError;const i="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,r.set(this,(()=>{})),n.set(this,0),o.set(this,{}),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:i})=>{if(i===e(this,n,"f")){s(this,n,i+1),e(this,r,"f").call(this,t);const a=Object.keys(e(this,o,"f"));if(a.length>0){let t=i+1;for(const s of a.sort()){if(parseInt(s)!==t)break;{const n=e(this,o,"f")[s];delete e(this,o,"f")[s],e(this,r,"f").call(this,n),t+=1}}s(this,n,t)}}else e(this,o,"f")[i.toString()]=t}))}set onmessage(t){s(this,r,t)}get onmessage(){return e(this,r,"f")}[(r=new WeakMap,n=new WeakMap,o=new WeakMap,i)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[i]()}}async function _(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}return t.download=async function(t,e,s,r,n,o){const i=new Uint32Array(1);window.crypto.getRandomValues(i);const c=i[0],l=new a;s&&(l.onmessage=s),await _("plugin:upload|download",{id:c,url:t,filePath:e,headers:r??{},onProgress:l,body:n,skipSslCertCheck:o?.skipSslCertCheck,trustSslCert:o?.trustSslCert})},t.upload=async function(t,e,s,r,n){const o=new Uint32Array(1);window.crypto.getRandomValues(o);const i=o[0],c=new a;return s&&(c.onmessage=s),await _("plugin:upload|upload",{id:i,url:t,filePath:e,headers:r??{},onProgress:c,skipSslCertCheck:n?.skipSslCertCheck,trustSslCert:n?.trustSslCert})},t}({});Object.defineProperty(window.__TAURI__,"upload",{value:__TAURI_PLUGIN_UPLOAD__})} diff --git a/plugins/upload/guest-js/index.ts b/plugins/upload/guest-js/index.ts index 03129db4b..ede164a65 100644 --- a/plugins/upload/guest-js/index.ts +++ b/plugins/upload/guest-js/index.ts @@ -17,7 +17,11 @@ async function upload( url: string, filePath: string, progressHandler?: ProgressHandler, - headers?: Map + headers?: Map, + options?: { + skipSslCertCheck?: boolean + trustSslCert?: string + } ): Promise { const ids = new Uint32Array(1) window.crypto.getRandomValues(ids) @@ -33,7 +37,9 @@ async function upload( url, filePath, headers: headers ?? {}, - onProgress + onProgress, + skipSslCertCheck: options?.skipSslCertCheck, + trustSslCert: options?.trustSslCert }) } @@ -46,7 +52,11 @@ async function download( filePath: string, progressHandler?: ProgressHandler, headers?: Map, - body?: string + body?: string, + options?: { + skipSslCertCheck?: boolean + trustSslCert?: string + } ): Promise { const ids = new Uint32Array(1) window.crypto.getRandomValues(ids) @@ -63,7 +73,9 @@ async function download( filePath, headers: headers ?? {}, onProgress, - body + body, + skipSslCertCheck: options?.skipSslCertCheck, + trustSslCert: options?.trustSslCert }) } diff --git a/plugins/upload/src/lib.rs b/plugins/upload/src/lib.rs index 23c33b115..275943eca 100644 --- a/plugins/upload/src/lib.rs +++ b/plugins/upload/src/lib.rs @@ -64,6 +64,23 @@ struct ProgressPayload { transfer_speed: u64, } +fn build_client( + skip_ssl_cert_check: Option, + trust_ssl_cert: Option, +) -> Result { + let mut client_builder = reqwest::Client::builder(); + if skip_ssl_cert_check.unwrap_or(false) { + client_builder = client_builder.danger_accept_invalid_certs(true); + } + if let Some(cert) = match trust_ssl_cert { + Some(cert) => reqwest::tls::Certificate::from_pem(cert.as_bytes()).ok(), + None => None, + } { + client_builder = client_builder.add_root_certificate(cert); + } + client_builder.build().map_err(Into::into) +} + #[command] async fn download( url: &str, @@ -71,8 +88,10 @@ async fn download( headers: HashMap, body: Option, on_progress: Channel, + skip_ssl_cert_check: Option, + trust_ssl_cert: Option, ) -> Result<()> { - let client = reqwest::Client::new(); + let client = build_client(skip_ssl_cert_check, trust_ssl_cert)?; let mut request = if let Some(body) = body { client.post(url).body(body) } else { @@ -118,13 +137,13 @@ async fn upload( file_path: &str, headers: HashMap, on_progress: Channel, + skip_ssl_cert_check: Option, + trust_ssl_cert: Option, ) -> Result { - // Read the file let file = File::open(file_path).await?; let file_len = file.metadata().await.unwrap().len(); - // Create the request and attach the file to the body - let client = reqwest::Client::new(); + let client = build_client(skip_ssl_cert_check, trust_ssl_cert)?; let mut request = client .post(url) .header(reqwest::header::CONTENT_LENGTH, file_len) @@ -210,7 +229,7 @@ mod tests { let _ = msg; Ok(()) }); - download(url, file_path, headers, None, sender).await + download(url, file_path, headers, None, sender, None, None).await } async fn spawn_server_mocked(return_status: usize) -> MockedServer {