Add ProxiFyre firewall rule management and bump version to 1.1.0
This commit is contained in:
@@ -18,13 +18,15 @@ pub use crate::configuration_use_case::{
|
||||
};
|
||||
pub use crate::proxifyre_runtime::wrap_elevated_package_script;
|
||||
use crate::proxifyre_runtime::{
|
||||
build_proxifyre_setup_status_for_install_dir, control_proxifyre_service,
|
||||
install_proxifyre_component, proxifyre_install_dir_for_app, read_proxifyre_setup_progress,
|
||||
singbox_install_dir_for_app, uninstall_proxifyre_component, ServiceControlAction,
|
||||
build_proxifyre_setup_status_for_install_dir, configure_proxifyre_firewall,
|
||||
control_proxifyre_service, install_proxifyre_component, proxifyre_install_dir_for_app,
|
||||
read_proxifyre_setup_progress, singbox_install_dir_for_app, uninstall_proxifyre_component,
|
||||
ServiceControlAction,
|
||||
};
|
||||
pub use crate::proxifyre_scripts::{
|
||||
install_proxifyre_script, install_proxifyre_script_for_target,
|
||||
install_proxifyre_script_with_bundle, uninstall_proxifyre_script,
|
||||
configure_proxifyre_firewall_script, install_proxifyre_script,
|
||||
install_proxifyre_script_for_target, install_proxifyre_script_with_bundle,
|
||||
uninstall_proxifyre_script,
|
||||
};
|
||||
pub use crate::proxy_apply::{
|
||||
apply_profiles_with_services, apply_profiles_with_services_and_detection,
|
||||
@@ -288,6 +290,13 @@ pub async fn install_proxifyre(
|
||||
.map_err(background_task_error)?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn configure_proxifyre_firewall_rules(app: tauri::AppHandle) -> Result<(), CommandError> {
|
||||
tauri::async_runtime::spawn_blocking(move || configure_proxifyre_firewall(&app))
|
||||
.await
|
||||
.map_err(background_task_error)?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn uninstall_proxifyre(
|
||||
app: tauri::AppHandle,
|
||||
|
||||
@@ -12,6 +12,8 @@ use std::{
|
||||
pub const PROXYWARDEN_COMPONENTS_DIR_NAME: &str = "components";
|
||||
pub const PROXIFYRE_COMPONENT_DIR_NAME: &str = "ProxiFyre";
|
||||
pub const SINGBOX_COMPONENT_DIR_NAME: &str = "sing-box";
|
||||
#[cfg(debug_assertions)]
|
||||
const PROXYWARDEN_DEV_INSTALL_ROOT_ENV: &str = "PROXYWARDEN_DEV_INSTALL_ROOT";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ProxyfierEngine {
|
||||
@@ -132,11 +134,42 @@ pub fn detect_proxyfier_install() -> Option<DetectedProxyfier> {
|
||||
}
|
||||
|
||||
pub fn app_install_dir_from_current_exe() -> Option<PathBuf> {
|
||||
#[cfg(debug_assertions)]
|
||||
if let Some(path) = env::var_os(PROXYWARDEN_DEV_INSTALL_ROOT_ENV)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(PathBuf::from)
|
||||
{
|
||||
return Some(path);
|
||||
}
|
||||
|
||||
env::current_exe()
|
||||
.ok()
|
||||
.and_then(|path| path.parent().map(Path::to_path_buf))
|
||||
}
|
||||
|
||||
#[cfg(all(test, debug_assertions))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug_component_roots_follow_configured_install() {
|
||||
let install_root = PathBuf::from(
|
||||
env::var(PROXYWARDEN_DEV_INSTALL_ROOT_ENV)
|
||||
.expect("Cargo dev config should define the installed ProxyWarden root"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
default_proxifyre_install_dir(),
|
||||
proxifyre_install_dir_from_app_dir(&install_root)
|
||||
);
|
||||
assert_eq!(
|
||||
default_singbox_install_dir(),
|
||||
singbox_install_dir_from_app_dir(&install_root)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn component_root_from_app_dir(app_dir: &Path) -> PathBuf {
|
||||
app_dir.join(PROXYWARDEN_COMPONENTS_DIR_NAME)
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ pub fn run() {
|
||||
commands::start_proxifyre_service,
|
||||
commands::stop_proxifyre_service,
|
||||
commands::install_proxifyre,
|
||||
commands::configure_proxifyre_firewall_rules,
|
||||
commands::uninstall_proxifyre,
|
||||
commands::start_singbox_service,
|
||||
commands::stop_singbox_service,
|
||||
|
||||
@@ -68,7 +68,8 @@ pub fn verify_managed_proxifyre_install(
|
||||
marker_path.display()
|
||||
)
|
||||
})?;
|
||||
let marker: ProxiFyreInstallMarker = serde_json::from_str(&marker_text).map_err(|error| {
|
||||
let marker_text = marker_text.strip_prefix('\u{feff}').unwrap_or(&marker_text);
|
||||
let marker: ProxiFyreInstallMarker = serde_json::from_str(marker_text).map_err(|error| {
|
||||
format!(
|
||||
"marker установки {} содержит некорректный JSON: {error}",
|
||||
marker_path.display()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use crate::clock::{Clock, SystemClock};
|
||||
use crate::command_dto::*;
|
||||
use crate::component_detection::{
|
||||
detect_proxyfier_install, proxifyre_install_dir_from_app_dir,
|
||||
app_install_dir_from_current_exe, detect_proxyfier_install, proxifyre_install_dir_from_app_dir,
|
||||
proxyfier_component_from_detection, singbox_install_dir_from_app_dir, DetectedProxyfier,
|
||||
};
|
||||
use crate::elevated_scripts;
|
||||
@@ -17,12 +17,15 @@ use crate::powershell::{
|
||||
};
|
||||
use crate::process::command_no_window;
|
||||
use crate::proxifyre_ownership::verify_managed_proxifyre_install;
|
||||
use crate::proxifyre_scripts::{install_proxifyre_script_for_target, uninstall_proxifyre_script};
|
||||
use crate::proxifyre_scripts::{
|
||||
configure_proxifyre_firewall_script, install_proxifyre_script_for_target,
|
||||
uninstall_proxifyre_script,
|
||||
};
|
||||
use crate::safe_fs;
|
||||
use crate::storage::{default_config_root, JsonStorage};
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs};
|
||||
use tauri::Manager;
|
||||
|
||||
pub(crate) fn control_proxifyre_service(
|
||||
@@ -389,6 +392,7 @@ exit 4
|
||||
enum ProxiFyrePackageAction {
|
||||
Install,
|
||||
Uninstall,
|
||||
ConfigureFirewall,
|
||||
}
|
||||
|
||||
impl ProxiFyrePackageAction {
|
||||
@@ -396,6 +400,7 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "proxifyre_install_failed",
|
||||
ProxiFyrePackageAction::Uninstall => "proxifyre_uninstall_failed",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => "proxifyre_firewall_failed",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +408,7 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "установить",
|
||||
ProxiFyrePackageAction::Uninstall => "удалить",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => "настроить Windows Firewall для",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +416,7 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "install",
|
||||
ProxiFyrePackageAction::Uninstall => "uninstall",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => "firewall",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +424,7 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "install",
|
||||
ProxiFyrePackageAction::Uninstall => "uninstall",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => "firewall",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +432,9 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "Готовлю установку ProxiFyre.",
|
||||
ProxiFyrePackageAction::Uninstall => "Готовлю удаление ProxiFyre и сетевого драйвера.",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => {
|
||||
"Готовлю правила Windows Firewall для ProxiFyre."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,6 +442,9 @@ impl ProxiFyrePackageAction {
|
||||
match self {
|
||||
ProxiFyrePackageAction::Install => "ProxiFyre и сетевой драйвер готовы.",
|
||||
ProxiFyrePackageAction::Uninstall => "ProxiFyre и сетевой драйвер удалены.",
|
||||
ProxiFyrePackageAction::ConfigureFirewall => {
|
||||
"Правила Windows Firewall для ProxiFyre добавлены."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,6 +491,36 @@ pub(crate) fn install_proxifyre_component(
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn configure_proxifyre_firewall(app: &tauri::AppHandle) -> Result<(), CommandError> {
|
||||
let Some(detected) = detect_proxyfier_install() else {
|
||||
return Err(CommandError::new(
|
||||
ProxiFyrePackageAction::ConfigureFirewall.error_code(),
|
||||
"ProxiFyre не найден на компьютере.",
|
||||
));
|
||||
};
|
||||
|
||||
let expected_install_dir = proxifyre_install_dir_for_app(app)?;
|
||||
verify_managed_proxifyre_install(
|
||||
&detected.install_dir,
|
||||
&detected.executable_path,
|
||||
&expected_install_dir,
|
||||
)
|
||||
.map_err(|reason| {
|
||||
CommandError::new(
|
||||
ProxiFyrePackageAction::ConfigureFirewall.error_code(),
|
||||
format!("Настройка Windows Firewall заблокирована: {reason}"),
|
||||
)
|
||||
})?;
|
||||
|
||||
let script = configure_proxifyre_firewall_script(&detected.executable_path);
|
||||
let artifact_dir = default_config_root().join("state");
|
||||
run_elevated_package_script(
|
||||
ProxiFyrePackageAction::ConfigureFirewall,
|
||||
script,
|
||||
&artifact_dir,
|
||||
)
|
||||
}
|
||||
|
||||
fn bundled_proxifyre_asset_dir(app: &tauri::AppHandle) -> Option<PathBuf> {
|
||||
let mut candidates = Vec::new();
|
||||
if let Ok(resource_dir) = app.path().resource_dir() {
|
||||
@@ -492,10 +536,8 @@ fn bundled_proxifyre_asset_dir(app: &tauri::AppHandle) -> Option<PathBuf> {
|
||||
}
|
||||
|
||||
fn app_install_dir(app: &tauri::AppHandle) -> Result<PathBuf, CommandError> {
|
||||
if let Ok(exe_path) = env::current_exe() {
|
||||
if let Some(parent) = exe_path.parent() {
|
||||
return Ok(parent.to_path_buf());
|
||||
}
|
||||
if let Some(app_dir) = app_install_dir_from_current_exe() {
|
||||
return Ok(app_dir);
|
||||
}
|
||||
|
||||
app.path().resource_dir().map_err(|error| {
|
||||
|
||||
@@ -14,6 +14,8 @@ const NDISAPI_PINNED_RELEASE_TAG: &str = "v3.6.2";
|
||||
const NDISAPI_PINNED_INSTALLER_VERSION: &str = "3.6.2.1";
|
||||
const VC_REDIST_X64_URL: &str = "https://aka.ms/vc14/vc_redist.x64.exe";
|
||||
const VC_REDIST_X86_URL: &str = "https://aka.ms/vc14/vc_redist.x86.exe";
|
||||
pub const PROXIFYRE_FIREWALL_INBOUND_RULE: &str = "ProxyWarden.ProxiFyre.Inbound";
|
||||
pub const PROXIFYRE_FIREWALL_OUTBOUND_RULE: &str = "ProxyWarden.ProxiFyre.Outbound";
|
||||
|
||||
pub fn install_proxifyre_script(generated_config_path: &Path) -> String {
|
||||
install_proxifyre_script_with_bundle(generated_config_path, None)
|
||||
@@ -453,14 +455,15 @@ pub fn install_proxifyre_script_for_target(
|
||||
}
|
||||
|
||||
$markerPath = Join-Path $targetDir 'proxywarden-component.json'
|
||||
[ordered]@{
|
||||
$markerJson = [ordered]@{
|
||||
manager = 'ProxyWarden'
|
||||
component = 'proxifyre'
|
||||
serviceName = 'ProxiFyreService'
|
||||
installedAt = (Get-Date).ToString('o')
|
||||
installRoot = $targetDir
|
||||
packetFilterInstalledByProxyWarden = (-not $packetFilterAlreadyInstalled)
|
||||
} | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $markerPath -Encoding UTF8
|
||||
} | ConvertTo-Json -Depth 4
|
||||
[IO.File]::WriteAllText($markerPath, $markerJson, [Text.UTF8Encoding]::new($false))
|
||||
|
||||
Write-ProxyWardenProgress 'install' 'proxifyre' 'running' 90 'Устанавливаю и запускаю службу ProxiFyre.'
|
||||
Push-Location $targetDir
|
||||
@@ -483,6 +486,38 @@ pub fn install_proxifyre_script_for_target(
|
||||
script
|
||||
}
|
||||
|
||||
pub fn configure_proxifyre_firewall_script(executable_path: &Path) -> String {
|
||||
let executable_path = escape_powershell_single(&executable_path.display().to_string());
|
||||
format!(
|
||||
r#"
|
||||
$exePath = '{executable_path}'
|
||||
if (-not (Test-Path -LiteralPath $exePath -PathType Leaf)) {{
|
||||
throw "ProxiFyre.exe не найден по подтвержденному пути: $exePath"
|
||||
}}
|
||||
|
||||
$ruleSpecs = @(
|
||||
@{{ Name = '{PROXIFYRE_FIREWALL_INBOUND_RULE}'; DisplayName = 'ProxyWarden: ProxiFyre (входящие)'; Direction = 'Inbound' }},
|
||||
@{{ Name = '{PROXIFYRE_FIREWALL_OUTBOUND_RULE}'; DisplayName = 'ProxyWarden: ProxiFyre (исходящие)'; Direction = 'Outbound' }}
|
||||
)
|
||||
|
||||
foreach ($rule in $ruleSpecs) {{
|
||||
Get-NetFirewallRule -Name $rule.Name -ErrorAction SilentlyContinue |
|
||||
Remove-NetFirewallRule -ErrorAction Stop
|
||||
New-NetFirewallRule `
|
||||
-Name $rule.Name `
|
||||
-DisplayName $rule.DisplayName `
|
||||
-Group 'ProxyWarden' `
|
||||
-Program $exePath `
|
||||
-Direction $rule.Direction `
|
||||
-Action Allow `
|
||||
-Profile Any `
|
||||
-Enabled True `
|
||||
-ErrorAction Stop | Out-Null
|
||||
}}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn uninstall_proxifyre_script(
|
||||
detected: Option<&DetectedProxyfier>,
|
||||
ownership: &ManagedProxiFyreOwnership,
|
||||
@@ -619,6 +654,11 @@ pub fn uninstall_proxifyre_script(
|
||||
sc.exe delete $service.Name | Out-Null
|
||||
}
|
||||
|
||||
foreach ($firewallRuleName in @('ProxyWarden.ProxiFyre.Inbound', 'ProxyWarden.ProxiFyre.Outbound')) {
|
||||
Get-NetFirewallRule -Name $firewallRuleName -ErrorAction SilentlyContinue |
|
||||
Remove-NetFirewallRule -ErrorAction Stop
|
||||
}
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($installDir) -and (Test-Path -LiteralPath $installDir)) {
|
||||
Remove-Item -LiteralPath $installDir -Recurse -Force
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user