chore: linting

This commit is contained in:
zhom
2026-04-19 21:07:10 +04:00
parent c4c6ec9dfd
commit a1170b586a
6 changed files with 105 additions and 39 deletions
+1 -1
View File
@@ -362,7 +362,7 @@ impl ExtensionManager {
}
}
extensions.sort_by(|a, b| a.created_at.cmp(&b.created_at));
extensions.sort_by_key(|a| a.created_at);
Ok(extensions)
}
+41
View File
@@ -1422,11 +1422,43 @@ pub fn run() {
// Without this cleanup, users on Windows accumulate dozens of idle workers
// (one per profile launch) that the periodic cleanup won't touch because
// profile-associated workers are deliberately skipped to avoid regressions.
//
// Preserves workers whose associated profile still has a running browser
// process — if the app crashed while a browser was running, its detached
// browser keeps going and needs the proxy/VPN worker to stay alive.
tauri::async_runtime::spawn(async move {
use crate::proxy_storage::{delete_proxy_config, is_process_running, list_proxy_configs};
use crate::vpn_worker_storage::{delete_vpn_worker_config, list_vpn_worker_configs};
// Build sets of (profile_id, vpn_id) whose browsers are still running
let profile_manager = crate::profile::ProfileManager::instance();
let profiles = profile_manager.list_profiles().unwrap_or_default();
let running_profile_ids: std::collections::HashSet<String> = profiles
.iter()
.filter(|p| p.process_id.is_some_and(is_process_running))
.map(|p| p.id.to_string())
.collect();
let running_vpn_ids: std::collections::HashSet<String> = profiles
.iter()
.filter(|p| p.process_id.is_some_and(is_process_running))
.filter_map(|p| p.vpn_id.clone())
.collect();
for config in list_proxy_configs() {
let has_running_browser = config
.profile_id
.as_ref()
.is_some_and(|pid| running_profile_ids.contains(pid));
if has_running_browser {
log::info!(
"Startup: preserving proxy worker {} (profile browser still running)",
config.id
);
continue;
}
if let Some(pid) = config.pid {
if is_process_running(pid) {
log::info!(
@@ -1442,6 +1474,15 @@ pub fn run() {
}
for worker in list_vpn_worker_configs() {
if running_vpn_ids.contains(&worker.vpn_id) {
log::info!(
"Startup: preserving VPN worker {} (profile browser using vpn_id {} still running)",
worker.id,
worker.vpn_id
);
continue;
}
if let Some(pid) = worker.pid {
if is_process_running(pid) {
log::info!(
+1 -5
View File
@@ -230,11 +230,7 @@ impl SyncProgressTracker {
let elapsed = self.start_time.elapsed().as_secs_f64().max(0.1);
let speed = (completed_bytes as f64 / elapsed) as u64;
let remaining_bytes = self.total_bytes.saturating_sub(completed_bytes);
let eta = if speed > 0 {
remaining_bytes / speed
} else {
0
};
let eta = remaining_bytes.checked_div(speed).unwrap_or(0);
let _ = events::emit(
"profile-sync-progress",
+57 -26
View File
@@ -141,11 +141,15 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
let mut peer: HashMap<String, String> = HashMap::new();
let mut current_section: Option<&str> = None;
// Strip a UTF-8 BOM if present — some editors/tools emit one and it would
// otherwise prepend invisible bytes to the first section header
let content = content.strip_prefix('\u{feff}').unwrap_or(content);
for line in content.lines() {
let line = line.trim();
// Skip empty lines and comments
if line.is_empty() || line.starts_with('#') {
if line.is_empty() || line.starts_with('#') || line.starts_with(';') {
continue;
}
@@ -159,7 +163,7 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
continue;
}
// Parse key-value pairs
// Parse key-value pairs (split on the first `=` so base64 padding is preserved)
if let Some((key, value)) = line.split_once('=') {
let key = key.trim().to_string();
let value = value.trim().to_string();
@@ -181,6 +185,7 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
.get("PrivateKey")
.ok_or_else(|| VpnError::InvalidWireGuard("Missing PrivateKey in [Interface]".to_string()))?
.clone();
validate_wireguard_key(&private_key, "PrivateKey")?;
let address = interface
.get("Address")
@@ -191,6 +196,7 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
.get("PublicKey")
.ok_or_else(|| VpnError::InvalidWireGuard("Missing PublicKey in [Peer]".to_string()))?
.clone();
validate_wireguard_key(&peer_public_key, "PublicKey")?;
let peer_endpoint = peer
.get("Endpoint")
@@ -207,6 +213,9 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
let dns = interface.get("DNS").cloned();
let mtu = interface.get("MTU").and_then(|s| s.parse().ok());
let preshared_key = peer.get("PresharedKey").cloned();
if let Some(ref psk) = preshared_key {
validate_wireguard_key(psk, "PresharedKey")?;
}
Ok(WireGuardConfig {
private_key,
@@ -221,6 +230,30 @@ pub fn parse_wireguard_config(content: &str) -> Result<WireGuardConfig, VpnError
})
}
/// Validate that a WireGuard key is a base64-encoded 32-byte value.
/// Reports the field name and a short preview of the bad value so users can
/// see exactly what went wrong (e.g. a redacted/masked key).
fn validate_wireguard_key(key: &str, field: &str) -> Result<(), VpnError> {
use base64::Engine;
let decoded = base64::engine::general_purpose::STANDARD
.decode(key)
.map_err(|e| {
let preview: String = key.chars().take(8).collect();
VpnError::InvalidWireGuard(format!(
"{field} is not valid base64 (starts with {preview:?}): {e}. \
Expected a 32-byte base64-encoded key (44 chars ending with '=')."
))
})?;
if decoded.len() != 32 {
return Err(VpnError::InvalidWireGuard(format!(
"{field} decoded to {} bytes (expected 32). The config may be truncated or malformed.",
decoded.len()
)));
}
Ok(())
}
/// Parse an OpenVPN configuration file
pub fn parse_openvpn_config(content: &str) -> Result<OpenVpnConfig, VpnError> {
let mut remote_host = String::new();
@@ -250,31 +283,23 @@ pub fn parse_openvpn_config(content: &str) -> Result<OpenVpnConfig, VpnError> {
if parts.len() >= 2 {
remote_host = parts[1].to_string();
}
if parts.len() >= 3 {
if let Ok(port) = parts[2].parse() {
remote_port = port;
}
if let Some(port) = parts.get(2).and_then(|p| p.parse().ok()) {
remote_port = port;
}
if parts.len() >= 4 {
protocol = parts[3].to_string();
}
}
"proto" => {
if parts.len() >= 2 {
protocol = parts[1].to_string();
}
"proto" if parts.len() >= 2 => {
protocol = parts[1].to_string();
}
"port" => {
if parts.len() >= 2 {
if let Ok(port) = parts[1].parse() {
remote_port = port;
}
if let Some(port) = parts.get(1).and_then(|p| p.parse().ok()) {
remote_port = port;
}
}
"dev" => {
if parts.len() >= 2 {
dev_type = parts[1].to_string();
}
"dev" if parts.len() >= 2 => {
dev_type = parts[1].to_string();
}
_ => {}
}
@@ -348,13 +373,13 @@ mod tests {
fn test_parse_wireguard_config() {
let content = r#"
[Interface]
PrivateKey = WGTestPrivateKey123456789012345678901234567890
PrivateKey = YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=
Address = 10.0.0.2/24
DNS = 1.1.1.1
MTU = 1420
[Peer]
PublicKey = WGTestPublicKey1234567890123456789012345678901
PublicKey = YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
@@ -363,14 +388,14 @@ PersistentKeepalive = 25
let config = parse_wireguard_config(content).unwrap();
assert_eq!(
config.private_key,
"WGTestPrivateKey123456789012345678901234567890"
"YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE="
);
assert_eq!(config.address, "10.0.0.2/24");
assert_eq!(config.dns, Some("1.1.1.1".to_string()));
assert_eq!(config.mtu, Some(1420));
assert_eq!(
config.peer_public_key,
"WGTestPublicKey1234567890123456789012345678901"
"YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI="
);
assert_eq!(config.peer_endpoint, "vpn.example.com:51820");
assert_eq!(config.allowed_ips, vec!["0.0.0.0/0", "::/0"]);
@@ -381,20 +406,26 @@ PersistentKeepalive = 25
fn test_parse_wireguard_config_minimal() {
let content = r#"
[Interface]
PrivateKey = minimalkey
PrivateKey = YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=
Address = 10.0.0.2/32
[Peer]
PublicKey = peerpubkey
PublicKey = YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=
Endpoint = 1.2.3.4:51820
"#;
let config = parse_wireguard_config(content).unwrap();
assert_eq!(config.private_key, "minimalkey");
assert_eq!(
config.private_key,
"YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE="
);
assert_eq!(config.address, "10.0.0.2/32");
assert!(config.dns.is_none());
assert!(config.mtu.is_none());
assert_eq!(config.peer_public_key, "peerpubkey");
assert_eq!(
config.peer_public_key,
"YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI="
);
assert_eq!(config.peer_endpoint, "1.2.3.4:51820");
}
+4 -6
View File
@@ -622,12 +622,10 @@ impl WireGuardSocks5Server {
// smoltcp → Client
if socket.can_recv() {
match socket.recv(|data| (data.len(), data.to_vec())) {
Ok(data) if !data.is_empty() => {
if conn.tcp_stream.try_write(&data).is_err() {
socket.close();
completed.push(idx);
continue;
}
Ok(data) if !data.is_empty() && conn.tcp_stream.try_write(&data).is_err() => {
socket.close();
completed.push(idx);
continue;
}
_ => {}
}
+1 -1
View File
@@ -144,7 +144,7 @@ Endpoint = 1.2.3.4:51820
fn test_wireguard_config_missing_peer() {
let config = r#"
[Interface]
PrivateKey = somekey
PrivateKey = YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=
Address = 10.0.0.2/24
"#;
let result = parse_wireguard_config(config);