From c4bfd4e253624c110e39821dd032ae175d02b9c1 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:31:02 +0400 Subject: [PATCH] chore: linting --- src-tauri/src/camoufox/config.rs | 2 +- .../src/camoufox/fingerprint/bayesian_node.rs | 2 +- src-tauri/src/camoufox/geolocation.rs | 2 +- src-tauri/src/camoufox/webgl.rs | 2 +- src-tauri/src/human_typing.rs | 4 +- src-tauri/src/proxy_manager.rs | 193 ++++++++++++++++++ src-tauri/src/settings_manager.rs | 4 +- src-tauri/src/vpn/socks5_server.rs | 12 +- src-tauri/src/vpn/storage.rs | 2 +- 9 files changed, 208 insertions(+), 15 deletions(-) diff --git a/src-tauri/src/camoufox/config.rs b/src-tauri/src/camoufox/config.rs index 0ab1eca..faedb8d 100644 --- a/src-tauri/src/camoufox/config.rs +++ b/src-tauri/src/camoufox/config.rs @@ -2,7 +2,7 @@ //! //! Converts fingerprints to Camoufox configuration format and builds launch options. -use rand::Rng; +use rand::RngExt; use serde_yaml; use std::collections::HashMap; use std::path::Path; diff --git a/src-tauri/src/camoufox/fingerprint/bayesian_node.rs b/src-tauri/src/camoufox/fingerprint/bayesian_node.rs index d7893ef..44bdbdf 100644 --- a/src-tauri/src/camoufox/fingerprint/bayesian_node.rs +++ b/src-tauri/src/camoufox/fingerprint/bayesian_node.rs @@ -2,7 +2,7 @@ //! //! Implements weighted random sampling from conditional probability distributions. -use rand::Rng; +use rand::RngExt; use serde::Deserialize; use std::collections::HashMap; diff --git a/src-tauri/src/camoufox/geolocation.rs b/src-tauri/src/camoufox/geolocation.rs index ef645af..c95fb99 100644 --- a/src-tauri/src/camoufox/geolocation.rs +++ b/src-tauri/src/camoufox/geolocation.rs @@ -9,7 +9,7 @@ use directories::BaseDirs; use maxminddb::{geoip2, Reader}; use quick_xml::events::Event; use quick_xml::Reader as XmlReader; -use rand::Rng; +use rand::RngExt; use std::collections::HashMap; use std::net::IpAddr; use std::path::PathBuf; diff --git a/src-tauri/src/camoufox/webgl.rs b/src-tauri/src/camoufox/webgl.rs index 04b3a8a..7cf5597 100644 --- a/src-tauri/src/camoufox/webgl.rs +++ b/src-tauri/src/camoufox/webgl.rs @@ -2,7 +2,7 @@ //! //! Samples realistic WebGL configurations based on OS-specific probability distributions. -use rand::Rng; +use rand::RngExt; use rusqlite::{Connection, Result as SqliteResult}; use std::collections::HashMap; use std::io::Write; diff --git a/src-tauri/src/human_typing.rs b/src-tauri/src/human_typing.rs index d137edd..f9b7c4a 100644 --- a/src-tauri/src/human_typing.rs +++ b/src-tauri/src/human_typing.rs @@ -1,4 +1,4 @@ -use rand::Rng; +use rand::{Rng, RngExt}; use std::collections::{HashMap, HashSet}; const PROB_ERROR: f64 = 0.04; @@ -117,7 +117,7 @@ fn normal_sample(rng: &mut impl Rng, mean: f64, std_dev: f64) -> f64 { // Box-Muller transform let u1: f64 = rng.random::().max(1e-10); let u2: f64 = rng.random::(); - let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos(); + let z = (-2.0_f64 * u1.ln()).sqrt() * (2.0_f64 * std::f64::consts::PI * u2).cos(); mean + std_dev * z } diff --git a/src-tauri/src/proxy_manager.rs b/src-tauri/src/proxy_manager.rs index 4c05445..0462e00 100644 --- a/src-tauri/src/proxy_manager.rs +++ b/src-tauri/src/proxy_manager.rs @@ -3391,4 +3391,197 @@ mod tests { delete_proxy_config(&id); } + + #[test] + fn test_parse_dynamic_proxy_json_standard_format() { + let body = r#"{"ip": "1.2.3.4", "port": 8080, "username": "user1", "password": "pass1"}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert_eq!(result.host, "1.2.3.4"); + assert_eq!(result.port, 8080); + assert_eq!(result.proxy_type, "http"); + assert_eq!(result.username.as_deref(), Some("user1")); + assert_eq!(result.password.as_deref(), Some("pass1")); + } + + #[test] + fn test_parse_dynamic_proxy_json_host_alias() { + let body = r#"{"host": "proxy.example.com", "port": 3128}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert_eq!(result.host, "proxy.example.com"); + assert_eq!(result.port, 3128); + assert!(result.username.is_none()); + assert!(result.password.is_none()); + } + + #[test] + fn test_parse_dynamic_proxy_json_user_pass_aliases() { + let body = r#"{"ip": "10.0.0.1", "port": 1080, "user": "u", "pass": "p"}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert_eq!(result.username.as_deref(), Some("u")); + assert_eq!(result.password.as_deref(), Some("p")); + } + + #[test] + fn test_parse_dynamic_proxy_json_port_as_string() { + let body = r#"{"ip": "1.2.3.4", "port": "9090"}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert_eq!(result.port, 9090); + } + + #[test] + fn test_parse_dynamic_proxy_json_with_proxy_type() { + let body = r#"{"ip": "1.2.3.4", "port": 1080, "type": "socks5"}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert_eq!(result.proxy_type, "socks5"); + + let body2 = r#"{"ip": "1.2.3.4", "port": 1080, "proxy_type": "socks4"}"#; + let result2 = ProxyManager::parse_dynamic_proxy_json(body2).unwrap(); + assert_eq!(result2.proxy_type, "socks4"); + } + + #[test] + fn test_parse_dynamic_proxy_json_empty_credentials_treated_as_none() { + let body = r#"{"ip": "1.2.3.4", "port": 8080, "username": "", "password": ""}"#; + let result = ProxyManager::parse_dynamic_proxy_json(body).unwrap(); + assert!(result.username.is_none()); + assert!(result.password.is_none()); + } + + #[test] + fn test_parse_dynamic_proxy_json_missing_ip() { + let body = r#"{"port": 8080}"#; + let err = ProxyManager::parse_dynamic_proxy_json(body).unwrap_err(); + assert!(err.contains("ip") || err.contains("host")); + } + + #[test] + fn test_parse_dynamic_proxy_json_missing_port() { + let body = r#"{"ip": "1.2.3.4"}"#; + let err = ProxyManager::parse_dynamic_proxy_json(body).unwrap_err(); + assert!(err.contains("port")); + } + + #[test] + fn test_parse_dynamic_proxy_json_invalid_json() { + let err = ProxyManager::parse_dynamic_proxy_json("not json").unwrap_err(); + assert!(err.contains("Invalid JSON")); + } + + #[test] + fn test_parse_dynamic_proxy_json_not_object() { + let err = ProxyManager::parse_dynamic_proxy_json("[1,2,3]").unwrap_err(); + assert!(err.contains("not an object")); + } + + #[test] + fn test_parse_dynamic_proxy_text_host_port_user_pass() { + let body = "proxy.example.com:8080:user1:pass1"; + let result = ProxyManager::parse_dynamic_proxy_text(body).unwrap(); + assert_eq!(result.host, "proxy.example.com"); + assert_eq!(result.port, 8080); + assert_eq!(result.username.as_deref(), Some("user1")); + assert_eq!(result.password.as_deref(), Some("pass1")); + } + + #[test] + fn test_parse_dynamic_proxy_text_protocol_url_format() { + let body = "http://user:pass@proxy.example.com:3128"; + let result = ProxyManager::parse_dynamic_proxy_text(body).unwrap(); + assert_eq!(result.host, "proxy.example.com"); + assert_eq!(result.port, 3128); + assert_eq!(result.proxy_type, "http"); + assert_eq!(result.username.as_deref(), Some("user")); + assert_eq!(result.password.as_deref(), Some("pass")); + } + + #[test] + fn test_parse_dynamic_proxy_text_with_whitespace() { + let body = " \n proxy.example.com:8080:user:pass \n "; + let result = ProxyManager::parse_dynamic_proxy_text(body).unwrap(); + assert_eq!(result.host, "proxy.example.com"); + assert_eq!(result.port, 8080); + } + + #[test] + fn test_parse_dynamic_proxy_text_empty() { + let err = ProxyManager::parse_dynamic_proxy_text("").unwrap_err(); + assert!(err.contains("Empty")); + } + + #[test] + fn test_parse_dynamic_proxy_text_whitespace_only() { + let err = ProxyManager::parse_dynamic_proxy_text(" \n \n ").unwrap_err(); + assert!(err.contains("Empty")); + } + + #[test] + fn test_stored_proxy_is_dynamic() { + let mut proxy = StoredProxy::new( + "test".to_string(), + ProxySettings { + proxy_type: "http".to_string(), + host: "h.com".to_string(), + port: 80, + username: None, + password: None, + }, + ); + assert!(!proxy.is_dynamic()); + + proxy.dynamic_proxy_url = Some("https://api.example.com/proxy".to_string()); + assert!(proxy.is_dynamic()); + } + + #[test] + fn test_is_dynamic_proxy_via_manager() { + let pm = ProxyManager::new(); + + let mut proxy = StoredProxy::new( + "DynTest".to_string(), + ProxySettings { + proxy_type: "http".to_string(), + host: "dynamic".to_string(), + port: 0, + username: None, + password: None, + }, + ); + proxy.dynamic_proxy_url = Some("https://api.example.com/proxy".to_string()); + proxy.dynamic_proxy_format = Some("json".to_string()); + + let id = proxy.id.clone(); + pm.stored_proxies.lock().unwrap().insert(id.clone(), proxy); + + assert!(pm.is_dynamic_proxy(&id)); + assert!(!pm.is_dynamic_proxy("nonexistent")); + } + + #[tokio::test] + async fn test_resolve_dynamic_proxy_not_dynamic() { + let pm = ProxyManager::new(); + + let proxy = StoredProxy::new( + "Regular".to_string(), + ProxySettings { + proxy_type: "http".to_string(), + host: "1.2.3.4".to_string(), + port: 8080, + username: None, + password: None, + }, + ); + let id = proxy.id.clone(); + pm.stored_proxies.lock().unwrap().insert(id.clone(), proxy); + + let err = pm.resolve_dynamic_proxy(&id).await.unwrap_err(); + assert!(err.contains("not a dynamic proxy")); + } + + #[tokio::test] + async fn test_resolve_dynamic_proxy_not_found() { + let pm = ProxyManager::new(); + + let err = pm.resolve_dynamic_proxy("nonexistent").await.unwrap_err(); + assert!(err.contains("not found")); + } } diff --git a/src-tauri/src/settings_manager.rs b/src-tauri/src/settings_manager.rs index 0ca9ee3..0cd96de 100644 --- a/src-tauri/src/settings_manager.rs +++ b/src-tauri/src/settings_manager.rs @@ -200,7 +200,7 @@ impl SettingsManager { ) -> Result> { // Generate a secure random token (base64 encoded for URL safety) let token_bytes: [u8; 32] = { - use rand::RngCore; + use rand::Rng; let mut rng = rand::rng(); let mut bytes = [0u8; 32]; rng.fill_bytes(&mut bytes); @@ -390,7 +390,7 @@ impl SettingsManager { app_handle: &tauri::AppHandle, ) -> Result> { let token_bytes: [u8; 32] = { - use rand::RngCore; + use rand::Rng; let mut rng = rand::rng(); let mut bytes = [0u8; 32]; rng.fill_bytes(&mut bytes); diff --git a/src-tauri/src/vpn/socks5_server.rs b/src-tauri/src/vpn/socks5_server.rs index f53f711..b2ccd5a 100644 --- a/src-tauri/src/vpn/socks5_server.rs +++ b/src-tauri/src/vpn/socks5_server.rs @@ -73,11 +73,11 @@ struct WgRxToken { } impl RxToken for WgRxToken { - fn consume(mut self, f: F) -> R + fn consume(self, f: F) -> R where - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&[u8]) -> R, { - f(&mut self.data) + f(&self.data) } } @@ -173,7 +173,7 @@ fn parse_cidr_address(addr: &str) -> Result<(IpCidr, IpAddress), VpnError> { )) } std::net::IpAddr::V6(v6) => { - let smol_ip = smoltcp::wire::Ipv6Address::from_bytes(&v6.octets()); + let smol_ip = smoltcp::wire::Ipv6Address::from(v6.octets()); Ok(( IpCidr::new(IpAddress::Ipv6(smol_ip), prefix), IpAddress::Ipv6(smol_ip), @@ -331,7 +331,7 @@ impl WireGuardSocks5Server { // Set default gateway match local_ip { IpAddress::Ipv4(v4) => { - let octets = v4.as_bytes(); + let octets = v4.octets(); let gw = Ipv4Address::new(octets[0], octets[1], octets[2], 1); iface .routes_mut() @@ -523,7 +523,7 @@ impl WireGuardSocks5Server { IpAddress::Ipv4(Ipv4Address::new(o[0], o[1], o[2], o[3])) } std::net::IpAddr::V6(v6) => { - IpAddress::Ipv6(smoltcp::wire::Ipv6Address::from_bytes(&v6.octets())) + IpAddress::Ipv6(smoltcp::wire::Ipv6Address::from(v6.octets())) } }; diff --git a/src-tauri/src/vpn/storage.rs b/src-tauri/src/vpn/storage.rs index f783741..2cffb31 100644 --- a/src-tauri/src/vpn/storage.rs +++ b/src-tauri/src/vpn/storage.rs @@ -6,7 +6,7 @@ use aes_gcm::{ Aes256Gcm, Nonce, }; use chrono::Utc; -use rand::Rng; +use rand::RngExt; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf;