From eb688f32f6da744abd0e13d4f18e513904008674 Mon Sep 17 00:00:00 2001 From: Dmitriy Petrov Date: Thu, 21 May 2026 20:30:01 +0300 Subject: [PATCH] feat: add windows helper scripts --- scripts/windows/VpnProxy.Windows.psm1 | 154 ++++++++++++++++++++++++++ scripts/windows/helper.ps1 | 26 +++++ scripts/windows/manage.ps1 | 64 +++++++++++ 3 files changed, 244 insertions(+) create mode 100644 scripts/windows/VpnProxy.Windows.psm1 create mode 100644 scripts/windows/helper.ps1 create mode 100644 scripts/windows/manage.ps1 diff --git a/scripts/windows/VpnProxy.Windows.psm1 b/scripts/windows/VpnProxy.Windows.psm1 new file mode 100644 index 0000000..e1a8b26 --- /dev/null +++ b/scripts/windows/VpnProxy.Windows.psm1 @@ -0,0 +1,154 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$script:InstallRoot = $env:VPN_PROXY_WINDOWS_ROOT +if ([string]::IsNullOrWhiteSpace($script:InstallRoot)) { + $script:InstallRoot = "C:\Tools\vpn-proxy-windows" +} + +$script:ProxiFyreRoot = $env:PROXIFYRE_ROOT +if ([string]::IsNullOrWhiteSpace($script:ProxiFyreRoot)) { + $script:ProxiFyreRoot = "C:\Tools\ProxiFyre" +} + +function New-VpnProxyResult { + param( + [string]$Action, + [bool]$Success, + [object]$Result = $null, + [string]$Message = "", + [string]$ErrorMessage = "" + ) + + $value = [ordered]@{ + success = $Success + action = $Action + } + if ($null -ne $Result) { $value.result = $Result } + if ($Message) { $value.message = $Message } + if ($ErrorMessage) { $value.error = $ErrorMessage } + return $value +} + +function Get-VpnProxyStatus { + $task = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue + $singboxProcess = Get-Process -Name "sing-box" -ErrorAction SilentlyContinue + $proxifyre = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue + + return [ordered]@{ + singbox = if ($singboxProcess) { "Running" } elseif ($task) { [string]$task.State } else { "NotInstalled" } + proxifyre = if ($proxifyre) { [string]$proxifyre.Status } else { "NotInstalled" } + installRoot = $script:InstallRoot + proxifyreRoot = $script:ProxiFyreRoot + } +} + +function Write-ProxiFyreConfig { + param( + [Parameter(Mandatory=$true)][string]$ConfigPath, + [Parameter(Mandatory=$true)][object]$Config + ) + + $dir = Split-Path -Parent $ConfigPath + New-Item -ItemType Directory -Force -Path $dir | Out-Null + if (Test-Path $ConfigPath) { + Copy-Item $ConfigPath "$ConfigPath.bak" -Force + } + $Config | ConvertTo-Json -Depth 20 | Set-Content -Path $ConfigPath -Encoding UTF8 +} + +function Restart-ProxiFyre { + $exe = Join-Path $script:ProxiFyreRoot "ProxiFyre.exe" + if (-not (Test-Path $exe)) { + throw "ProxiFyre.exe not found at $exe" + } + + & $exe stop 2>$null | Out-Null + & $exe install 2>$null | Out-Null + & $exe start 2>$null | Out-Null +} + +function Invoke-ProxiFyreApply { + param([object]$Payload) + + Write-ProxiFyreConfig -ConfigPath $Payload.configPath -Config $Payload.config + Restart-ProxiFyre + return New-VpnProxyResult -Action "proxifyre.apply" -Success $true -Message "ProxiFyre config applied and service restarted" +} + +function Invoke-ServiceControl { + param([object]$Payload) + + $service = [string]$Payload.service + $action = [string]$Payload.action + + if ($service -eq "proxifyre") { + if ($action -eq "restart") { Restart-ProxiFyre } + elseif ($action -eq "start") { Start-Service -Name "ProxiFyreService" } + elseif ($action -eq "stop") { Stop-Service -Name "ProxiFyreService" -Force } + else { throw "Unknown ProxiFyre action: $action" } + } elseif ($service -eq "sing-box") { + if ($action -eq "restart") { + Stop-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue + Start-ScheduledTask -TaskName "SingBoxProxy" + } elseif ($action -eq "start") { + Start-ScheduledTask -TaskName "SingBoxProxy" + } elseif ($action -eq "stop") { + Stop-ScheduledTask -TaskName "SingBoxProxy" + } else { + throw "Unknown sing-box action: $action" + } + } elseif ($service -eq "ui") { + return New-VpnProxyResult -Action "service.control" -Success $true -Message "UI is controlled by manage.ps1 -OpenUi" + } else { + throw "Unknown service: $service" + } + + return New-VpnProxyResult -Action "service.control" -Success $true -Message "$service $action complete" +} + +function Get-VpnProxyLogs { + $paths = @( + (Join-Path $script:InstallRoot "runtime\sing-box\singbox.log"), + (Join-Path $script:ProxiFyreRoot "ProxiFyre.log") + ) + $logs = @() + + foreach ($path in $paths) { + if (Test-Path $path) { + $logs += [ordered]@{ + path = $path + lines = @(Get-Content $path -Tail 120 -ErrorAction SilentlyContinue) + } + } + } + + return $logs +} + +function Invoke-VpnProxyAction { + param( + [Parameter(Mandatory=$true)][string]$Action, + [object]$Payload = @{} + ) + + switch ($Action) { + "status.get" { + return New-VpnProxyResult -Action $Action -Success $true -Result (Get-VpnProxyStatus) + } + "proxifyre.apply" { + return Invoke-ProxiFyreApply -Payload $Payload + } + "service.control" { + return Invoke-ServiceControl -Payload $Payload + } + "logs.get" { + return New-VpnProxyResult -Action $Action -Success $true -Result (Get-VpnProxyLogs) + } + default { + throw "Unknown action: $Action" + } + } +} + +Export-ModuleMember -Function Invoke-VpnProxyAction, Get-VpnProxyStatus diff --git a/scripts/windows/helper.ps1 b/scripts/windows/helper.ps1 new file mode 100644 index 0000000..e4ee46d --- /dev/null +++ b/scripts/windows/helper.ps1 @@ -0,0 +1,26 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +Import-Module (Join-Path $ScriptDir "VpnProxy.Windows.psm1") -Force + +try { + $raw = [Console]::In.ReadToEnd() + if ([string]::IsNullOrWhiteSpace($raw)) { + throw "Missing JSON input" + } + + $request = $raw | ConvertFrom-Json + $payload = if ($request.PSObject.Properties.Name -contains "payload") { $request.payload } else { @{} } + $result = Invoke-VpnProxyAction -Action ([string]$request.action) -Payload $payload + $result | ConvertTo-Json -Depth 30 -Compress + exit 0 +} catch { + $errorResult = [ordered]@{ + success = $false + action = "error" + error = $_.Exception.Message + } + $errorResult | ConvertTo-Json -Depth 10 -Compress + exit 1 +} diff --git a/scripts/windows/manage.ps1 b/scripts/windows/manage.ps1 new file mode 100644 index 0000000..d6c3723 --- /dev/null +++ b/scripts/windows/manage.ps1 @@ -0,0 +1,64 @@ +param( + [switch]$OpenUi, + [switch]$Status, + [switch]$RestartServices +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$AppDir = Split-Path -Parent (Split-Path -Parent $ScriptDir) +if (-not (Test-Path (Join-Path $AppDir "package.json"))) { + throw "Cannot locate app root from $ScriptDir" +} + +$Root = $env:VPN_PROXY_WINDOWS_ROOT +if ([string]::IsNullOrWhiteSpace($Root)) { + if ((Split-Path -Leaf $AppDir) -eq "app") { + $Root = Split-Path -Parent $AppDir + } else { + $Root = $AppDir + } +} + +$env:VPN_PROXY_WINDOWS_ROOT = $Root +$env:APP_MODE = "windows" +$env:DATA_DIR = Join-Path $Root "data" +$env:DIST_DIR = Join-Path $AppDir "dist" +$env:PROXY_PORT = "1080" +$env:PROXY_BIND_IP = "127.0.0.1" +$env:SING_BOX_CONFIG = Join-Path $Root "runtime\sing-box\config.json" +$env:SING_BOX_CACHE = Join-Path $Root "runtime\sing-box\cache.db" +$env:WINDOWS_HELPER = Join-Path $AppDir "scripts\windows\helper.ps1" + +function Get-NodeCommand { + $portable = Join-Path $Root "runtime\node\node.exe" + if (Test-Path $portable) { return $portable } + return "node" +} + +if ($Status) { + $inputJson = @{ action = "status.get"; payload = @{} } | ConvertTo-Json -Compress + $inputJson | & $env:WINDOWS_HELPER + exit $LASTEXITCODE +} + +if ($RestartServices) { + $helper = $env:WINDOWS_HELPER + (@{ action = "service.control"; payload = @{ service = "proxifyre"; action = "restart" } } | ConvertTo-Json -Compress) | & $helper + (@{ action = "service.control"; payload = @{ service = "sing-box"; action = "restart" } } | ConvertTo-Json -Compress) | & $helper + exit 0 +} + +if ($OpenUi) { + $node = Get-NodeCommand + Start-Process "http://127.0.0.1:3456" + & $node (Join-Path $AppDir "src\server\index.js") + exit $LASTEXITCODE +} + +Write-Host "VPN Proxy Windows" +Write-Host " -OpenUi Start local UI" +Write-Host " -Status Print JSON status" +Write-Host " -RestartServices Restart ProxiFyre and sing-box"