421 lines
16 KiB
PowerShell
421 lines
16 KiB
PowerShell
# ==========================================
|
||
# 🎮 DISCORD PROXY SETUP
|
||
# ==========================================
|
||
|
||
param(
|
||
[switch]$Force,
|
||
[switch]$Debug
|
||
)
|
||
|
||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
. "$ScriptDir\lib\Common.ps1"
|
||
. "$ScriptDir\lib\Net.ps1"
|
||
. "$ScriptDir\lib\System.ps1"
|
||
|
||
if ($Debug) { Set-DebugMode -Enabled $true }
|
||
|
||
Write-Header "НАСТРОЙКА DISCORD / VESKTOP" -ClearScreen
|
||
|
||
Ensure-Admin
|
||
|
||
$InstallPath = "C:\Tools\ProxiFyre"
|
||
$ConfigPath = "$InstallPath\app-config.json"
|
||
$DriverUrl = "https://github.com/wiresock/ndisapi/releases/download/v3.6.2/Windows.Packet.Filter.3.6.2.1.x64.msi"
|
||
$AppUrl = "https://github.com/wiresock/proxifyre/releases/download/v2.1.4/ProxiFyre-v2.1.4-x64-signed.zip"
|
||
|
||
# --- ФУНКЦИИ ---
|
||
|
||
function Test-ProxyConnection {
|
||
param([string]$ProxyAddr)
|
||
|
||
Write-Info "Проверка подключения к прокси $ProxyAddr..."
|
||
|
||
try {
|
||
$parts = $ProxyAddr -split ":"
|
||
$host_ = $parts[0]
|
||
$port = [int]$parts[1]
|
||
|
||
# 1. Проверяем TCP соединение
|
||
$tcp = New-Object System.Net.Sockets.TcpClient
|
||
$tcp.Connect($host_, $port)
|
||
$tcp.Close()
|
||
Write-Success "TCP соединение установлено"
|
||
|
||
# 2. Пробуем получить внешний IP через прокси (используем curl для SOCKS5)
|
||
try {
|
||
$result = & curl.exe -s -x "socks5://$ProxyAddr" "http://v4.ident.me" --connect-timeout 5 2>$null
|
||
if ($result -match "^\d+\.\d+\.\d+\.\d+$") {
|
||
Write-Success "Внешний IP через прокси: $result"
|
||
return $true
|
||
}
|
||
}
|
||
catch {}
|
||
|
||
Write-Warning "TCP работает, но не удалось получить IP. Возможно прокси не полностью настроен."
|
||
return $true
|
||
}
|
||
catch {
|
||
Write-Error "Не удалось подключиться к $ProxyAddr"
|
||
Write-Host " Убедитесь, что прокси запущен и доступен." -ForegroundColor Gray
|
||
return $false
|
||
}
|
||
}
|
||
|
||
function Get-CurrentConfig {
|
||
if (Test-Path $ConfigPath) {
|
||
try {
|
||
$cfg = Get-Content $ConfigPath -Raw | ConvertFrom-Json
|
||
return @{
|
||
Apps = $cfg.proxies[0].appNames -join ", "
|
||
Proxy = $cfg.proxies[0].socks5ProxyEndpoint
|
||
}
|
||
}
|
||
catch {}
|
||
}
|
||
return $null
|
||
}
|
||
|
||
function Install-ProxiFyre {
|
||
# 0. Остановка старых процессов (чтобы файлы не были заблокированы)
|
||
Write-Step "Остановка старых процессов..."
|
||
Stop-Service "ProxiFyreService" -Force -ErrorAction SilentlyContinue
|
||
Stop-Process -Name "ProxiFyre" -Force -ErrorAction SilentlyContinue
|
||
Start-Sleep -Seconds 2
|
||
|
||
# Установка драйвера
|
||
Write-Step "Установка драйвера..."
|
||
$msi = "$env:TEMP\WinpkFilter.msi"
|
||
if (Download-File -Url $DriverUrl -Destination $msi) {
|
||
Start-Process msiexec.exe -ArgumentList "/i `"$msi`" /qn /norestart" -Wait
|
||
Write-Success "Драйвер готов"
|
||
}
|
||
|
||
# Установка ProxiFyre
|
||
Write-Step "Установка ProxiFyre..."
|
||
New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
|
||
$zip = "$env:TEMP\ProxiFyre.zip"
|
||
if (Download-File -Url $AppUrl -Destination $zip) {
|
||
Expand-Archive -Path $zip -DestinationPath $InstallPath -Force
|
||
$exe = Get-ChildItem $InstallPath -Recurse -Filter "ProxiFyre.exe" | Select-Object -First 1
|
||
if ($exe.DirectoryName -ne $InstallPath) {
|
||
Copy-Item "$($exe.DirectoryName)\*" $InstallPath -Recurse -Force
|
||
}
|
||
Write-Success "Распаковано"
|
||
}
|
||
|
||
# Создание правил Firewall
|
||
Write-Step "Настройка Windows Firewall..."
|
||
$exePath = "$InstallPath\ProxiFyre.exe"
|
||
$ruleName = "ProxiFyre"
|
||
|
||
# Удаляем старые правила
|
||
Remove-NetFirewallRule -DisplayName "$ruleName*" -ErrorAction SilentlyContinue
|
||
|
||
# Входящее правило
|
||
New-NetFirewallRule -DisplayName "$ruleName (Inbound)" `
|
||
-Direction Inbound `
|
||
-Action Allow `
|
||
-Program $exePath `
|
||
-Profile Domain, Private, Public `
|
||
-Description "Разрешить входящие соединения для ProxiFyre" | Out-Null
|
||
|
||
# Исходящее правило
|
||
New-NetFirewallRule -DisplayName "$ruleName (Outbound)" `
|
||
-Direction Outbound `
|
||
-Action Allow `
|
||
-Program $exePath `
|
||
-Profile Domain, Private, Public `
|
||
-Description "Разрешить исходящие соединения для ProxiFyre" | Out-Null
|
||
|
||
Write-Success "Правила Firewall созданы"
|
||
}
|
||
|
||
function Configure-And-Start {
|
||
param($TargetApps, $ProxyAddr)
|
||
|
||
# Конфиг (гарантируем, что appNames - массив)
|
||
$appNamesArray = @($TargetApps)
|
||
$cfg = @{
|
||
logLevel = "Info"
|
||
proxies = @(@{
|
||
appNames = $appNamesArray
|
||
socks5ProxyEndpoint = $ProxyAddr
|
||
supportedProtocols = @("TCP", "UDP")
|
||
})
|
||
excludes = @()
|
||
}
|
||
$cfg | ConvertTo-Json -Depth 5 | Set-Content $ConfigPath -Encoding UTF8
|
||
|
||
# Служба
|
||
Write-Step "Перезапуск службы..."
|
||
if (Get-DebugMode) {
|
||
& "$InstallPath\ProxiFyre.exe" stop
|
||
& "$InstallPath\ProxiFyre.exe" install
|
||
& "$InstallPath\ProxiFyre.exe" start
|
||
}
|
||
else {
|
||
& "$InstallPath\ProxiFyre.exe" stop 2>&1 | Out-Null
|
||
& "$InstallPath\ProxiFyre.exe" install 2>&1 | Out-Null
|
||
& "$InstallPath\ProxiFyre.exe" start 2>&1 | Out-Null
|
||
}
|
||
|
||
# Мониторинг запуска (10 сек)
|
||
Write-Info "Проверка стабильности запуска (10 сек)..."
|
||
$lastLogSize = 0
|
||
$logFile = $null
|
||
|
||
for ($i = 1; $i -le 10; $i++) {
|
||
Start-Sleep -Seconds 1
|
||
|
||
# 1. Ищем файл логов (если еще не нашли)
|
||
if (-not $logFile) {
|
||
$logFile = Get-ChildItem "$InstallPath\*.log" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime | Select-Object -Last 1
|
||
}
|
||
|
||
# 2. Выводим новые строки лога
|
||
if ($logFile) {
|
||
try {
|
||
$stream = [System.IO.File]::Open($logFile.FullName, 'Open', 'Read', 'ReadWrite')
|
||
if ($stream.Length -gt $lastLogSize) {
|
||
$stream.Seek($lastLogSize, 'Begin') | Out-Null
|
||
$reader = New-Object System.IO.StreamReader($stream)
|
||
$content = $reader.ReadToEnd()
|
||
$newPos = $stream.Position # Сохраняем позицию
|
||
$reader.Dispose() # Закрывает поток
|
||
$lastLogSize = $newPos
|
||
|
||
if (-not [string]::IsNullOrWhiteSpace($content)) {
|
||
$content -split "`r`n" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object {
|
||
Write-Host " LOG: $_" -ForegroundColor DarkGray
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
$stream.Dispose()
|
||
}
|
||
}
|
||
catch {}
|
||
}
|
||
|
||
# 3. Проверяем статус службы
|
||
$svc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue
|
||
if ($svc.Status -ne 'Running') {
|
||
Write-Error "Служба упала при запуске! (Код 1064 или другая ошибка)"
|
||
Write-Host " Попробуйте запустить вручную для диагностики." -ForegroundColor Gray
|
||
return
|
||
}
|
||
}
|
||
|
||
Write-Success "Готово! Служба стабильна."
|
||
}
|
||
|
||
function Get-AppPath {
|
||
Write-Host "`n📁 Укажите путь до папки с приложением" -ForegroundColor Yellow
|
||
Write-Host " (Будут проксированы все .exe из этой папки)" -ForegroundColor Gray
|
||
|
||
# Стандартные пути установки Discord-клиентов
|
||
$defaultPaths = @{
|
||
"Discord" = "$env:LOCALAPPDATA\Discord"
|
||
"Discord PTB" = "$env:LOCALAPPDATA\DiscordPTB"
|
||
"Discord Canary" = "$env:LOCALAPPDATA\DiscordCanary"
|
||
"Vesktop" = "$env:LOCALAPPDATA\vesktop"
|
||
"Lightcord" = "$env:LOCALAPPDATA\Lightcord"
|
||
}
|
||
|
||
$suggestions = @()
|
||
foreach ($app in $defaultPaths.Keys) {
|
||
if (Test-Path $defaultPaths[$app]) {
|
||
$suggestions += @{ Name = $app; Path = $defaultPaths[$app] }
|
||
}
|
||
}
|
||
|
||
if ($suggestions.Count -gt 0) {
|
||
Write-Host "`n Найденные приложения:" -ForegroundColor Cyan
|
||
for ($i = 0; $i -lt $suggestions.Count; $i++) {
|
||
Write-Host " [$($i+1)] $($suggestions[$i].Name): $($suggestions[$i].Path)" -ForegroundColor Gray
|
||
}
|
||
Write-Host " [c] Указать свой путь" -ForegroundColor Gray
|
||
|
||
$choice = Read-Host "`n Выберите"
|
||
if ($choice -match "^\d+$" -and [int]$choice -ge 1 -and [int]$choice -le $suggestions.Count) {
|
||
return @($suggestions[[int]$choice - 1].Path)
|
||
}
|
||
}
|
||
|
||
# Ручной ввод пути
|
||
while ($true) {
|
||
$path = Read-Host " Путь до папки"
|
||
|
||
if ([string]::IsNullOrWhiteSpace($path)) {
|
||
Write-Warning "Путь не указан"
|
||
continue
|
||
}
|
||
|
||
if (Test-Path $path) {
|
||
$exeCount = (Get-ChildItem $path -Filter "*.exe" -Recurse -ErrorAction SilentlyContinue).Count
|
||
if ($exeCount -gt 0) {
|
||
Write-Success "Найдено $exeCount исполняемых файлов"
|
||
return @($path)
|
||
}
|
||
else {
|
||
Write-Warning "В папке не найдено .exe файлов"
|
||
}
|
||
}
|
||
else {
|
||
Write-Error "Папка не существует: $path"
|
||
}
|
||
|
||
$retry = Read-Host " Попробовать другой путь? (y/n)"
|
||
if ($retry -ne 'y') { return $null }
|
||
}
|
||
}
|
||
|
||
function Select-Apps {
|
||
Write-Host "`n🎮 Какие приложения проксировать?" -ForegroundColor Yellow
|
||
$appOpts = [Ordered]@{
|
||
"1" = "Discord (по имени процесса)"
|
||
"2" = "Vesktop (по имени процесса)"
|
||
"3" = "Discord + Vesktop (по имени процесса)"
|
||
"4" = "Указать путь до папки приложения"
|
||
}
|
||
$appChoice = Show-Menu -Options $appOpts
|
||
|
||
# Discord запускается через Update.exe, нужно перехватывать оба процесса
|
||
$result = switch ($appChoice) {
|
||
"1" { @("Discord", "Update") }
|
||
"2" { @("Vesktop") }
|
||
"3" { @("Vesktop", "Discord", "Update") }
|
||
"4" { Get-AppPath }
|
||
default { @("Discord", "Update") }
|
||
}
|
||
return $result
|
||
}
|
||
|
||
function Get-ProxyAddress {
|
||
# Проверяем локальный sing-box
|
||
$singboxStatus = Get-TaskStatus -Name "SingBoxProxy"
|
||
$localProxy = "127.0.0.1:1080"
|
||
|
||
if ($singboxStatus -eq "Running") {
|
||
Write-Info "Обнаружен работающий VPN клиент (Sing-box)."
|
||
Write-Host " Рекомендуется использовать локальный прокси: " -NoNewline -ForegroundColor Gray
|
||
Write-Host $localProxy -ForegroundColor Green
|
||
|
||
$useLocal = Read-Host " Использовать локальный? (y/n) [y]"
|
||
if ($useLocal -ne 'n') {
|
||
return $localProxy
|
||
}
|
||
}
|
||
else {
|
||
Write-Warning "VPN клиент не запущен!"
|
||
Write-Host " Вы можете указать адрес удалённого прокси." -ForegroundColor Gray
|
||
}
|
||
|
||
# Запрашиваем адрес
|
||
while ($true) {
|
||
$proxyAddr = Read-Host "`n Введите адрес прокси (IP:порт)"
|
||
|
||
if ([string]::IsNullOrWhiteSpace($proxyAddr)) {
|
||
Write-Warning "Адрес не указан"
|
||
continue
|
||
}
|
||
|
||
if ($proxyAddr -notmatch "^[\d\.]+:\d+$") {
|
||
Write-Error "Неверный формат. Ожидается: IP:порт (например 192.168.1.100:1080)"
|
||
continue
|
||
}
|
||
|
||
# Проверяем подключение
|
||
if (Test-ProxyConnection -ProxyAddr $proxyAddr) {
|
||
return $proxyAddr
|
||
}
|
||
|
||
$retry = Read-Host " Попробовать другой адрес? (y/n)"
|
||
if ($retry -ne 'y') { return $null }
|
||
}
|
||
}
|
||
|
||
# --- MAIN ---
|
||
|
||
$isInstalled = Test-Path "$InstallPath\ProxiFyre.exe"
|
||
$discSvc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue
|
||
$currentConfig = Get-CurrentConfig
|
||
|
||
if ($isInstalled -and $currentConfig -and -not $Force) {
|
||
# Уже установлено — показываем меню управления
|
||
Write-Info "ProxiFyre уже установлен."
|
||
Write-Host ""
|
||
Write-Host " Статус: " -NoNewline -ForegroundColor Gray
|
||
if ($discSvc.Status -eq 'Running') {
|
||
Write-Host "АКТИВЕН" -ForegroundColor Green
|
||
}
|
||
else {
|
||
Write-Host "ОСТАНОВЛЕН" -ForegroundColor Yellow
|
||
}
|
||
Write-Host " Приложения: $($currentConfig.Apps)" -ForegroundColor Gray
|
||
Write-Host " Прокси: $($currentConfig.Proxy)" -ForegroundColor Gray
|
||
Write-Host ""
|
||
|
||
$opts = [Ordered]@{
|
||
"1" = "Изменить настройки (приложения/прокси)"
|
||
"2" = "Проверить подключение к прокси"
|
||
"3" = "Перезапустить службу"
|
||
"4" = "Остановить службу"
|
||
"5" = "Переустановить"
|
||
"b" = "Назад"
|
||
}
|
||
|
||
$action = Show-Menu -Options $opts
|
||
|
||
switch ($action) {
|
||
"1" {
|
||
$targetApps = Select-Apps
|
||
$proxyAddr = Get-ProxyAddress
|
||
if ($proxyAddr) {
|
||
Configure-And-Start -TargetApps $targetApps -ProxyAddr $proxyAddr
|
||
}
|
||
}
|
||
"2" {
|
||
Test-ProxyConnection -ProxyAddr $currentConfig.Proxy | Out-Null
|
||
}
|
||
"3" {
|
||
Write-Step "Перезапуск службы..."
|
||
Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow
|
||
Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow
|
||
Write-Success "Перезапущено!"
|
||
}
|
||
"4" {
|
||
Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow
|
||
Write-Success "Остановлено!"
|
||
}
|
||
"5" {
|
||
$Force = $true
|
||
}
|
||
"b" { exit }
|
||
}
|
||
|
||
if (-not $Force) {
|
||
Start-Sleep -Seconds 2
|
||
exit
|
||
}
|
||
}
|
||
|
||
# --- НОВАЯ УСТАНОВКА ---
|
||
|
||
if (-not $isInstalled -or $Force) {
|
||
Ensure-VCRedist
|
||
Install-ProxiFyre
|
||
}
|
||
|
||
$targetApps = Select-Apps
|
||
$proxyAddr = Get-ProxyAddress
|
||
|
||
if (-not $proxyAddr) {
|
||
Write-Error "Прокси не настроен. Выход."
|
||
Start-Sleep -Seconds 2
|
||
exit
|
||
}
|
||
|
||
Configure-And-Start -TargetApps $targetApps -ProxyAddr $proxyAddr
|
||
Start-Sleep -Seconds 3
|