From 7bb7d211fa9430d9bd2fcedd45888ac0fb2e258c Mon Sep 17 00:00:00 2001 From: ospab Date: Wed, 10 Jun 2026 02:26:13 +0300 Subject: [PATCH] Remove stealth_port entirely and integrate fallback into UoT HTTP handler --- README.md | 2 +- README.ru.md | 3 +- ostp-client/src/bridge.rs | 50 +- ostp-client/src/config.rs | 11 +- ostp-client/src/transport/xhttp.rs | 18 +- ostp-flutter/lib/ui/home_screen.dart | 4 - ostp-flutter/lib/ui/settings_screen.dart | 5 - ostp-flutter/pubspec.yaml | 2 +- ostp-gui/src-tauri/Cargo.lock | 828 ++---------------- ostp-gui/src-tauri/Cargo.toml | 2 - .../src-tauri/permissions/app-commands.toml | 5 +- ostp-gui/src-tauri/src/lib.rs | 155 ++-- ostp-gui/src-tauri/tauri.conf.json | 2 +- ostp-gui/src/i18n.js | 24 + ostp-gui/src/index.html | 40 +- ostp-gui/src/main.js | 101 ++- ostp-gui/src/styles.css | 28 +- ostp-server/src/fallback.rs | 2 +- ostp-server/src/lib.rs | 13 +- ostp-server/src/transport/uot.rs | 64 +- ostp/src/main.rs | 4 - test.json | Bin 126 -> 2 bytes 22 files changed, 431 insertions(+), 932 deletions(-) diff --git a/README.md b/README.md index a1be4f4..fbca816 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ graph TD "server": "YOUR_SERVER_IP:50000", "access_key": "YOUR_SECRET_KEY", "socks5_bind": "127.0.0.1:1088", - "transport": { "mode": "udp", "stealth_sni": "vk.com", "stealth_port": 443 }, + "transport": { "mode": "udp", "stealth_sni": "vk.com" }, "tun": { "enable": false, "dns": "1.1.1.1" } } ``` diff --git a/README.ru.md b/README.ru.md index 0d50802..a0be641 100644 --- a/README.ru.md +++ b/README.ru.md @@ -115,8 +115,7 @@ irm https://raw.githubusercontent.com/ospab/ostp/master/scripts/install.ps1 | ie // Настройки транспорта (udp или uot) "transport": { "mode": "udp", - "stealth_sni": "vk.com", - "stealth_port": 443 + "stealth_sni": "vk.com" }, // TUN-режим (полносистемный VPN) "tun": { diff --git a/ostp-client/src/bridge.rs b/ostp-client/src/bridge.rs index 3528ff6..8252c2b 100644 --- a/ostp-client/src/bridge.rs +++ b/ostp-client/src/bridge.rs @@ -66,7 +66,6 @@ pub struct Bridge { pub transport_mode: String, pub stealth_sni: String, - pub stealth_port: u16, pub wss: bool, pub mtu: usize, pub reality_enabled: bool, @@ -103,7 +102,6 @@ impl Bridge { transport_mode: config.transport.mode.clone(), stealth_sni: config.transport.stealth_sni.clone(), - stealth_port: config.transport.stealth_port, wss: config.transport.wss, mtu: config.ostp.mtu, reality_enabled: config.reality.enabled, @@ -337,6 +335,7 @@ impl Bridge { tokio::spawn(async move { let mut buf = vec![0_u8; 65535]; + let is_uot = matches!(socket_clone, crate::transport::Transport::Uot { .. }); loop { match socket_clone.recv(&mut buf).await { Ok(n) => { @@ -346,8 +345,14 @@ impl Bridge { } } Err(e) => { - tracing::warn!("UDP socket recv error (session {}): {}", session_index, e); - tokio::time::sleep(std::time::Duration::from_millis(10)).await; + if is_uot { + // TCP is dead — drop sender to signal bridge via channel close + tracing::warn!("UoT session {} disconnected: {}", session_index, e); + break; + } else { + tracing::warn!("UDP socket recv error (session {}): {}", session_index, e); + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + } } } } @@ -427,6 +432,7 @@ impl Bridge { tokio::spawn(async move { let mut buf = vec![0_u8; 65535]; + let is_uot = matches!(socket_clone, crate::transport::Transport::Uot { .. }); loop { match socket_clone.recv(&mut buf).await { Ok(n) => { @@ -434,8 +440,13 @@ impl Bridge { if udp_tx_clone.send((session_index, inbound)).await.is_err() { break; } } Err(e) => { - tracing::warn!("UDP recv error (network-change session {}): {}", session_index, e); - tokio::time::sleep(std::time::Duration::from_millis(10)).await; + if is_uot { + tracing::warn!("UoT network-change session {} disconnected: {}", session_index, e); + break; + } else { + tracing::warn!("UDP recv error (network-change session {}): {}", session_index, e); + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + } } } } @@ -557,6 +568,7 @@ impl Bridge { tokio::spawn(async move { let mut buf = vec![0_u8; 65535]; + let is_uot = matches!(socket_clone, crate::transport::Transport::Uot { .. }); loop { match socket_clone.recv(&mut buf).await { Ok(n) => { @@ -566,8 +578,13 @@ impl Bridge { } } Err(e) => { - tracing::warn!("UDP socket recv error (reconnect session {}): {}", session_index, e); - tokio::time::sleep(std::time::Duration::from_millis(10)).await; + if is_uot { + tracing::warn!("UoT reconnect session {} disconnected: {}", session_index, e); + break; + } else { + tracing::warn!("UDP socket recv error (reconnect session {}): {}", session_index, e); + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + } } } } @@ -910,7 +927,10 @@ impl Bridge { // and break the Noise state machine (noise-read error). // For UDP: retry up to 4x with 1200ms timeout to survive packet loss. let is_uot = matches!(socket, crate::transport::Transport::Uot { .. }); - let (attempt_limit, attempt_timeout_ms) = if is_uot { (1, 4000) } else { (4, 1200) }; + // UoT (TCP): 1 attempt only — retrying on TCP causes stale Noise frames to queue. + // Timeout is generous (8s) to accommodate slow mobile TCP+TLS setup. + // UDP: 4 attempts × 1200ms — survives individual packet loss. + let (attempt_limit, attempt_timeout_ms) = if is_uot { (1, 8000) } else { (4, 1200) }; for attempt in 0..attempt_limit { if attempt > 0 { @@ -989,7 +1009,7 @@ impl Bridge { self.mux_sessions = cfg.multiplex.sessions.max(1); self.transport_mode = cfg.transport.mode.clone(); self.stealth_sni = cfg.transport.stealth_sni.clone(); - self.stealth_port = cfg.transport.stealth_port; + self.wss = cfg.transport.wss; // Fix: wss was not updated on hot-reload self.reality_enabled = cfg.reality.enabled; self.reality_pbk = cfg.reality.pbk.clone(); self.reality_sid = cfg.reality.sid.clone(); @@ -1005,16 +1025,8 @@ impl Bridge { ) -> Result { let mode = self.transport_mode.to_lowercase(); if mode == "uot" || mode == "tcp" { - // For UoT, use the stealth_port if it's configured and differs from default 443; - // otherwise fall back to the actual server port so the user doesn't need two separate - // port fields for the same destination. - let uot_port = if self.stealth_port > 0 { - self.stealth_port - } else { - port - }; let (tx, rx) = crate::transport::xhttp::connect_xhttp( - target_ip, uot_port, &self.stealth_sni, &self.access_key, self.reality_enabled, self.wss, &self.reality_pbk, &self.reality_sid + target_ip, port, &self.stealth_sni, &self.access_key, self.reality_enabled, self.wss, &self.reality_pbk, &self.reality_sid ).await?; Ok(crate::transport::Transport::Uot { tx, rx }) } else { diff --git a/ostp-client/src/config.rs b/ostp-client/src/config.rs index 99ebe5a..b84ffda 100644 --- a/ostp-client/src/config.rs +++ b/ostp-client/src/config.rs @@ -78,23 +78,18 @@ pub struct TransportConfig { /// TLS SNI and HTTP Host for stealth routing #[serde(default)] pub stealth_sni: String, - /// TCP Port for the stealth connection - #[serde(default = "default_stealth_port")] - pub stealth_port: u16, /// Enable strict RFC 6455 WebSocket framing #[serde(default)] pub wss: bool, } fn default_transport_mode() -> String { "udp".to_string() } -fn default_stealth_port() -> u16 { 443 } impl Default for TransportConfig { fn default() -> Self { Self { mode: default_transport_mode(), stealth_sni: String::new(), - stealth_port: default_stealth_port(), wss: false, } } @@ -191,7 +186,6 @@ struct RawUnifiedConfig { struct RawTransportSection { mode: Option, stealth_sni: Option, - stealth_port: Option, wss: Option, } @@ -280,9 +274,8 @@ impl ClientConfig { spx: raw.reality.as_ref().and_then(|t| t.spx.clone()).unwrap_or_default(), }, transport: TransportConfig { - mode: raw.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(|| "udp".to_string()), - stealth_sni: raw.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_else(|| "microsoft.com".to_string()), - stealth_port: raw.transport.as_ref().and_then(|t| t.stealth_port).unwrap_or(443), + mode: raw.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(default_transport_mode), + stealth_sni: raw.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_default(), wss: raw.transport.as_ref().and_then(|t| t.wss).unwrap_or(false), }, exclusions: ExclusionConfig { diff --git a/ostp-client/src/transport/xhttp.rs b/ostp-client/src/transport/xhttp.rs index 3ae9044..fbe31f4 100644 --- a/ostp-client/src/transport/xhttp.rs +++ b/ostp-client/src/transport/xhttp.rs @@ -31,8 +31,13 @@ pub async fn connect_xhttp( let addr = std::net::SocketAddr::new(target_ip, port); #[cfg(not(target_os = "android"))] - let mut tcp_stream = tokio::net::TcpStream::connect(addr).await - .with_context(|| format!("failed to connect to {}", addr))?; + let mut tcp_stream = tokio::time::timeout( + std::time::Duration::from_secs(10), + tokio::net::TcpStream::connect(addr), + ) + .await + .map_err(|_| anyhow::anyhow!("TCP connect timeout to {}", addr))? + .with_context(|| format!("failed to connect to {}", addr))?; #[cfg(target_os = "android")] let mut tcp_stream = { @@ -44,8 +49,13 @@ pub async fn connect_xhttp( sock.set_nonblocking(true)?; let tcp_socket = tokio::net::TcpSocket::from_std_stream(sock.into()); - tcp_socket.connect(addr).await - .with_context(|| format!("failed to connect to {}", addr))? + tokio::time::timeout( + std::time::Duration::from_secs(10), + tcp_socket.connect(addr), + ) + .await + .map_err(|_| anyhow::anyhow!("TCP connect timeout to {}", addr))? + .with_context(|| format!("failed to connect to {}", addr))? }; tcp_stream.set_nodelay(true)?; diff --git a/ostp-flutter/lib/ui/home_screen.dart b/ostp-flutter/lib/ui/home_screen.dart index c824cdb..df4e814 100644 --- a/ostp-flutter/lib/ui/home_screen.dart +++ b/ostp-flutter/lib/ui/home_screen.dart @@ -83,7 +83,6 @@ class _HomeScreenState extends State with TickerProviderStateMixin { final debugMode = widget.prefs.getBool('debug_mode') ?? false; final transportMode = widget.prefs.getString('transport_mode') ?? 'udp'; final stealthSni = widget.prefs.getString('stealth_sni') ?? 'vk.com'; - final stealthPort = widget.prefs.getString('stealth_port') ?? '443'; final wss = widget.prefs.getBool('wss') ?? false; final mtu = widget.prefs.getString('mtu') ?? '1140'; final muxEnabled = widget.prefs.getBool('mux_enabled') ?? false; @@ -113,7 +112,6 @@ class _HomeScreenState extends State with TickerProviderStateMixin { "transport": { "mode": transportMode, "stealth_sni": stealthSni, - "stealth_port": int.tryParse(stealthPort) ?? 443, "wss": wss, }, "multiplex": { @@ -182,7 +180,6 @@ class _HomeScreenState extends State with TickerProviderStateMixin { final debugMode = widget.prefs.getBool('debug_mode') ?? false; final transportMode = widget.prefs.getString('transport_mode') ?? 'udp'; final stealthSni = widget.prefs.getString('stealth_sni') ?? 'vk.com'; - final stealthPort = widget.prefs.getString('stealth_port') ?? '443'; final wss = widget.prefs.getBool('wss') ?? false; final mtu = widget.prefs.getString('mtu') ?? '1140'; final muxEnabled = widget.prefs.getBool('mux_enabled') ?? false; @@ -211,7 +208,6 @@ class _HomeScreenState extends State with TickerProviderStateMixin { "transport": { "mode": transportMode, "stealth_sni": stealthSni, - "stealth_port": int.tryParse(stealthPort) ?? 443, "wss": wss, }, "multiplex": { diff --git a/ostp-flutter/lib/ui/settings_screen.dart b/ostp-flutter/lib/ui/settings_screen.dart index 1ace5a1..eca3218 100644 --- a/ostp-flutter/lib/ui/settings_screen.dart +++ b/ostp-flutter/lib/ui/settings_screen.dart @@ -29,7 +29,6 @@ class _SettingsScreenState extends State { late TextEditingController _ipsCtrl; late TextEditingController _processesCtrl; late TextEditingController _stealthSniCtrl; - late TextEditingController _stealthPortCtrl; late TextEditingController _pbkCtrl; late TextEditingController _sidCtrl; @@ -56,7 +55,6 @@ class _SettingsScreenState extends State { _ipsCtrl = TextEditingController(text: widget.prefs.getString('ex_ips') ?? ''); _processesCtrl = TextEditingController(text: widget.prefs.getString('ex_processes') ?? ''); _stealthSniCtrl = TextEditingController(text: widget.prefs.getString('stealth_sni') ?? ''); - _stealthPortCtrl = TextEditingController(text: widget.prefs.getString('stealth_port') ?? '443'); _pbkCtrl = TextEditingController(text: widget.prefs.getString('pbk') ?? ''); _sidCtrl = TextEditingController(text: widget.prefs.getString('sid') ?? ''); _wss = widget.prefs.getBool('wss') ?? false; @@ -82,7 +80,6 @@ class _SettingsScreenState extends State { _ipsCtrl.dispose(); _processesCtrl.dispose(); _stealthSniCtrl.dispose(); - _stealthPortCtrl.dispose(); _pbkCtrl.dispose(); _sidCtrl.dispose(); _muxSessionsCtrl.dispose(); @@ -104,7 +101,6 @@ class _SettingsScreenState extends State { widget.prefs.setString('transport_mode', _transportMode); widget.prefs.setString('tun_stack', _tunStack); widget.prefs.setString('stealth_sni', _stealthSniCtrl.text.trim()); - widget.prefs.setString('stealth_port', _stealthPortCtrl.text.trim()); widget.prefs.setString('pbk', _pbkCtrl.text.trim()); widget.prefs.setString('sid', _sidCtrl.text.trim()); widget.prefs.setBool('mux_enabled', _muxEnabled); @@ -394,7 +390,6 @@ class _SettingsScreenState extends State { if (newValue != null) { setState(() { _stealthSniCtrl.text = newValue; - _stealthPortCtrl.text = '443'; _saveSettings(); }); } diff --git a/ostp-flutter/pubspec.yaml b/ostp-flutter/pubspec.yaml index 0b940c0..ecb913b 100644 --- a/ostp-flutter/pubspec.yaml +++ b/ostp-flutter/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 +version: 0.2.87+2 environment: sdk: ^3.11.4 diff --git a/ostp-gui/src-tauri/Cargo.lock b/ostp-gui/src-tauri/Cargo.lock index 8d10cf9..60937fc 100644 --- a/ostp-gui/src-tauri/Cargo.lock +++ b/ostp-gui/src-tauri/Cargo.lock @@ -14,7 +14,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common 0.1.7", + "crypto-common", "generic-array", ] @@ -25,19 +25,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher 0.4.4", - "cpufeatures 0.2.17", -] - -[[package]] -name = "aes" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" -dependencies = [ - "cipher 0.5.2", - "cpubits", - "cpufeatures 0.3.0", + "cipher", + "cpufeatures", ] [[package]] @@ -47,8 +36,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", - "aes 0.8.4", - "cipher 0.4.4", + "aes", + "cipher", "ctr", "ghash", "subtle", @@ -265,28 +254,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-lc-rs" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "base64" version = "0.21.7" @@ -335,7 +302,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -347,16 +314,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" -dependencies = [ - "hybrid-array", - "zeroize", -] - [[package]] name = "block2" version = "0.6.2" @@ -436,15 +393,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bzip2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" -dependencies = [ - "libbz2-rs-sys", -] - [[package]] name = "cairo-rs" version = "0.18.5" @@ -519,8 +467,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] @@ -570,8 +516,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher 0.4.4", - "cpufeatures 0.2.17", + "cipher", + "cpufeatures", ] [[package]] @@ -582,7 +528,7 @@ checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher 0.4.4", + "cipher", "poly1305", "zeroize", ] @@ -607,36 +553,11 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common 0.1.7", - "inout 0.1.4", + "crypto-common", + "inout", "zeroize", ] -[[package]] -name = "cipher" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" -dependencies = [ - "crypto-common 0.2.2", - "inout 0.2.2", -] - -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - -[[package]] -name = "cmov" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" - [[package]] name = "combine" version = "4.6.7" @@ -656,18 +577,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "constant_time_eq" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" - [[package]] name = "cookie" version = "0.18.1" @@ -678,16 +587,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -711,7 +610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ "bitflags 2.11.1", - "core-foundation 0.10.1", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -724,16 +623,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.11.1", - "core-foundation 0.10.1", + "core-foundation", "libc", ] -[[package]] -name = "cpubits" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -743,15 +636,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -783,19 +667,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "typenum", ] -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - [[package]] name = "cssparser" version = "0.36.0" @@ -841,16 +716,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.4.4", -] - -[[package]] -name = "ctutils" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" -dependencies = [ - "cmov", + "cipher", ] [[package]] @@ -860,7 +726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "curve25519-dalek-derive", "fiat-crypto", "rustc_version", @@ -924,12 +790,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "deflate64" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" - [[package]] name = "defmt" version = "0.3.100" @@ -1008,24 +868,11 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", + "block-buffer", + "crypto-common", "subtle", ] -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer 0.12.0", - "const-oid", - "crypto-common 0.2.2", - "ctutils", - "zeroize", -] - [[package]] name = "dirs" version = "6.0.0" @@ -1179,15 +1026,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "endi" version = "1.1.1" @@ -1317,7 +1155,6 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", - "zlib-rs", ] [[package]] @@ -1374,12 +1211,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.32" @@ -1597,10 +1428,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -1610,11 +1439,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] @@ -1624,12 +1451,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 6.0.0", "wasip2", "wasip3", - "wasm-bindgen", ] [[package]] @@ -1790,25 +1615,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "h2" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.14.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hash32" version = "0.3.1" @@ -1879,7 +1685,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac 0.12.1", + "hmac", ] [[package]] @@ -1888,16 +1694,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" -dependencies = [ - "digest 0.11.3", + "digest", ] [[package]] @@ -1949,15 +1746,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "hybrid-array" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" -dependencies = [ - "typenum", -] - [[package]] name = "hyper" version = "1.9.0" @@ -1968,7 +1756,6 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", "http", "http-body", "httparse", @@ -1979,21 +1766,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.27.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "tokio", - "tokio-rustls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -2012,11 +1784,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", - "system-configuration", "tokio", "tower-service", "tracing", - "windows-registry", ] [[package]] @@ -2209,15 +1979,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "inout" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" -dependencies = [ - "hybrid-array", -] - [[package]] name = "ipnet" version = "2.12.0" @@ -2288,36 +2049,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "jni" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" -dependencies = [ - "cfg-if", - "combine", - "jni-macros", - "jni-sys 0.4.1", - "log", - "simd_cesu8", - "thiserror 2.0.18", - "walkdir", - "windows-link 0.2.1", -] - -[[package]] -name = "jni-macros" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "simd_cesu8", - "syn 2.0.117", -] - [[package]] name = "jni-sys" version = "0.3.1" @@ -2346,16 +2077,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - [[package]] name = "js-sys" version = "0.3.98" @@ -2443,12 +2164,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "libbz2-rs-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" - [[package]] name = "libc" version = "0.2.186" @@ -2520,21 +2235,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "lzma-rust2" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce716bf1a316f47a280fc76295f6495b5bea4752bca01c3b3885e101b1c23c02" -dependencies = [ - "sha2 0.11.0", -] - [[package]] name = "managed" version = "0.8.0" @@ -2656,7 +2356,7 @@ checksum = "398691cef792b89eb5d29e6ea6b3999def706b908d355e29815ba8101cf5c4c8" dependencies = [ "etherparse", "futures", - "rand 0.8.6", + "rand", "smoltcp", "spin", "tokio", @@ -2947,12 +2647,6 @@ dependencies = [ "pathdiff", ] -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - [[package]] name = "option-ext" version = "0.2.0" @@ -2971,7 +2665,7 @@ dependencies = [ [[package]] name = "ostp-client" -version = "0.2.86" +version = "0.2.87" dependencies = [ "anyhow", "base64 0.22.1", @@ -2981,17 +2675,17 @@ dependencies = [ "futures", "futures-util", "hex", - "hmac 0.12.1", + "hmac", "json_comments", "libc", "netstack-smoltcp", "ostp-core", "ostp-tun", "portable-atomic", - "rand 0.8.6", + "rand", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "socket2", "tokio", "tracing", @@ -3005,15 +2699,15 @@ dependencies = [ [[package]] name = "ostp-core" -version = "0.2.86" +version = "0.2.87" dependencies = [ "anyhow", "bytes", "chacha20poly1305", "hkdf", - "hmac 0.12.1", - "rand 0.8.6", - "sha2 0.10.9", + "hmac", + "rand", + "sha2", "snow", "thiserror 1.0.69", "tracing", @@ -3028,20 +2722,18 @@ dependencies = [ "json_comments", "ostp-client", "portable-atomic", - "rand 0.8.6", - "reqwest", + "rand", "serde", "serde_json", "tauri", "tauri-build", "tauri-plugin-opener", "tokio", - "zip", ] [[package]] name = "ostp-tun" -version = "0.2.86" +version = "0.2.87" dependencies = [ "anyhow", "libc", @@ -3111,16 +2803,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "pbkdf2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" -dependencies = [ - "digest 0.11.3", - "hmac 0.13.0", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -3262,7 +2944,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures 0.2.17", + "cpufeatures", "opaque-debug", "universal-hash", ] @@ -3274,7 +2956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "opaque-debug", "universal-hash", ] @@ -3300,12 +2982,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[package]] -name = "ppmd-rust" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3424,62 +3100,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.4", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "quote" version = "1.0.45" @@ -3508,18 +3128,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_chacha", + "rand_core", ] [[package]] @@ -3529,17 +3139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "rand_core", ] [[package]] @@ -3551,15 +3151,6 @@ dependencies = [ "getrandom 0.2.17", ] -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -3643,31 +3234,21 @@ checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64 0.22.1", "bytes", - "encoding_rs", - "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "http-body-util", "hyper", - "hyper-rustls", "hyper-util", "js-sys", "log", - "mime", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", - "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3679,20 +3260,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rustc-hash" version = "2.1.2" @@ -3721,80 +3288,11 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "aws-lc-rs", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pki-types" version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni 0.22.4", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] [[package]] name = "rustversion" @@ -3811,15 +3309,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "schemars" version = "0.8.22" @@ -3877,29 +3366,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags 2.11.1", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "selectors" version = "0.36.1" @@ -4087,17 +3553,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "sha1" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - [[package]] name = "sha2" version = "0.10.9" @@ -4105,19 +3560,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -4151,22 +3595,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" -[[package]] -name = "simd_cesu8" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" -dependencies = [ - "rustc_version", - "simdutf8", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - [[package]] name = "siphasher" version = "1.0.3" @@ -4210,9 +3638,9 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", "rustc_version", - "sha2 0.10.9", + "sha2", "subtle", ] @@ -4383,27 +3811,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags 2.11.1", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "system-deps" version = "6.2.2" @@ -4425,7 +3832,7 @@ checksum = "a33f7f9e486ade65fcf1e45c440f9236c904f5c1002cdc7fc6ae582777345ce4" dependencies = [ "bitflags 2.11.1", "block2", - "core-foundation 0.10.1", + "core-foundation", "core-graphics", "crossbeam-channel", "dbus", @@ -4435,7 +3842,7 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni 0.21.1", + "jni", "libc", "log", "ndk", @@ -4491,7 +3898,7 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni 0.21.1", + "jni", "libc", "log", "mime", @@ -4563,7 +3970,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "syn 2.0.117", "tauri-utils", "thiserror 2.0.18", @@ -4635,7 +4042,7 @@ dependencies = [ "dpi", "gtk", "http", - "jni 0.21.1", + "jni", "objc2", "objc2-ui-kit", "objc2-web-kit", @@ -4658,7 +4065,7 @@ checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9" dependencies = [ "gtk", "http", - "jni 0.21.1", + "jni", "log", "objc2", "objc2-app-kit", @@ -4805,7 +4212,6 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", - "js-sys", "num-conv", "powerfmt", "serde_core", @@ -4882,16 +4288,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -5193,12 +4589,6 @@ dependencies = [ "wintun-bindings", ] -[[package]] -name = "typed-path" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" - [[package]] name = "typeid" version = "1.0.3" @@ -5287,16 +4677,10 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common 0.1.7", + "crypto-common", "subtle", ] -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "url" version = "2.5.8" @@ -5539,16 +4923,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "web_atoms" version = "0.2.4" @@ -5605,15 +4979,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "webpki-root-certs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "webpki-roots" version = "0.26.11" @@ -5817,17 +5182,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -5873,15 +5227,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" @@ -6205,7 +5550,7 @@ dependencies = [ "gtk", "http", "javascriptcore-rs", - "jni 0.21.1", + "jni", "libc", "ndk", "objc2", @@ -6217,7 +5562,7 @@ dependencies = [ "once_cell", "percent-encoding", "raw-window-handle", - "sha2 0.10.9", + "sha2", "soup3", "tao-macros", "thiserror 2.0.18", @@ -6259,7 +5604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", "serde", "zeroize", ] @@ -6442,85 +5787,12 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "zip" -version = "8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" -dependencies = [ - "aes 0.9.1", - "bzip2", - "constant_time_eq", - "crc32fast", - "deflate64", - "flate2", - "getrandom 0.4.2", - "hmac 0.13.0", - "indexmap 2.14.0", - "lzma-rust2", - "memchr", - "pbkdf2", - "ppmd-rust", - "sha1", - "time", - "typed-path", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zlib-rs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" - [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "zvariant" version = "5.11.0" diff --git a/ostp-gui/src-tauri/Cargo.toml b/ostp-gui/src-tauri/Cargo.toml index a9e7458..1cacbe6 100644 --- a/ostp-gui/src-tauri/Cargo.toml +++ b/ostp-gui/src-tauri/Cargo.toml @@ -28,6 +28,4 @@ ostp-client = { path = "../../ostp-client" } portable-atomic = "1" json_comments = "0.2" rand = "0.8" -reqwest = { version = "0.13.4", features = ["blocking"] } -zip = "8.6.0" diff --git a/ostp-gui/src-tauri/permissions/app-commands.toml b/ostp-gui/src-tauri/permissions/app-commands.toml index 6a120e8..aae11a1 100644 --- a/ostp-gui/src-tauri/permissions/app-commands.toml +++ b/ostp-gui/src-tauri/permissions/app-commands.toml @@ -9,5 +9,8 @@ allow = [ "get_tunnel_status", "get_metrics", "get_config", - "save_config" + "save_config", + "get_wintun_install_path", + "set_autostart", + "get_autostart" ] diff --git a/ostp-gui/src-tauri/src/lib.rs b/ostp-gui/src-tauri/src/lib.rs index b2ea628..a28a3c0 100644 --- a/ostp-gui/src-tauri/src/lib.rs +++ b/ostp-gui/src-tauri/src/lib.rs @@ -35,6 +35,13 @@ struct ClientConfigRaw { debug: Option, exclude: Option, mux: Option, + gui: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +struct GuiConfig { + autoconnect: Option, + launch_startup: Option, } #[derive(Debug, Deserialize, Serialize, Clone)] @@ -61,7 +68,6 @@ struct RealityConfigRaw { struct TransportConfigRaw { mode: Option, stealth_sni: Option, - stealth_port: Option, wss: Option, } @@ -99,9 +105,10 @@ enum HelperMsg { // ── Application state ───────────────────────────────────────────────────────── struct InProcessState { - shutdown_tx: Option>, - metrics: Arc, - handle: JoinHandle>, + shutdown_tx: Option>, + metrics: Arc, + handle: tokio::task::JoinHandle>, + error_msg: Arc>>, } struct HelperState { @@ -174,7 +181,6 @@ fn map_to_client_config(raw: &ClientConfigRaw, mode: &str) -> ostp_client::confi transport: ostp_client::config::TransportConfig { mode: raw.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(|| "udp".to_string()), stealth_sni: raw.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_else(|| "microsoft.com".to_string()), - stealth_port: raw.transport.as_ref().and_then(|t| t.stealth_port).unwrap_or(443), wss: raw.transport.as_ref().and_then(|t| t.wss).unwrap_or(false), }, exclusions: ostp_client::config::ExclusionConfig { @@ -194,48 +200,63 @@ fn map_to_client_config(raw: &ClientConfigRaw, mode: &str) -> ostp_client::confi // ── Tauri commands ──────────────────────────────────────────────────────────── +/// Returns the directory path where wintun.dll should be placed. #[tauri::command] -async fn download_wintun() -> Result { - tokio::task::spawn_blocking(move || { - let response = reqwest::blocking::get("https://www.wintun.net/builds/wintun-0.14.1.zip") - .map_err(|e| format!("Failed to download wintun.zip: {}", e))?; - let bytes = response.bytes().map_err(|e| format!("Failed to read bytes: {}", e))?; - let cursor = std::io::Cursor::new(bytes); - let mut zip = zip::ZipArchive::new(cursor).map_err(|e| format!("Invalid zip archive: {}", e))?; - - let arch = if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "aarch64") { - "arm64" - } else { - "amd64" - }; - let arch_path = format!("wintun/bin/{}/wintun.dll", arch); - - let mut file = zip.by_name(&arch_path).map_err(|e| format!("wintun.dll not found in zip: {}", e))?; - - let mut paths_to_write = vec![]; - if let Ok(cwd) = std::env::current_dir() { - paths_to_write.push(cwd.join("wintun.dll")); +fn get_wintun_install_path() -> String { + if let Some(helper) = find_helper_exe() { + if let Some(dir) = helper.parent() { + return dir.to_string_lossy().into_owned(); } - if let Some(helper) = find_helper_exe() { - if let Some(dir) = helper.parent() { - paths_to_write.push(dir.join("wintun.dll")); + } + if let Ok(cwd) = std::env::current_dir() { + return cwd.to_string_lossy().into_owned(); + } + String::new() +} + +/// Sets or removes the app from Windows startup (HKCU\...\Run). +#[tauri::command] +fn set_autostart(enable: bool) -> Result<(), String> { + #[cfg(target_os = "windows")] + { + use std::process::Command; + let key = r"HKCU\Software\Microsoft\Windows\CurrentVersion\Run"; + let app_name = "OSTP"; + if enable { + let exe = std::env::current_exe() + .map_err(|e| format!("Cannot get exe path: {}", e))?; + let exe_str = format!("\"{}\"", exe.to_string_lossy()); + let out = Command::new("reg") + .args(["add", key, "/v", app_name, "/t", "REG_SZ", "/d", &exe_str, "/f"]) + .output() + .map_err(|e| format!("reg add failed: {}", e))?; + if !out.status.success() { + return Err(String::from_utf8_lossy(&out.stderr).to_string()); } + } else { + let _ = Command::new("reg") + .args(["delete", key, "/v", app_name, "/f"]) + .output(); } - - if paths_to_write.is_empty() { - return Err("Could not determine where to place wintun.dll".to_string()); + } + Ok(()) +} + +/// Checks if the app is currently in Windows startup. +#[tauri::command] +fn get_autostart() -> bool { + #[cfg(target_os = "windows")] + { + use std::process::Command; + let key = r"HKCU\Software\Microsoft\Windows\CurrentVersion\Run"; + let out = Command::new("reg") + .args(["query", key, "/v", "OSTP"]) + .output(); + if let Ok(o) = out { + return o.status.success(); } - - let mut buf = Vec::new(); - std::io::copy(&mut file, &mut buf).map_err(|e| format!("Failed to read from zip: {}", e))?; - - for p in paths_to_write { - let _ = std::fs::write(&p, &buf); - } - Ok(true) - }).await.map_err(|e| e.to_string())? + } + false } #[tauri::command] @@ -300,11 +321,28 @@ async fn get_tunnel_status(state: tauri::State<'_, AppState>) -> Result Ok(0), Some(TunnelHandle::InProcess(s)) => { - if s.handle.is_finished() { return Ok(0); } - Ok(s.metrics.connection_state.load(Ordering::Relaxed)) + let finished = s.handle.is_finished(); + let conn_state = s.metrics.connection_state.load(Ordering::Relaxed); + eprintln!("[OSTP] get_tunnel_status InProcess: finished={} conn_state={}", finished, conn_state); + if finished { + let mut err_guard = s.error_msg.lock().await; + if let Some(e) = err_guard.take() { + eprintln!("[OSTP] get_tunnel_status returning Err: {}", e); + return Err(e); + } + return Ok(0); + } + Ok(conn_state) } Some(TunnelHandle::Helper(h)) => { - let ps = h.pipe_state.lock().await; + let mut ps = h.pipe_state.lock().await; + eprintln!("[OSTP] get_tunnel_status Helper: conn_state={}", ps.connection_state); + if ps.connection_state == 0 { + if let Some(e) = ps.error_msg.take() { + eprintln!("[OSTP] get_tunnel_status returning Err: {}", e); + return Err(e); + } + } Ok(ps.connection_state) } } @@ -422,28 +460,39 @@ async fn start_tunnel(state: tauri::State<'_, AppState>, app: tauri::AppHandle) }; let is_tun_enabled = client_cfg.tun.as_ref().map(|t| t.enable).unwrap_or(false); + eprintln!("[OSTP] start_tunnel: is_tun_enabled={}", is_tun_enabled); #[cfg(target_os = "windows")] if is_tun_enabled { let mut found = false; if let Ok(cwd) = std::env::current_dir() { - if cwd.join("wintun.dll").exists() { found = true; } + let p = cwd.join("wintun.dll"); + eprintln!("[OSTP] checking wintun at: {:?} exists={}", p, p.exists()); + if p.exists() { found = true; } } if !found { if let Some(helper) = find_helper_exe() { + eprintln!("[OSTP] helper exe found at: {:?}", helper); if let Some(dir) = helper.parent() { - if dir.join("wintun.dll").exists() { found = true; } + let p = dir.join("wintun.dll"); + eprintln!("[OSTP] checking wintun at: {:?} exists={}", p, p.exists()); + if p.exists() { found = true; } } + } else { + eprintln!("[OSTP] helper exe NOT FOUND"); } } if !found { + eprintln!("[OSTP] WINTUN_MISSING — returning error"); return Err("WINTUN_MISSING".to_string()); } } if is_tun_enabled { + eprintln!("[OSTP] starting TUN via helper"); start_tun_via_helper(&mut guard, &client_cfg, app).await } else { + eprintln!("[OSTP] starting proxy in-process"); start_proxy_in_process(&mut guard, &client_cfg, app).await } } @@ -465,10 +514,15 @@ async fn start_proxy_in_process( let (shutdown_tx, shutdown_rx) = watch::channel(false); let metrics_clone = metrics.clone(); + let error_msg = Arc::new(tokio::sync::Mutex::new(None)); + let error_msg_clone = error_msg.clone(); + let handle = tokio::spawn(async move { match ostp_client::runner::run_client_core(mapped, metrics_clone, shutdown_rx, None).await { Ok(_) => Ok(()), Err(e) => { + let mut err_guard = error_msg_clone.lock().await; + *err_guard = Some(e.to_string()); let _ = app.emit("tunnel-error", e.to_string()); Err(e.to_string()) } @@ -479,6 +533,7 @@ async fn start_proxy_in_process( shutdown_tx: Some(shutdown_tx), metrics, handle, + error_msg, })); Ok(true) } @@ -517,7 +572,7 @@ async fn start_tun_via_helper( }).to_string(); let (cmd_tx, mut cmd_rx) = tokio::sync::mpsc::channel::(16); - let pipe_state = Arc::new(Mutex::new(HelperPipeState { connection_state: 1, bytes_sent: 0, bytes_recv: 0, rtt_ms: 0 })); + let pipe_state = Arc::new(Mutex::new(HelperPipeState { connection_state: 1, bytes_sent: 0, bytes_recv: 0, rtt_ms: 0, error_msg: None })); let state_for_task = pipe_state.clone(); tokio::spawn(async move { @@ -540,6 +595,7 @@ async fn start_tun_via_helper( HelperMsg::Metrics { bytes_sent, bytes_recv, rtt_ms } => { s.bytes_sent = bytes_sent; s.bytes_recv = bytes_recv; s.rtt_ms = rtt_ms; } HelperMsg::Error { message } => { s.connection_state = 0; + s.error_msg = Some(message.clone()); eprintln!("Helper error: {}", message); let _ = app.emit("tunnel-error", message); } @@ -564,6 +620,7 @@ struct HelperPipeState { bytes_sent: u64, bytes_recv: u64, rtt_ms: u32, + error_msg: Option, } fn find_helper_exe() -> Option { @@ -745,7 +802,7 @@ pub fn run() { } _ => {} }) - .invoke_handler(tauri::generate_handler![start_tunnel, stop_tunnel, reload_tunnel, get_tunnel_status, get_metrics, get_config, save_config, download_wintun]) + .invoke_handler(tauri::generate_handler![start_tunnel, stop_tunnel, reload_tunnel, get_tunnel_status, get_metrics, get_config, save_config, get_wintun_install_path, set_autostart, get_autostart]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/ostp-gui/src-tauri/tauri.conf.json b/ostp-gui/src-tauri/tauri.conf.json index e14cebf..660330a 100644 --- a/ostp-gui/src-tauri/tauri.conf.json +++ b/ostp-gui/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "ostp-gui", - "version": "0.1.0", + "version": "0.2.87", "identifier": "com.ospab.ostp", "build": { "frontendDist": "../src" diff --git a/ostp-gui/src/i18n.js b/ostp-gui/src/i18n.js index 20b6657..7b5bb2c 100644 --- a/ostp-gui/src/i18n.js +++ b/ostp-gui/src/i18n.js @@ -50,6 +50,18 @@ const translations = { toast_error: 'Error', err_server_req: 'Server address is required', err_key_req: 'Access key is required', + label_autoconnect: 'Auto-connect', + autoconnect_hint: 'Connect automatically on startup', + label_launch_startup: 'Launch at Startup', + launch_startup_hint: 'Start OSTP with Windows', + cancel_btn: 'Cancel', + wintun_missing_title: 'Wintun Driver Missing', + wintun_missing_desc: 'TUN mode requires the Wintun network driver (wintun.dll).', + wintun_step1: 'Download wintun.zip from the official site', + wintun_step2: 'Extract amd64\\wintun.dll from the archive', + wintun_step3: 'Place it here:', + wintun_step4: 'Restart the connection', + wintun_open_btn: 'Open wintun.net ↗', }, ru: { // Главный экран @@ -99,6 +111,18 @@ const translations = { toast_error: 'Ошибка', err_server_req: 'Укажите адрес сервера', err_key_req: 'Укажите ключ доступа', + label_autoconnect: 'Автоподключение', + autoconnect_hint: 'Подключаться автоматически при запуске', + label_launch_startup: 'Запуск вместе с Windows', + launch_startup_hint: 'Автозапуск OSTP при входе в систему', + cancel_btn: 'Отмена', + wintun_missing_title: 'Отсутствует драйвер Wintun', + wintun_missing_desc: 'Режим TUN требует сетевой драйвер Wintun (wintun.dll).', + wintun_step1: 'Скачайте wintun.zip с официального сайта', + wintun_step2: 'Извлеките amd64\\wintun.dll из архива', + wintun_step3: 'Поместите файл сюда:', + wintun_step4: 'Перезапустите подключение', + wintun_open_btn: 'Открыть wintun.net ↗', }, }; diff --git a/ostp-gui/src/index.html b/ostp-gui/src/index.html index 027634e..27b6785 100644 --- a/ostp-gui/src/index.html +++ b/ostp-gui/src/index.html @@ -295,6 +295,33 @@ +
+
+ Launch at Startup + Start with Windows +
+ +
+ +
+
+ Auto-connect + Connect automatically on startup +
+ +
+ +
Debug Logs @@ -308,6 +335,7 @@
+
Exclusions @@ -342,10 +370,16 @@ diff --git a/ostp-gui/src/main.js b/ostp-gui/src/main.js index dc9793a..cb28679 100644 --- a/ostp-gui/src/main.js +++ b/ostp-gui/src/main.js @@ -54,14 +54,17 @@ const inTun = $('in-tun-mode'); const inKillSwitch = $('in-kill-switch'); const inMux = $('in-mux-mode'); const inMuxSessions = $('in-mux-sessions'); -const inDebug = $('in-debug'); +const inDebug = $('in-debug'); +const inAutoconnect = $('in-autoconnect'); +const inLaunchStartup = $('in-launch-startup'); const inDomains = $('in-ex-domains'); const inIps = $('in-ex-ips'); const inProcesses = $('in-ex-processes'); -const wintunModal = $('wintun-modal'); -const btnWintunCancel = $('btn-wintun-cancel'); -const btnWintunDownload = $('btn-wintun-download'); +const wintunModal = $('wintun-modal'); +const btnWintunCancel = $('btn-wintun-cancel'); +const btnWintunOpen = $('btn-wintun-open'); +const wintunInstallPath = $('wintun-install-path'); // ── Utilities ──────────────────────────────────────────────────────────────── function fmtBytes(b) { @@ -139,7 +142,6 @@ function setState(next) { if (next === 'disconnected') { statusLabel.textContent = t('status_disconnected'); statusSub.textContent = t('hint_tap'); - statusLabel.classList.add(''); connInfo.classList.add('hidden'); metricDown.textContent = '0 B'; metricUp.textContent = '0 B'; @@ -193,6 +195,7 @@ async function poll() { try { const code = await invoke('get_tunnel_status'); if (!pollTimer) return; // Prevent race condition if disconnected during await + console.log('[OSTP] poll status code:', code); if (code === 0) { setState('disconnected'); return; } else if (code === 1) setState('connecting'); @@ -203,8 +206,13 @@ async function poll() { metricDown.textContent = fmtBytes(metrics.bytes_recv); metricUp.textContent = fmtBytes(metrics.bytes_sent); } - } catch { - if (pollTimer) setState('disconnected'); + } catch (err) { + console.error('[OSTP] poll threw:', err); + if (pollTimer) { + setState('disconnected'); + showToast(String(err), 'error'); + alert('[OSTP POLL ERROR] ' + String(err)); + } } } @@ -226,21 +234,24 @@ async function handleToggle() { setState('connecting'); try { + console.log('[OSTP] invoking start_tunnel...'); const ok = await invoke('start_tunnel'); + console.log('[OSTP] start_tunnel returned:', ok); if (ok) { startPolling(); } else { setState('disconnected'); showToast(t('toast_error') || 'Failed to connect', 'error'); - alert(t('toast_error') || 'Failed to connect'); + alert('[OSTP] start_tunnel returned false'); } } catch (err) { + console.error('[OSTP] start_tunnel threw:', err); setState('disconnected'); - if (err === "WINTUN_MISSING") { - wintunModal.classList.remove('hidden'); + if (String(err).includes("WINTUN_MISSING")) { + if (wintunModal) wintunModal.classList.remove('hidden'); } else { showToast(String(err), 'error'); - alert(String(err)); + alert('[OSTP ERROR] ' + String(err)); } } } else { @@ -293,6 +304,9 @@ async function loadConfigIntoForm() { updateKillSwitchVisibility(); inDebug.checked = !!c.debug; + if (inAutoconnect) inAutoconnect.checked = !!c.gui?.autoconnect; + if (inLaunchStartup) inLaunchStartup.checked = !!c.gui?.launch_startup; + const ex = c.exclude || {}; inDomains.value = (ex.domains || []).join('\n'); @@ -324,6 +338,17 @@ async function handleSave(silent = false) { rawConfig.access_key = key; rawConfig.socks5_bind = inSocks.value.trim() || null; rawConfig.debug = inDebug.checked; + if (inAutoconnect || inLaunchStartup) { + rawConfig.gui = rawConfig.gui || {}; + if (inAutoconnect) rawConfig.gui.autoconnect = inAutoconnect.checked; + if (inLaunchStartup) rawConfig.gui.launch_startup = inLaunchStartup.checked; + } + + if (inLaunchStartup) { + try { await invoke('set_autostart', { enable: inLaunchStartup.checked }); } catch (err) { console.error('autostart error', err); } + } + + rawConfig.transport = rawConfig.transport || {}; rawConfig.transport.mode = inTransport.value; @@ -429,11 +454,33 @@ window.addEventListener('DOMContentLoaded', async () => { if (window.__TAURI__ && window.__TAURI__.event) { window.__TAURI__.event.listen('tunnel-error', (evt) => { setState('disconnected'); - showToast(String(evt.payload), 'error'); - alert(String(evt.payload)); + const errStr = String(evt.payload); + showToast(errStr, 'error'); + alert(errStr); }); } + // Load wintun install path for modal instruction + if (wintunInstallPath) { + try { + const p = await invoke('get_wintun_install_path'); + if (p) wintunInstallPath.textContent = p; + } catch { /* ignore */ } + } + + // Auto-connect on startup + try { + const raw = await invoke('get_config'); + rawConfig = JSON.parse(raw); + if (rawConfig?.gui?.autoconnect) { + setTimeout(() => { + if (appState === 'disconnected') handleToggle(); + }, 800); + } + } catch (err) { + console.error('Failed to load config on startup', err); + } + btnConnect.addEventListener('click', handleToggle); if (btnAutoConnect) { @@ -547,22 +594,18 @@ window.addEventListener('DOMContentLoaded', async () => { wintunModal.classList.add('hidden'); }); - btnWintunDownload.addEventListener('click', async () => { - try { - btnWintunDownload.disabled = true; - btnWintunDownload.textContent = "Downloading..."; - await invoke('download_wintun'); - wintunModal.classList.add('hidden'); - showToast("Wintun driver downloaded successfully!", "ok"); - handleToggle(); - } catch (err) { - showToast("Failed to download: " + err, "error"); - alert("Download failed: " + err); - } finally { - btnWintunDownload.disabled = false; - btnWintunDownload.textContent = "Download"; - } - }); + // Open wintun.net link — handled natively by , but also wire as fallback + if (btnWintunOpen && window.__TAURI__) { + btnWintunOpen.addEventListener('click', (e) => { + e.preventDefault(); + const opener = window.__TAURI__?.opener || window.__TAURI__?.shell; + if (opener && opener.open) { + opener.open('https://www.wintun.net'); + } else { + window.open('https://www.wintun.net', '_blank'); + } + }); + } async function runPingTest() { pingValueTxt.textContent = 'Testing...'; diff --git a/ostp-gui/src/styles.css b/ostp-gui/src/styles.css index 34d2417..8478ad2 100644 --- a/ostp-gui/src/styles.css +++ b/ostp-gui/src/styles.css @@ -929,13 +929,37 @@ input, textarea { font-family: inherit; } border: 1px solid var(--c-card-border); padding: 20px; border-radius: var(--r-md); - width: 280px; + width: 300px; box-shadow: 0 10px 40px rgba(0,0,0,0.6); display: flex; flex-direction: column; - gap: 12px; + gap: 10px; } +.modal-steps { + margin: 2px 0 0 0; + padding-left: 18px; + font-size: 0.76rem; + color: var(--c-txt-2); + line-height: 1.7; +} +.modal-steps li { margin-bottom: 2px; } +.modal-steps code { + background: rgba(255,255,255,0.07); + border-radius: 3px; + padding: 1px 5px; + font-family: monospace; + font-size: 0.74rem; + word-break: break-all; + color: var(--c-accent, #a78bfa); +} +.modal-actions a.btn { + display: inline-block; + text-decoration: none; + cursor: pointer; +} + + .modal-title { font-size: 0.9rem; font-weight: 600; diff --git a/ostp-server/src/fallback.rs b/ostp-server/src/fallback.rs index 61abaa2..bc83ca2 100644 --- a/ostp-server/src/fallback.rs +++ b/ostp-server/src/fallback.rs @@ -50,7 +50,7 @@ pub async fn start_fallback_server(config: FallbackConfig) { } } -async fn proxy_connection(mut client: TcpStream, target: &str) -> anyhow::Result<()> { +pub async fn proxy_connection(mut client: TcpStream, target: &str) -> anyhow::Result<()> { let mut upstream = TcpStream::connect(target).await?; let (mut client_read, mut client_write) = client.split(); diff --git a/ostp-server/src/lib.rs b/ostp-server/src/lib.rs index 47e30a0..10d2a8d 100644 --- a/ostp-server/src/lib.rs +++ b/ostp-server/src/lib.rs @@ -284,10 +284,11 @@ pub async fn run_server( } // Spawn Fallback TCP proxy if configured - if let Some(fb_cfg) = fallback_config { + if let Some(ref fb_cfg) = fallback_config { if fb_cfg.enabled { + let fb_cfg_clone = fb_cfg.clone(); tokio::spawn(async move { - fallback::start_fallback_server(fb_cfg).await; + fallback::start_fallback_server(fb_cfg_clone).await; }); } } @@ -328,9 +329,10 @@ pub async fn run_server( tracing::info!(listeners = bind_addrs.len(), keys = key_count, "server started"); tracing::info!("ARQ config: max_reorder=16384, reorder_buf=8192, sent_history=32768, rto=100ms"); let reality_config_arc = reality_config.map(std::sync::Arc::new); + let fallback_target = fallback_config.as_ref().and_then(|f| if f.enabled { Some(f.target.clone()) } else { None }); tokio::select! { - res = run_server_loop(bind_addrs.clone(), primary_socket, sockets, dispatcher, ui_cmd_rx, ui_event_tx, shared_keys, router, reality_config_arc) => { + res = run_server_loop(bind_addrs.clone(), primary_socket, sockets, dispatcher, ui_cmd_rx, ui_event_tx, shared_keys, router, reality_config_arc, fallback_target) => { if let Err(e) = res { tracing::error!("Server error: {e}"); } @@ -355,6 +357,7 @@ async fn run_server_loop( shared_keys: std::sync::Arc>>, router: std::sync::Arc, reality_config: Option>, + fallback_target: Option, ) -> Result<()> { let mut remotes: HashMap<(u32, u16), RemoteState> = HashMap::new(); let (stream_tx, mut stream_rx) = mpsc::unbounded_channel::<(u32, u16, Vec)>(); @@ -392,6 +395,7 @@ async fn run_server_loop( let shared_keys_clone = shared_keys.clone(); let udp_tx_clone = udp_tx.clone(); let reality_config_outer = reality_config.clone(); + let fb_target_outer = fallback_target.clone(); tokio::spawn(async move { if let Ok(listener) = tokio::net::TcpListener::bind(&addr).await { @@ -431,8 +435,9 @@ async fn run_server_loop( let keys = shared_keys_clone.clone(); let tx = udp_tx_clone.clone(); let reality = reality_config_outer.clone(); + let fb_target = fb_target_outer.clone(); tokio::spawn(async move { - if let Err(e) = crate::transport::uot::handle_tcp_connection(stream, peer_addr, keys, tx, tm, reality).await { + if let Err(e) = crate::transport::uot::handle_tcp_connection(stream, peer_addr, keys, tx, tm, reality, fb_target).await { tracing::warn!("UoT connection from {} closed: {}", peer_addr, e); } }); diff --git a/ostp-server/src/transport/uot.rs b/ostp-server/src/transport/uot.rs index 10b4f32..e6b2f4c 100644 --- a/ostp-server/src/transport/uot.rs +++ b/ostp-server/src/transport/uot.rs @@ -27,6 +27,7 @@ pub async fn handle_tcp_connection( udp_tx: mpsc::Sender<(Bytes, SocketAddr)>, tcp_map: Arc>>>, reality_config: Option>, + fb_target: Option, ) -> Result<()> where S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static, @@ -61,9 +62,16 @@ where if let Some(rc) = reality_config { return handle_reality_connection(stream, initial_buf[..header_len].to_vec(), peer_addr, shared_keys, udp_tx, tcp_map, rc).await; } else { - // Received TLS but Reality is not enabled, maybe forward to a default fallback? - // For now, just drop - anyhow::bail!("received TLS but Reality is not configured"); + // Received TLS but Reality is not enabled + if let Some(target) = fb_target { + tracing::info!("Fallback triggered for {} -> {}", peer_addr, target); + let mut dest_stream: TcpStream = TcpStream::connect(&target).await?; + dest_stream.write_all(&initial_buf[..header_len]).await?; + tokio::io::copy_bidirectional(&mut stream, &mut dest_stream).await?; + return Ok(()); + } else { + anyhow::bail!("received TLS but Reality is not configured and no fallback target"); + } } } @@ -89,10 +97,16 @@ where } else if headers_str.starts_with("GET /stream HTTP/1.1\r\n") { false } else { - // Not a valid OSTP path. If Reality fallback was configured but we received plain HTTP, maybe fallback? - // Actually fallback is handled above for TLS. For HTTP, we just 404. - let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; - anyhow::bail!("invalid request line"); + if let Some(target) = fb_target { + tracing::info!("Fallback triggered for {} -> {}", peer_addr, target); + let mut dest_stream: TcpStream = TcpStream::connect(&target).await?; + dest_stream.write_all(&initial_buf[..header_len]).await?; + tokio::io::copy_bidirectional(&mut stream, &mut dest_stream).await?; + return Ok(()); + } else { + let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; + anyhow::bail!("invalid request line"); + } }; // Extract Authorization @@ -107,16 +121,32 @@ where let sig_b64 = match signature_base64 { Some(s) => s, None => { - let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; - anyhow::bail!("missing authorization"); + if let Some(target) = fb_target { + tracing::info!("Fallback triggered for {} -> {}", peer_addr, target); + let mut dest_stream: TcpStream = TcpStream::connect(&target).await?; + dest_stream.write_all(&initial_buf[..header_len]).await?; + tokio::io::copy_bidirectional(&mut stream, &mut dest_stream).await?; + return Ok(()); + } else { + let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; + anyhow::bail!("missing authorization"); + } } }; let sig_bytes = match base64::Engine::decode(&base64::engine::general_purpose::STANDARD_NO_PAD, &sig_b64) { Ok(b) => b, Err(_) => { - let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; - anyhow::bail!("invalid base64 signature"); + if let Some(target) = fb_target { + tracing::info!("Fallback triggered for {} -> {}", peer_addr, target); + let mut dest_stream: TcpStream = TcpStream::connect(&target).await?; + dest_stream.write_all(&initial_buf[..header_len]).await?; + tokio::io::copy_bidirectional(&mut stream, &mut dest_stream).await?; + return Ok(()); + } else { + let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; + anyhow::bail!("invalid base64 signature"); + } } }; @@ -153,8 +183,16 @@ where } if !authenticated { - let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; - anyhow::bail!("unauthorized (invalid HMAC)"); + if let Some(target) = fb_target { + tracing::info!("Fallback triggered for {} -> {}", peer_addr, target); + let mut dest_stream: TcpStream = TcpStream::connect(&target).await?; + dest_stream.write_all(&initial_buf[..header_len]).await?; + tokio::io::copy_bidirectional(&mut stream, &mut dest_stream).await?; + return Ok(()); + } else { + let _ = stream.write_all(b"HTTP/1.1 404 Not Found\r\n\r\n").await; + anyhow::bail!("unauthorized (invalid HMAC)"); + } } if wss { diff --git a/ostp/src/main.rs b/ostp/src/main.rs index 512ae6e..681d491 100644 --- a/ostp/src/main.rs +++ b/ostp/src/main.rs @@ -109,7 +109,6 @@ fn parse_ostp_link(link: &str) -> Result { transport: Some(TransportConfigRaw { mode: Some(transport_mode), stealth_sni: Some(sni.clone()), - stealth_port: Some(443), wss: Some(wss_enabled), }), socks5_bind: Some("127.0.0.1:1088".to_string()), @@ -347,7 +346,6 @@ struct ClientConfig { struct TransportConfigRaw { mode: Option, stealth_sni: Option, - stealth_port: Option, wss: Option, } @@ -857,7 +855,6 @@ async fn run_app() -> Result<()> { "transport": {{ "mode": "udp", "stealth_sni": "www.microsoft.com", - "stealth_port": 443, "wss": false }}, @@ -1232,7 +1229,6 @@ async fn run_client_directly(client_cfg: ClientConfig) -> Result<()> { transport: ostp_client::config::TransportConfig { mode: client_cfg.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(|| "udp".to_string()), stealth_sni: client_cfg.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_else(|| "microsoft.com".to_string()), - stealth_port: client_cfg.transport.as_ref().and_then(|t| t.stealth_port).unwrap_or(443), wss: client_cfg.transport.as_ref().and_then(|t| t.wss).unwrap_or(false), }, dns_server: client_cfg.tun.as_ref().and_then(|t| t.dns.clone()), diff --git a/test.json b/test.json index 4b74d8df0fb5e83af144efa6175e18ced047a408..46b134b197f35e75e0784bedbf94a8dd124693b1 100644 GIT binary patch literal 2 JcmezW4*&xG0sa60 literal 126 zcmezWubM%LL4hHcA)g_IA(bJ9!3xNWVJHT&ix|qlWDJ827BP^zYM{y_hD?S$pk9d1 jXdrFKV8md~pvPbU#fCsLO@TZJjA4jns0Bh^1}+8w1`-tM