From f0b21dccacb846510e2eb8f2150b1fd02fffd9dd Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 12 Apr 2024 07:43:51 +0100 Subject: [PATCH 1/4] parse and validate websocket url --- Cargo.lock | 1 + mm2src/mm2_net/Cargo.toml | 1 + mm2src/mm2_net/src/wasm/wasm_ws.rs | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 1550012249..61c804719a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4660,6 +4660,7 @@ dependencies = [ "tokio-rustls", "tonic", "tower-service", + "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index fd42e034ac..5b9813e82e 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -43,6 +43,7 @@ js-sys = "0.3.27" pin-project = "1.1.2" tonic = { version = "0.7", default-features = false, features = ["prost", "codegen"] } tower-service = "0.3" +url = { version = "2.2.2", default-features = false } wasm-bindgen = "0.2.86" wasm-bindgen-test = { version = "0.3.2" } wasm-bindgen-futures = "0.4.21" diff --git a/mm2src/mm2_net/src/wasm/wasm_ws.rs b/mm2src/mm2_net/src/wasm/wasm_ws.rs index 661babef3c..3282d189a1 100644 --- a/mm2src/mm2_net/src/wasm/wasm_ws.rs +++ b/mm2src/mm2_net/src/wasm/wasm_ws.rs @@ -14,6 +14,7 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; +use url::Url; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use web_sys::{CloseEvent, DomException, MessageEvent, WebSocket}; @@ -312,7 +313,8 @@ struct WebSocketImpl { impl WebSocketImpl { fn init(url: &str) -> InitWsResult<(WebSocketImpl, WsTransportReceiver)> { - let ws = WebSocket::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; + let url = validate_websocket_url(url)?; + let ws = WebSocket::new(url.as_str()).map_to_mm(|e| InitWsError::from_ws_new_err(e, url.as_str()))?; let (tx, rx) = mpsc::channel(1024); @@ -371,6 +373,21 @@ impl Drop for WebSocketImpl { } } +pub fn validate_websocket_url(url: &str) -> Result> { + let parsed_url = Url::parse(url).map_err(|e| InitWsError::InvalidUrl { + url: url.to_string(), + reason: e.to_string(), + })?; + if parsed_url.scheme() != "ws" && parsed_url.scheme() != "wss" { + return MmError::err(InitWsError::InvalidUrl { + url: url.to_string(), + reason: "URL must use ws or wss scheme".to_string(), + }); + } + + Ok(parsed_url) +} + struct WsStateMachine { idx: ConnIdx, ws: WebSocketImpl, From 3b11bd696e1e48999d77ef852e180a52c76feed6 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 12 Apr 2024 08:21:41 +0100 Subject: [PATCH 2/4] use websys::Url for validation --- Cargo.lock | 1 - mm2src/mm2_net/Cargo.toml | 3 +-- mm2src/mm2_net/src/wasm/wasm_ws.rs | 29 ++++++++++++++++++----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61c804719a..1550012249 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4660,7 +4660,6 @@ dependencies = [ "tokio-rustls", "tonic", "tower-service", - "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index 5b9813e82e..5627f003ff 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -43,14 +43,13 @@ js-sys = "0.3.27" pin-project = "1.1.2" tonic = { version = "0.7", default-features = false, features = ["prost", "codegen"] } tower-service = "0.3" -url = { version = "2.2.2", default-features = false } wasm-bindgen = "0.2.86" wasm-bindgen-test = { version = "0.3.2" } wasm-bindgen-futures = "0.4.21" web-sys = { version = "0.3.55", features = ["console", "CloseEvent", "DomException", "ErrorEvent", "IdbDatabase", "IdbCursor", "IdbCursorWithValue", "IdbFactory", "IdbIndex", "IdbIndexParameters", "IdbObjectStore", "IdbObjectStoreParameters", "IdbOpenDbRequest", "IdbKeyRange", "IdbTransaction", "IdbTransactionMode", - "IdbVersionChangeEvent", "MessageEvent", "MessagePort", "ReadableStreamDefaultReader", "ReadableStream", "SharedWorker", "WebSocket"] } + "IdbVersionChangeEvent", "MessageEvent", "MessagePort", "ReadableStreamDefaultReader", "ReadableStream", "SharedWorker", "Url", "WebSocket"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/mm2src/mm2_net/src/wasm/wasm_ws.rs b/mm2src/mm2_net/src/wasm/wasm_ws.rs index 3282d189a1..15c4def48a 100644 --- a/mm2src/mm2_net/src/wasm/wasm_ws.rs +++ b/mm2src/mm2_net/src/wasm/wasm_ws.rs @@ -14,10 +14,9 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -use url::Url; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -use web_sys::{CloseEvent, DomException, MessageEvent, WebSocket}; +use web_sys::{CloseEvent, DomException, MessageEvent, Url, WebSocket}; const NORMAL_CLOSURE_CODE: u16 = 1000; @@ -51,6 +50,15 @@ pub enum InitWsError { impl InitWsError { fn from_ws_new_err(e: JsValue, url: &str) -> InitWsError { let reason = stringify_js_error(&e); + + // Check for TypeError + if reason.contains("URL constructor") { + return InitWsError::InvalidUrl { + url: url.to_owned(), + reason, + }; + }; + match e.dyn_ref::().map(DomException::code) { Some(DomException::SYNTAX_ERR) => InitWsError::InvalidUrl { url: url.to_owned(), @@ -314,7 +322,7 @@ struct WebSocketImpl { impl WebSocketImpl { fn init(url: &str) -> InitWsResult<(WebSocketImpl, WsTransportReceiver)> { let url = validate_websocket_url(url)?; - let ws = WebSocket::new(url.as_str()).map_to_mm(|e| InitWsError::from_ws_new_err(e, url.as_str()))?; + let ws = WebSocket::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; let (tx, rx) = mpsc::channel(1024); @@ -373,19 +381,18 @@ impl Drop for WebSocketImpl { } } -pub fn validate_websocket_url(url: &str) -> Result> { - let parsed_url = Url::parse(url).map_err(|e| InitWsError::InvalidUrl { - url: url.to_string(), - reason: e.to_string(), - })?; - if parsed_url.scheme() != "ws" && parsed_url.scheme() != "wss" { +pub fn validate_websocket_url(url: &str) -> Result<&str, MmError> { + let parsed_url = Url::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; + + let scheme = parsed_url.protocol(); + if scheme != "ws:" && scheme != "wss:" { return MmError::err(InitWsError::InvalidUrl { url: url.to_string(), - reason: "URL must use ws or wss scheme".to_string(), + reason: "URL must use 'ws' or 'wss' scheme".to_string(), }); } - Ok(parsed_url) + Ok(url) } struct WsStateMachine { From 10bfe5b3941adb8da7f14135055175e696bbe477 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 12 Apr 2024 08:57:29 +0100 Subject: [PATCH 3/4] code organization --- mm2src/mm2_net/src/wasm/wasm_ws.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mm2src/mm2_net/src/wasm/wasm_ws.rs b/mm2src/mm2_net/src/wasm/wasm_ws.rs index 15c4def48a..cb634622f2 100644 --- a/mm2src/mm2_net/src/wasm/wasm_ws.rs +++ b/mm2src/mm2_net/src/wasm/wasm_ws.rs @@ -321,7 +321,7 @@ struct WebSocketImpl { impl WebSocketImpl { fn init(url: &str) -> InitWsResult<(WebSocketImpl, WsTransportReceiver)> { - let url = validate_websocket_url(url)?; + Self::validate_websocket_url(url)?; let ws = WebSocket::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; let (tx, rx) = mpsc::channel(1024); @@ -365,6 +365,20 @@ impl WebSocketImpl { }, } } + + fn validate_websocket_url(url: &str) -> Result<(), MmError> { + let parsed_url = Url::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; + + let scheme = parsed_url.protocol(); + if scheme != "ws:" && scheme != "wss:" { + return MmError::err(InitWsError::InvalidUrl { + url: url.to_string(), + reason: "URL must use 'ws' or 'wss' scheme".to_string(), + }); + } + + Ok(()) + } } impl Drop for WebSocketImpl { @@ -381,20 +395,6 @@ impl Drop for WebSocketImpl { } } -pub fn validate_websocket_url(url: &str) -> Result<&str, MmError> { - let parsed_url = Url::new(url).map_to_mm(|e| InitWsError::from_ws_new_err(e, url))?; - - let scheme = parsed_url.protocol(); - if scheme != "ws:" && scheme != "wss:" { - return MmError::err(InitWsError::InvalidUrl { - url: url.to_string(), - reason: "URL must use 'ws' or 'wss' scheme".to_string(), - }); - } - - Ok(url) -} - struct WsStateMachine { idx: ConnIdx, ws: WebSocketImpl, From cd352dd5d9be8462961ddb321b1f3f549628b3fb Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 12 Apr 2024 17:32:38 +0100 Subject: [PATCH 4/4] use DomException::name for jsvalue err --- mm2src/mm2_net/src/wasm/wasm_ws.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_net/src/wasm/wasm_ws.rs b/mm2src/mm2_net/src/wasm/wasm_ws.rs index cb634622f2..a0a7bbb067 100644 --- a/mm2src/mm2_net/src/wasm/wasm_ws.rs +++ b/mm2src/mm2_net/src/wasm/wasm_ws.rs @@ -59,8 +59,8 @@ impl InitWsError { }; }; - match e.dyn_ref::().map(DomException::code) { - Some(DomException::SYNTAX_ERR) => InitWsError::InvalidUrl { + match e.dyn_ref::().map(DomException::name) { + Some(ref name) if name == "SyntaxError" => InitWsError::InvalidUrl { url: url.to_owned(), reason, },