Refactor Tauri crate into a library and add OS version header
This commit is contained in:
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
@@ -2326,6 +2326,7 @@ dependencies = [
|
|||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -22,3 +22,6 @@ reqwest = { version = "0.12", default-features = false, features = ["blocking",
|
|||||||
percent-encoding = "2"
|
percent-encoding = "2"
|
||||||
url = "2"
|
url = "2"
|
||||||
uuid = { version = "1", features = ["v4"] }
|
uuid = { version = "1", features = ["v4"] }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
winreg = "0.55"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#[cfg(not(test))]
|
|
||||||
use crate::adapters::proxy_router::{
|
use crate::adapters::proxy_router::{
|
||||||
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
||||||
ProxyRouterRequest,
|
ProxyRouterRequest,
|
||||||
@@ -7,11 +6,6 @@ use crate::models::{
|
|||||||
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItemType, Protocol,
|
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItemType, Protocol,
|
||||||
ProxyProtocol, Target,
|
ProxyProtocol, Target,
|
||||||
};
|
};
|
||||||
#[cfg(test)]
|
|
||||||
use crate::proxy_router::{
|
|
||||||
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
|
||||||
ProxyRouterRequest,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub const PROXIFYRE_ADAPTER_ID: &str = "proxifyre";
|
pub const PROXIFYRE_ADAPTER_ID: &str = "proxifyre";
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
#[cfg(not(test))]
|
|
||||||
use crate::adapters::proxifyre::{ProxiFyreAdapter, ProxiFyreConfig, ProxiFyreProxy};
|
use crate::adapters::proxifyre::{ProxiFyreAdapter, ProxiFyreConfig, ProxiFyreProxy};
|
||||||
#[cfg(not(test))]
|
|
||||||
use crate::adapters::proxy_router::{
|
use crate::adapters::proxy_router::{
|
||||||
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
||||||
ProxyRouterRequest,
|
ProxyRouterRequest,
|
||||||
};
|
};
|
||||||
#[cfg(not(test))]
|
|
||||||
use crate::adapters::singbox::{
|
use crate::adapters::singbox::{
|
||||||
SingBoxAdapter, SingBoxCheckResult, SingBoxCommandChecker, SingBoxConfigChecker,
|
SingBoxAdapter, SingBoxCheckResult, SingBoxCommandChecker, SingBoxConfigChecker,
|
||||||
SingBoxConfigError, SingBoxConfigErrorKind, SingBoxGeneratedConfig, SingBoxGenerationRequest,
|
SingBoxConfigError, SingBoxConfigErrorKind, SingBoxGeneratedConfig, SingBoxGenerationRequest,
|
||||||
@@ -21,18 +18,6 @@ use crate::models::{
|
|||||||
SubscriptionCache, SubscriptionServer, Target, TargetInput, TargetKind,
|
SubscriptionCache, SubscriptionServer, Target, TargetInput, TargetKind,
|
||||||
};
|
};
|
||||||
use crate::process::command_no_window;
|
use crate::process::command_no_window;
|
||||||
#[cfg(test)]
|
|
||||||
use crate::proxifyre::{ProxiFyreAdapter, ProxiFyreConfig, ProxiFyreProxy};
|
|
||||||
#[cfg(test)]
|
|
||||||
use crate::proxy_router::{
|
|
||||||
ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig,
|
|
||||||
ProxyRouterRequest,
|
|
||||||
};
|
|
||||||
#[cfg(test)]
|
|
||||||
use crate::singbox::{
|
|
||||||
SingBoxAdapter, SingBoxCheckResult, SingBoxCommandChecker, SingBoxConfigChecker,
|
|
||||||
SingBoxConfigError, SingBoxConfigErrorKind, SingBoxGeneratedConfig, SingBoxGenerationRequest,
|
|
||||||
};
|
|
||||||
use crate::singbox_service::{
|
use crate::singbox_service::{
|
||||||
build_singbox_setup_status, ensure_safe_singbox_install_dir,
|
build_singbox_setup_status, ensure_safe_singbox_install_dir,
|
||||||
parse_service_command_output as parse_singbox_service_command_output, service_control_script,
|
parse_service_command_output as parse_singbox_service_command_output, service_control_script,
|
||||||
@@ -1327,10 +1312,29 @@ pub fn apply_profiles_with_services(
|
|||||||
adapter: &impl ProxyRouterAdapter,
|
adapter: &impl ProxyRouterAdapter,
|
||||||
helper: &impl ProxyApplyHelper,
|
helper: &impl ProxyApplyHelper,
|
||||||
clock: &impl Clock,
|
clock: &impl Clock,
|
||||||
|
) -> Result<ApplyProfilesResponse, CommandError> {
|
||||||
|
apply_profiles_with_services_and_detection(
|
||||||
|
storage,
|
||||||
|
adapter,
|
||||||
|
helper,
|
||||||
|
clock,
|
||||||
|
detect_proxyfier_install(),
|
||||||
|
detect_singbox_install(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_profiles_with_services_and_detection(
|
||||||
|
storage: &JsonStorage,
|
||||||
|
adapter: &impl ProxyRouterAdapter,
|
||||||
|
helper: &impl ProxyApplyHelper,
|
||||||
|
clock: &impl Clock,
|
||||||
|
detected_proxyfier: Option<DetectedProxyfier>,
|
||||||
|
detected_singbox: Option<DetectedSingBox>,
|
||||||
) -> Result<ApplyProfilesResponse, CommandError> {
|
) -> Result<ApplyProfilesResponse, CommandError> {
|
||||||
let profiles = storage.read_profiles().map_err(storage_error)?;
|
let profiles = storage.read_profiles().map_err(storage_error)?;
|
||||||
let targets = storage.read_targets().map_err(storage_error)?;
|
let targets = storage.read_targets().map_err(storage_error)?;
|
||||||
let components = components_or_defaults(storage)?;
|
let components =
|
||||||
|
components_or_defaults_with_detection(storage, detected_proxyfier, detected_singbox)?;
|
||||||
let generated =
|
let generated =
|
||||||
match adapter.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components)) {
|
match adapter.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components)) {
|
||||||
Ok(generated) => generated,
|
Ok(generated) => generated,
|
||||||
@@ -2441,7 +2445,7 @@ try {{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn singbox_installer_runner_script(
|
pub fn singbox_installer_runner_script(
|
||||||
installer_path: &Path,
|
installer_path: &Path,
|
||||||
result_path: &Path,
|
result_path: &Path,
|
||||||
installer_args: &[String],
|
installer_args: &[String],
|
||||||
@@ -2560,11 +2564,23 @@ fn elevated_singbox_service_failed_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn components_or_defaults(storage: &JsonStorage) -> Result<Vec<ComponentStatus>, CommandError> {
|
fn components_or_defaults(storage: &JsonStorage) -> Result<Vec<ComponentStatus>, CommandError> {
|
||||||
|
components_or_defaults_with_detection(
|
||||||
|
storage,
|
||||||
|
detect_proxyfier_install(),
|
||||||
|
detect_singbox_install(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn components_or_defaults_with_detection(
|
||||||
|
storage: &JsonStorage,
|
||||||
|
detected_proxyfier: Option<DetectedProxyfier>,
|
||||||
|
detected_singbox: Option<DetectedSingBox>,
|
||||||
|
) -> Result<Vec<ComponentStatus>, CommandError> {
|
||||||
let components = storage.read_components().map_err(storage_error)?;
|
let components = storage.read_components().map_err(storage_error)?;
|
||||||
Ok(resolve_component_statuses(
|
Ok(resolve_component_statuses(
|
||||||
components,
|
components,
|
||||||
detect_proxyfier_install(),
|
detected_proxyfier,
|
||||||
detect_singbox_install(),
|
detected_singbox,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3443,7 +3459,7 @@ try {{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn wrap_elevated_package_script(body: &str, result_path: &Path) -> String {
|
pub fn wrap_elevated_package_script(body: &str, result_path: &Path) -> String {
|
||||||
let mut script = String::new();
|
let mut script = String::new();
|
||||||
script.push_str("$ErrorActionPreference = 'Stop'\n");
|
script.push_str("$ErrorActionPreference = 'Stop'\n");
|
||||||
script.push_str(&format!(
|
script.push_str(&format!(
|
||||||
@@ -3530,7 +3546,7 @@ fn powershell_output_message(output: &Output, fallback: &str) -> String {
|
|||||||
fallback.to_string()
|
fallback.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn install_proxifyre_script(generated_config_path: &Path) -> String {
|
pub fn install_proxifyre_script(generated_config_path: &Path) -> String {
|
||||||
let mut script = String::new();
|
let mut script = String::new();
|
||||||
script.push_str(&format!(
|
script.push_str(&format!(
|
||||||
"$targetDir = '{}'\n",
|
"$targetDir = '{}'\n",
|
||||||
|
|||||||
@@ -1,5 +1,59 @@
|
|||||||
|
pub mod activity;
|
||||||
|
pub mod commands;
|
||||||
|
pub mod component_detection;
|
||||||
|
pub mod helper;
|
||||||
|
pub mod models;
|
||||||
|
pub mod process;
|
||||||
|
pub mod singbox_service;
|
||||||
|
pub mod storage;
|
||||||
|
pub mod subscription;
|
||||||
|
pub mod validation;
|
||||||
|
|
||||||
|
pub mod adapters {
|
||||||
|
pub mod proxifyre;
|
||||||
|
pub mod proxy_router;
|
||||||
|
pub mod singbox;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.manage(commands::CommandState::default())
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
commands::get_status,
|
||||||
|
commands::get_admin_status,
|
||||||
|
commands::restart_as_admin,
|
||||||
|
commands::get_startup_snapshot,
|
||||||
|
commands::get_profiles,
|
||||||
|
commands::get_saved_state,
|
||||||
|
commands::save_profile,
|
||||||
|
commands::get_targets,
|
||||||
|
commands::save_target,
|
||||||
|
commands::get_components,
|
||||||
|
commands::get_proxifyre_setup_status,
|
||||||
|
commands::get_singbox_status,
|
||||||
|
commands::get_singbox_setup_status,
|
||||||
|
commands::resolve_profile_preview,
|
||||||
|
commands::save_singbox_subscription,
|
||||||
|
commands::fetch_singbox_subscription,
|
||||||
|
commands::forget_singbox_subscription,
|
||||||
|
commands::select_singbox_server,
|
||||||
|
commands::ping_singbox_server,
|
||||||
|
commands::ping_all_singbox_servers,
|
||||||
|
commands::ping_proxy_target,
|
||||||
|
commands::generate_singbox_config,
|
||||||
|
commands::apply_profiles,
|
||||||
|
commands::get_logs,
|
||||||
|
commands::open_config_location,
|
||||||
|
commands::start_proxifyre_service,
|
||||||
|
commands::stop_proxifyre_service,
|
||||||
|
commands::install_proxifyre,
|
||||||
|
commands::uninstall_proxifyre,
|
||||||
|
commands::start_singbox_service,
|
||||||
|
commands::stop_singbox_service,
|
||||||
|
commands::install_singbox,
|
||||||
|
commands::uninstall_singbox
|
||||||
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("не удалось запустить клиент ProxyWarden");
|
.expect("не удалось запустить клиент ProxyWarden");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +1,5 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
mod activity;
|
|
||||||
mod commands;
|
|
||||||
mod component_detection;
|
|
||||||
mod models;
|
|
||||||
mod process;
|
|
||||||
mod singbox_service;
|
|
||||||
mod storage;
|
|
||||||
mod subscription;
|
|
||||||
mod validation;
|
|
||||||
|
|
||||||
mod adapters {
|
|
||||||
pub mod proxifyre;
|
|
||||||
pub mod proxy_router;
|
|
||||||
pub mod singbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) mod proxifyre {
|
|
||||||
pub use crate::adapters::proxifyre::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) mod proxy_router {
|
|
||||||
pub use crate::adapters::proxy_router::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) mod singbox {
|
|
||||||
pub use crate::adapters::singbox::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri::Builder::default()
|
proxywarden_lib::run();
|
||||||
.plugin(tauri_plugin_dialog::init())
|
|
||||||
.manage(commands::CommandState::default())
|
|
||||||
.invoke_handler(tauri::generate_handler![
|
|
||||||
commands::get_status,
|
|
||||||
commands::get_admin_status,
|
|
||||||
commands::restart_as_admin,
|
|
||||||
commands::get_startup_snapshot,
|
|
||||||
commands::get_profiles,
|
|
||||||
commands::get_saved_state,
|
|
||||||
commands::save_profile,
|
|
||||||
commands::get_targets,
|
|
||||||
commands::save_target,
|
|
||||||
commands::get_components,
|
|
||||||
commands::get_proxifyre_setup_status,
|
|
||||||
commands::get_singbox_status,
|
|
||||||
commands::get_singbox_setup_status,
|
|
||||||
commands::resolve_profile_preview,
|
|
||||||
commands::save_singbox_subscription,
|
|
||||||
commands::fetch_singbox_subscription,
|
|
||||||
commands::forget_singbox_subscription,
|
|
||||||
commands::select_singbox_server,
|
|
||||||
commands::ping_singbox_server,
|
|
||||||
commands::ping_all_singbox_servers,
|
|
||||||
commands::ping_proxy_target,
|
|
||||||
commands::generate_singbox_config,
|
|
||||||
commands::apply_profiles,
|
|
||||||
commands::get_logs,
|
|
||||||
commands::open_config_location,
|
|
||||||
commands::start_proxifyre_service,
|
|
||||||
commands::stop_proxifyre_service,
|
|
||||||
commands::install_proxifyre,
|
|
||||||
commands::uninstall_proxifyre,
|
|
||||||
commands::start_singbox_service,
|
|
||||||
commands::stop_singbox_service,
|
|
||||||
commands::install_singbox,
|
|
||||||
commands::uninstall_singbox
|
|
||||||
])
|
|
||||||
.run(tauri::generate_context!())
|
|
||||||
.expect("не удалось запустить клиент ProxyWarden");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ pub struct SubscriptionFetchIdentity {
|
|||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub device_os: String,
|
pub device_os: String,
|
||||||
|
pub device_os_version: Option<String>,
|
||||||
pub device_model: String,
|
pub device_model: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ impl Default for SubscriptionFetchIdentity {
|
|||||||
app_name: DEFAULT_APP_NAME.to_string(),
|
app_name: DEFAULT_APP_NAME.to_string(),
|
||||||
user_agent: format!("{DEFAULT_APP_NAME}/{device_os}"),
|
user_agent: format!("{DEFAULT_APP_NAME}/{device_os}"),
|
||||||
device_os,
|
device_os,
|
||||||
|
device_os_version: detect_device_os_version(),
|
||||||
device_model: DEFAULT_APP_NAME.to_string(),
|
device_model: DEFAULT_APP_NAME.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,18 @@ pub fn fetch_subscription_with_identity(
|
|||||||
.header("x-device-os", identity.device_os.as_str())
|
.header("x-device-os", identity.device_os.as_str())
|
||||||
.header("x-device-model", identity.device_model.as_str());
|
.header("x-device-model", identity.device_model.as_str());
|
||||||
|
|
||||||
|
if let Some(device_os_version) = identity
|
||||||
|
.device_os_version
|
||||||
|
.as_deref()
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
{
|
||||||
|
let header_value = sanitize_header_value(device_os_version);
|
||||||
|
if !header_value.is_empty() {
|
||||||
|
request = request.header("x-device-os-version", header_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(device_hwid) = identity
|
if let Some(device_hwid) = identity
|
||||||
.device_hwid
|
.device_hwid
|
||||||
.as_deref()
|
.as_deref()
|
||||||
@@ -318,6 +332,86 @@ fn query_value(url: &Url, key: &str) -> Option<String> {
|
|||||||
.map(|(_, value)| value.into_owned())
|
.map(|(_, value)| value.into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sanitize_header_value(value: &str) -> String {
|
||||||
|
value
|
||||||
|
.chars()
|
||||||
|
.filter(|ch| ch.is_ascii_graphic() || *ch == ' ')
|
||||||
|
.collect::<String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_device_os_version() -> Option<String> {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
windows_device_os_version()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn windows_device_os_version() -> Option<String> {
|
||||||
|
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
|
||||||
|
|
||||||
|
let current_version = RegKey::predef(HKEY_LOCAL_MACHINE)
|
||||||
|
.open_subkey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let product_name = current_version
|
||||||
|
.get_value::<String, _>("ProductName")
|
||||||
|
.ok()
|
||||||
|
.map(|value| normalize_windows_product_name(&value, ¤t_version))
|
||||||
|
.filter(|value| !value.trim().is_empty());
|
||||||
|
let display_version = current_version
|
||||||
|
.get_value::<String, _>("DisplayVersion")
|
||||||
|
.ok()
|
||||||
|
.or_else(|| current_version.get_value::<String, _>("ReleaseId").ok())
|
||||||
|
.filter(|value| !value.trim().is_empty());
|
||||||
|
let build = current_version
|
||||||
|
.get_value::<String, _>("CurrentBuildNumber")
|
||||||
|
.ok()
|
||||||
|
.or_else(|| current_version.get_value::<String, _>("CurrentBuild").ok())
|
||||||
|
.filter(|value| !value.trim().is_empty());
|
||||||
|
let ubr = current_version.get_value::<u32, _>("UBR").ok();
|
||||||
|
let build = match (build, ubr) {
|
||||||
|
(Some(build), Some(ubr)) => Some(format!("{build}.{ubr}")),
|
||||||
|
(build, _) => build,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
if let Some(product_name) = product_name {
|
||||||
|
parts.push(product_name);
|
||||||
|
}
|
||||||
|
if let Some(display_version) = display_version {
|
||||||
|
parts.push(display_version);
|
||||||
|
}
|
||||||
|
if let Some(build) = build {
|
||||||
|
parts.push(format!("build {build}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = parts.join(" | ");
|
||||||
|
(!version.is_empty()).then_some(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn normalize_windows_product_name(value: &str, current_version: &winreg::RegKey) -> String {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
let build_number = current_version
|
||||||
|
.get_value::<String, _>("CurrentBuildNumber")
|
||||||
|
.ok()
|
||||||
|
.or_else(|| current_version.get_value::<String, _>("CurrentBuild").ok())
|
||||||
|
.and_then(|value| value.parse::<u32>().ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if build_number >= 22000 && trimmed.starts_with("Windows 10") {
|
||||||
|
return trimmed.replacen("Windows 10", "Windows 11", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
trimmed.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn now_timestamp() -> String {
|
fn now_timestamp() -> String {
|
||||||
let seconds = SystemTime::now()
|
let seconds = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,42 +1,19 @@
|
|||||||
#[path = "../src/activity.rs"]
|
use proxywarden_lib::adapters::proxifyre::ProxiFyreAdapter;
|
||||||
mod activity;
|
use proxywarden_lib::commands::{
|
||||||
#[path = "../src/commands.rs"]
|
self, apply_profiles_with_services, apply_profiles_with_services_and_detection, build_status,
|
||||||
mod commands;
|
read_saved_state_with_proxifyre_config, resolve_component_statuses, resolve_preview,
|
||||||
#[path = "../src/component_detection.rs"]
|
save_profile_to_storage, save_target_to_storage, Clock, CommandError, DetectedProxyApplyHelper,
|
||||||
mod component_detection;
|
HelperApplyRequest, HelperApplyResult, ProfileInputDto, ProfileItemInputDto, ProxyApplyHelper,
|
||||||
#[path = "../src/models.rs"]
|
TargetInputDto,
|
||||||
mod models;
|
|
||||||
#[path = "../src/process.rs"]
|
|
||||||
mod process;
|
|
||||||
#[path = "../src/adapters/proxifyre.rs"]
|
|
||||||
mod proxifyre;
|
|
||||||
#[path = "../src/adapters/proxy_router.rs"]
|
|
||||||
mod proxy_router;
|
|
||||||
#[path = "../src/adapters/singbox.rs"]
|
|
||||||
mod singbox;
|
|
||||||
#[path = "../src/singbox_service.rs"]
|
|
||||||
mod singbox_service;
|
|
||||||
#[path = "../src/storage.rs"]
|
|
||||||
mod storage;
|
|
||||||
#[path = "../src/subscription.rs"]
|
|
||||||
mod subscription;
|
|
||||||
#[path = "../src/validation.rs"]
|
|
||||||
mod validation;
|
|
||||||
|
|
||||||
use commands::{
|
|
||||||
apply_profiles_with_services, build_status, read_saved_state_with_proxifyre_config,
|
|
||||||
resolve_component_statuses, resolve_preview, save_profile_to_storage, save_target_to_storage,
|
|
||||||
Clock, CommandError, DetectedProxyApplyHelper, HelperApplyRequest, HelperApplyResult,
|
|
||||||
ProfileInputDto, ProfileItemInputDto, ProxyApplyHelper, TargetInputDto,
|
|
||||||
};
|
};
|
||||||
use component_detection::{
|
use proxywarden_lib::component_detection::{
|
||||||
DetectedProxyfier, ProxyfierDetectionHost, ProxyfierEngine, RegistryInstallEntry,
|
DetectedProxyfier, ProxyfierDetectionHost, ProxyfierEngine, RegistryInstallEntry,
|
||||||
};
|
};
|
||||||
use models::{
|
use proxywarden_lib::models::{
|
||||||
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol,
|
self, ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType,
|
||||||
ProxyProtocol, Target, TargetKind,
|
Protocol, ProxyProtocol, Target, TargetKind,
|
||||||
};
|
};
|
||||||
use proxifyre::ProxiFyreAdapter;
|
use proxywarden_lib::storage::JsonStorage;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
@@ -44,7 +21,6 @@ use std::path::{Path, PathBuf};
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::process::Command as ProcessCommand;
|
use std::process::Command as ProcessCommand;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use storage::JsonStorage;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn save_commands_normalize_and_persist_profile_and_target() {
|
fn save_commands_normalize_and_persist_profile_and_target() {
|
||||||
@@ -354,11 +330,13 @@ fn apply_blocks_local_singbox_target_when_component_is_missing() {
|
|||||||
.expect("write targets");
|
.expect("write targets");
|
||||||
write_json(&storage.paths().components_file, &[singbox_missing()]);
|
write_json(&storage.paths().components_file, &[singbox_missing()]);
|
||||||
|
|
||||||
let error = apply_profiles_with_services(
|
let error = apply_profiles_with_services_and_detection(
|
||||||
&storage,
|
&storage,
|
||||||
&ProxiFyreAdapter::default(),
|
&ProxiFyreAdapter::default(),
|
||||||
&MockApplyHelper,
|
&MockApplyHelper,
|
||||||
&FixedClock,
|
&FixedClock,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.expect_err("missing sing-box should block local target apply");
|
.expect_err("missing sing-box should block local target apply");
|
||||||
let activity = storage.read_activity().expect("read blocked activity");
|
let activity = storage.read_activity().expect("read blocked activity");
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
#[path = "../src/component_detection.rs"]
|
use proxywarden_lib::component_detection::{
|
||||||
mod component_detection;
|
|
||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
#[path = "../src/process.rs"]
|
|
||||||
mod process;
|
|
||||||
|
|
||||||
use component_detection::{
|
|
||||||
detect_proxyfier_install_with_host, detect_singbox_install_with_host,
|
detect_proxyfier_install_with_host, detect_singbox_install_with_host,
|
||||||
proxyfier_component_from_detection, singbox_component_from_detection, ProxyfierDetectionHost,
|
proxyfier_component_from_detection, singbox_component_from_detection, ProxyfierDetectionHost,
|
||||||
ProxyfierEngine, RegistryInstallEntry,
|
ProxyfierEngine, RegistryInstallEntry,
|
||||||
};
|
};
|
||||||
use models::ComponentState;
|
use proxywarden_lib::models::ComponentState;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#[path = "../src/models.rs"]
|
use proxywarden_lib::models::{
|
||||||
mod models;
|
|
||||||
#[path = "../src/validation.rs"]
|
|
||||||
mod validation;
|
|
||||||
|
|
||||||
use models::{
|
|
||||||
ComponentId, ProfileInput, ProfileItemInput, ProfileItemType, Protocol, ProxyProtocol,
|
ComponentId, ProfileInput, ProfileItemInput, ProfileItemType, Protocol, ProxyProtocol,
|
||||||
TargetInput, TargetKind,
|
TargetInput, TargetKind,
|
||||||
};
|
};
|
||||||
use validation::{normalize_profile, normalize_target};
|
use proxywarden_lib::validation::{normalize_profile, normalize_target};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn normalizes_profile_source_items() {
|
fn normalizes_profile_source_items() {
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
#[path = "../src/helper.rs"]
|
use proxywarden_lib::helper::{
|
||||||
mod helper;
|
|
||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
|
|
||||||
use helper::{
|
|
||||||
helper_action_requires_elevation, install_request, parse_helper_response,
|
helper_action_requires_elevation, install_request, parse_helper_response,
|
||||||
proxifyre_apply_request, service_request, HelperAction, HelperCommandOutput,
|
proxifyre_apply_request, service_request, HelperAction, HelperCommandOutput,
|
||||||
HelperCommandRunner, HelperCommandSpec, HelperError, HelperResponse, StructuredHelper,
|
HelperCommandRunner, HelperCommandSpec, HelperError, HelperResponse, StructuredHelper,
|
||||||
};
|
};
|
||||||
use models::ComponentId;
|
use proxywarden_lib::models::ComponentId;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
#[path = "../src/models.rs"]
|
use proxywarden_lib::adapters::proxifyre::{
|
||||||
mod models;
|
ProxiFyreAdapter, ProxiFyreConfig, PROXIFYRE_OUTPUT_FILE,
|
||||||
#[path = "../src/adapters/proxifyre.rs"]
|
};
|
||||||
mod proxifyre;
|
use proxywarden_lib::adapters::proxy_router::{
|
||||||
#[path = "../src/adapters/proxy_router.rs"]
|
ProxyRouterAdapter, ProxyRouterErrorKind, ProxyRouterRequest,
|
||||||
mod proxy_router;
|
};
|
||||||
|
use proxywarden_lib::models::{
|
||||||
use models::{
|
|
||||||
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol,
|
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol,
|
||||||
ProxyProtocol, Target, TargetKind,
|
ProxyProtocol, Target, TargetKind,
|
||||||
};
|
};
|
||||||
use proxifyre::{ProxiFyreAdapter, ProxiFyreConfig, PROXIFYRE_OUTPUT_FILE};
|
|
||||||
use proxy_router::{ProxyRouterAdapter, ProxyRouterErrorKind, ProxyRouterRequest};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generates_proxifyre_config_for_discord_external_socks5_target() {
|
fn generates_proxifyre_config_for_discord_external_socks5_target() {
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
#[path = "../src/models.rs"]
|
use proxywarden_lib::adapters::proxifyre::{ProxiFyreAdapter, ProxiFyreConfig};
|
||||||
mod models;
|
use proxywarden_lib::adapters::proxy_router::{ProxyRouterAdapter, ProxyRouterRequest};
|
||||||
#[path = "../src/process.rs"]
|
use proxywarden_lib::adapters::singbox::{
|
||||||
mod process;
|
|
||||||
#[path = "../src/adapters/proxifyre.rs"]
|
|
||||||
mod proxifyre;
|
|
||||||
#[path = "../src/adapters/proxy_router.rs"]
|
|
||||||
mod proxy_router;
|
|
||||||
#[path = "../src/adapters/singbox.rs"]
|
|
||||||
mod singbox;
|
|
||||||
|
|
||||||
use models::{
|
|
||||||
ComponentId, ComponentState, ComponentStatus, LocalSingBoxConfig, Profile, ProfileItem,
|
|
||||||
ProfileItemType, Protocol, ProxyProtocol, SubscriptionCache, SubscriptionServer, Target,
|
|
||||||
TargetKind,
|
|
||||||
};
|
|
||||||
use proxifyre::{ProxiFyreAdapter, ProxiFyreConfig};
|
|
||||||
use proxy_router::{ProxyRouterAdapter, ProxyRouterRequest};
|
|
||||||
use singbox::{
|
|
||||||
SingBoxAdapter, SingBoxCheckResult, SingBoxConfigChecker, SingBoxConfigError,
|
SingBoxAdapter, SingBoxCheckResult, SingBoxConfigChecker, SingBoxConfigError,
|
||||||
SingBoxConfigErrorKind, SingBoxGenerationRequest, DEFAULT_VPN_OUTBOUND_TAG,
|
SingBoxConfigErrorKind, SingBoxGenerationRequest, DEFAULT_VPN_OUTBOUND_TAG,
|
||||||
SINGBOX_OUTPUT_FILE,
|
SINGBOX_OUTPUT_FILE,
|
||||||
};
|
};
|
||||||
|
use proxywarden_lib::models::{
|
||||||
|
ComponentId, ComponentState, ComponentStatus, LocalSingBoxConfig, Profile, ProfileItem,
|
||||||
|
ProfileItemType, Protocol, ProxyProtocol, SubscriptionCache, SubscriptionServer, Target,
|
||||||
|
TargetKind,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|||||||
@@ -1,44 +1,22 @@
|
|||||||
#[path = "../src/activity.rs"]
|
use proxywarden_lib::adapters::singbox::{
|
||||||
mod activity;
|
SingBoxAdapter, SingBoxCheckResult, SingBoxConfigChecker, SingBoxConfigError,
|
||||||
#[path = "../src/commands.rs"]
|
};
|
||||||
mod commands;
|
use proxywarden_lib::commands::{
|
||||||
#[path = "../src/component_detection.rs"]
|
|
||||||
mod component_detection;
|
|
||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
#[path = "../src/process.rs"]
|
|
||||||
mod process;
|
|
||||||
#[path = "../src/adapters/proxifyre.rs"]
|
|
||||||
mod proxifyre;
|
|
||||||
#[path = "../src/adapters/proxy_router.rs"]
|
|
||||||
mod proxy_router;
|
|
||||||
#[path = "../src/adapters/singbox.rs"]
|
|
||||||
mod singbox;
|
|
||||||
#[path = "../src/singbox_service.rs"]
|
|
||||||
mod singbox_service;
|
|
||||||
#[path = "../src/storage.rs"]
|
|
||||||
mod storage;
|
|
||||||
#[path = "../src/subscription.rs"]
|
|
||||||
mod subscription;
|
|
||||||
#[path = "../src/validation.rs"]
|
|
||||||
mod validation;
|
|
||||||
|
|
||||||
use commands::{
|
|
||||||
fetch_singbox_subscription_with_fetcher, forget_singbox_subscription_in_storage,
|
fetch_singbox_subscription_with_fetcher, forget_singbox_subscription_in_storage,
|
||||||
generate_singbox_config_with_services, save_singbox_subscription_to_storage,
|
generate_singbox_config_with_services, save_singbox_subscription_to_storage,
|
||||||
select_singbox_server_in_storage, Clock, SaveSingBoxSubscriptionInputDto,
|
select_singbox_server_in_storage, Clock, SaveSingBoxSubscriptionInputDto,
|
||||||
SelectSingBoxServerInputDto, SubscriptionFetcher,
|
SelectSingBoxServerInputDto, SubscriptionFetcher,
|
||||||
};
|
};
|
||||||
use models::{
|
use proxywarden_lib::models::{
|
||||||
ActivityLevel, ComponentId, LocalSingBoxConfig, ProxyProtocol, SubscriptionCache,
|
ActivityLevel, ComponentId, LocalSingBoxConfig, ProxyProtocol, SubscriptionCache,
|
||||||
SubscriptionServer, TargetKind,
|
SubscriptionServer, TargetKind,
|
||||||
};
|
};
|
||||||
|
use proxywarden_lib::storage::JsonStorage;
|
||||||
|
use proxywarden_lib::subscription;
|
||||||
use serde_json::{json, Map};
|
use serde_json::{json, Map};
|
||||||
use singbox::{SingBoxAdapter, SingBoxCheckResult, SingBoxConfigChecker, SingBoxConfigError};
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use storage::JsonStorage;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn saves_subscription_url_without_exposing_secret_query() {
|
fn saves_subscription_url_without_exposing_secret_query() {
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
#[path = "../src/component_detection.rs"]
|
use proxywarden_lib::component_detection::DetectedSingBox;
|
||||||
mod component_detection;
|
use proxywarden_lib::singbox_service::{
|
||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
#[path = "../src/process.rs"]
|
|
||||||
mod process;
|
|
||||||
#[path = "../src/singbox_service.rs"]
|
|
||||||
mod singbox_service;
|
|
||||||
|
|
||||||
use component_detection::DetectedSingBox;
|
|
||||||
use singbox_service::{
|
|
||||||
build_singbox_setup_status, ensure_safe_singbox_install_dir, parse_service_command_output,
|
build_singbox_setup_status, ensure_safe_singbox_install_dir, parse_service_command_output,
|
||||||
service_control_script, SingBoxServiceAction,
|
service_control_script, SingBoxServiceAction,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
#[path = "../src/activity.rs"]
|
use proxywarden_lib::models::{
|
||||||
mod activity;
|
|
||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
#[path = "../src/storage.rs"]
|
|
||||||
mod storage;
|
|
||||||
|
|
||||||
use models::{
|
|
||||||
ActivityEntry, ActivityLevel, ComponentId, ComponentState, ComponentStatus, LocalSingBoxConfig,
|
ActivityEntry, ActivityLevel, ComponentId, ComponentState, ComponentStatus, LocalSingBoxConfig,
|
||||||
Profile, ProfileItem, ProfileItemType, Protocol, ProxyProtocol, SubscriptionCache,
|
Profile, ProfileItem, ProfileItemType, Protocol, ProxyProtocol, SubscriptionCache,
|
||||||
SubscriptionServer, Target, TargetKind,
|
SubscriptionServer, Target, TargetKind,
|
||||||
};
|
};
|
||||||
|
use proxywarden_lib::storage::{backup_path, default_config_root, JsonStorage, StoragePaths};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use storage::{backup_path, default_config_root, JsonStorage, StoragePaths};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage_defaults_to_programdata_root() {
|
fn storage_defaults_to_programdata_root() {
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
#[path = "../src/models.rs"]
|
|
||||||
mod models;
|
|
||||||
#[path = "../src/subscription.rs"]
|
|
||||||
mod subscription;
|
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use models::redact_subscription_url;
|
use proxywarden_lib::models::redact_subscription_url;
|
||||||
|
use proxywarden_lib::subscription::{
|
||||||
|
self, parse_subscription_body, parse_user_info, SubscriptionFetchIdentity,
|
||||||
|
};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use subscription::{parse_subscription_body, parse_user_info, SubscriptionFetchIdentity};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_singbox_json_config_servers() {
|
fn parses_singbox_json_config_servers() {
|
||||||
@@ -130,7 +127,8 @@ fn fetch_subscription_sends_device_hwid_header_when_identity_is_set() {
|
|||||||
String::from_utf8_lossy(&request).to_ascii_lowercase()
|
String::from_utf8_lossy(&request).to_ascii_lowercase()
|
||||||
});
|
});
|
||||||
|
|
||||||
let identity = SubscriptionFetchIdentity::with_device_hwid(Some("hwid-abc123"));
|
let mut identity = SubscriptionFetchIdentity::with_device_hwid(Some("hwid-abc123"));
|
||||||
|
identity.device_os_version = Some("Windows 11 Pro | 25H2 | build 26200.8655".to_string());
|
||||||
let cache = subscription::fetch_subscription_with_identity(&url, &identity)
|
let cache = subscription::fetch_subscription_with_identity(&url, &identity)
|
||||||
.expect("fetch subscription through local test server");
|
.expect("fetch subscription through local test server");
|
||||||
let request = request_thread.join().expect("request thread");
|
let request = request_thread.join().expect("request thread");
|
||||||
@@ -140,6 +138,7 @@ fn fetch_subscription_sends_device_hwid_header_when_identity_is_set() {
|
|||||||
assert!(request.contains("user-agent: proxywarden/"));
|
assert!(request.contains("user-agent: proxywarden/"));
|
||||||
assert!(request.contains("x-app-name: proxywarden"));
|
assert!(request.contains("x-app-name: proxywarden"));
|
||||||
assert!(request.contains("x-device-os:"));
|
assert!(request.contains("x-device-os:"));
|
||||||
|
assert!(request.contains("x-device-os-version: windows 11 pro | 25h2 | build 26200.8655"));
|
||||||
assert!(request.contains("x-device-model: proxywarden"));
|
assert!(request.contains("x-device-model: proxywarden"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user