diff --git a/.gitignore b/.gitignore index 1269488..91b6e6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ data +_legacy diff --git a/discord-windows-hack.ps1 b/discord-windows-hack.ps1 deleted file mode 100644 index bbc361e..0000000 --- a/discord-windows-hack.ps1 +++ /dev/null @@ -1,419 +0,0 @@ -# ========================================== -# �️ PROXIFYRE INSTALLER ДЛЯ DISCORD/VESKTOP -# ========================================== -param( - [switch]$Force, # Принудительная переустановка - [string]$Proxy = "", # Адрес прокси (для неинтерактивного режима), например "127.0.0.1:8080" - [string[]]$Apps = @(), # Приложения (для неинтерактивного режима), например @("Discord", "Vesktop") - [switch]$Silent # Тихий режим (без лишнего вывода, для вызова из других скриптов) -) - -# ========================================== -# 🛠️ ПРЯМЫЕ ССЫЛКИ (Hardcoded) -# ========================================== -$InstallPath = "C:\Tools\ProxiFyre" -$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" -# ========================================== - -# 0. Проверка прав -if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { - Write-Host "⛔ Запусти от имени АДМИНИСТРАТОРА!" -ForegroundColor Red - Start-Sleep -s 3; Exit -} - -Clear-Host -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host " 🚀 PROXIFYRE SERVICE INSTALLER " -ForegroundColor Cyan -Write-Host "==========================================" -ForegroundColor Cyan - -# ========================================== -# ПРОВЕРКА СУЩЕСТВУЮЩЕЙ УСТАНОВКИ -# ========================================== -$proxifyreExists = Test-Path "$InstallPath\ProxiFyre.exe" -$proxifyreService = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - -if ($proxifyreExists -and -not $Force) { - Write-Host "" - Write-Host "==========================================" -ForegroundColor Green - Write-Host " ✅ PROXIFYRE УЖЕ УСТАНОВЛЕН! " -ForegroundColor Green - Write-Host "==========================================" -ForegroundColor Green - Write-Host "" - - # Статус службы - Write-Host "📊 Статус службы: " -NoNewline -ForegroundColor Yellow - if ($proxifyreService -and $proxifyreService.Status -eq 'Running') { - Write-Host "РАБОТАЕТ" -ForegroundColor Green - } - elseif ($proxifyreService) { - Write-Host "$($proxifyreService.Status)" -ForegroundColor Red - } - else { - Write-Host "НЕ ЗАРЕГИСТРИРОВАНА" -ForegroundColor Red - } - - Write-Host "" - Write-Host "📁 Расположение:" -ForegroundColor Yellow - Write-Host " Путь: $InstallPath" -ForegroundColor White - Write-Host " Конфиг: $InstallPath\app-config.json" -ForegroundColor White - Write-Host " Логи: $InstallPath\logs\" -ForegroundColor White - Write-Host "" - - # Показываем текущий конфиг - $configPath = "$InstallPath\app-config.json" - if (Test-Path $configPath) { - try { - $config = Get-Content $configPath -Raw | ConvertFrom-Json - $apps = $config.proxies[0].appNames -join ", " - $proxy = $config.proxies[0].socks5ProxyEndpoint - Write-Host "⚙️ Текущие настройки:" -ForegroundColor Yellow - Write-Host " Прокси: $proxy" -ForegroundColor White - Write-Host " Приложения: $apps" -ForegroundColor White - Write-Host "" - } - catch { - Write-Host " ⚠️ Не удалось прочитать конфиг" -ForegroundColor Yellow - } - } - - Write-Host "==========================================" -ForegroundColor Cyan - Write-Host "" - Write-Host "Что вы хотите сделать?" -ForegroundColor Yellow - Write-Host " [1] Запустить службу" -ForegroundColor White - Write-Host " [2] Остановить службу" -ForegroundColor White - Write-Host " [3] Перезапустить службу" -ForegroundColor White - Write-Host " [4] Изменить настройки (прокси/приложения)" -ForegroundColor White - Write-Host " [5] Показать логи" -ForegroundColor White - Write-Host " [6] Показать конфиг" -ForegroundColor White - Write-Host " [7] Переустановить (полная переустановка)" -ForegroundColor White - Write-Host " [q] Выход" -ForegroundColor White - Write-Host "" - $choice = Read-Host "👉 Выбор (1-7/q)" - - switch ($choice) { - "1" { - Write-Host "`n🚀 Запуск службы..." -ForegroundColor Cyan - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow - Start-Sleep -s 2 - $svc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - Write-Host " Статус: $($svc.Status)" -ForegroundColor Green - exit 0 - } - "2" { - Write-Host "`n⏹️ Остановка службы..." -ForegroundColor Cyan - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow - Write-Host " ✅ Служба остановлена" -ForegroundColor Green - exit 0 - } - "3" { - Write-Host "`n🔄 Перезапуск службы..." -ForegroundColor Cyan - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow - Start-Sleep -s 1 - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow - Start-Sleep -s 2 - $svc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - Write-Host " Статус: $($svc.Status)" -ForegroundColor Green - exit 0 - } - "4" { - Write-Host "`n⚙️ Изменение настроек..." -ForegroundColor Cyan - - # Выбор режима - Write-Host "" - Write-Host "📡 Где работает VPN-прокси?" -ForegroundColor Yellow - Write-Host " [1] Удалённый сервер (Docker на VPS/другом ПК)" -ForegroundColor White - Write-Host " [2] Локальный Docker Desktop (на этом ПК)" -ForegroundColor White - $modeChoice = Read-Host "👉 Выбор (1-2)" - - if ($modeChoice -eq "2") { - # Локальный Docker — нужен sing-box - $singboxTask = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue - if ($singboxTask -and $singboxTask.State -eq "Running") { - Write-Host "`n✅ Нативный sing-box работает!" -ForegroundColor Green - $NewProxy = "127.0.0.1:1080" - } - else { - Write-Host "`n⚠️ Нативный sing-box не запущен!" -ForegroundColor Yellow - Write-Host " Запустите: .\setup-singbox-native.ps1" -ForegroundColor Cyan - $runSetup = Read-Host " Запустить сейчас? (y/n)" - if ($runSetup -eq "y") { - $setupScript = Join-Path $PSScriptRoot "setup-singbox-native.ps1" - if (Test-Path $setupScript) { & $setupScript } - } - $NewProxy = "127.0.0.1:1080" - } - } - else { - # Удалённый прокси - Write-Host "`n🌐 SOCKS5 Прокси (IP:PORT):" -ForegroundColor Yellow - $NewProxy = Read-Host " [Enter] для 127.0.0.1:8080" - if ([string]::IsNullOrWhiteSpace($NewProxy)) { $NewProxy = "127.0.0.1:8080" } - } - - # Запрос приложений - Write-Host "`n🎮 Что проксируем?" -ForegroundColor Yellow - Write-Host " [1] Vesktop" - Write-Host " [2] Discord" - Write-Host " [3] Vesktop + Discord" - $AppChoice = Read-Host "👉 Выбор (1-3)" - - switch ($AppChoice) { - "2" { $NewApps = @("Discord") } - "3" { $NewApps = @("Vesktop", "Discord") } - Default { $NewApps = @("Vesktop") } - } - - # Генерируем новый конфиг - Write-Host "`n📝 Обновляем конфиг..." -ForegroundColor Cyan - $ConfigData = @{ - logLevel = "Info" - proxies = @( - @{ - appNames = $NewApps - socks5ProxyEndpoint = $NewProxy - username = "" - password = "" - supportedProtocols = @("TCP", "UDP") - } - ) - excludes = @() - } | ConvertTo-Json -Depth 4 - Set-Content -Path $configPath -Value $ConfigData -Encoding UTF8 - - Write-Host " ✅ Конфиг обновлён:" -ForegroundColor Green - Write-Host " Прокси: $NewProxy" -ForegroundColor White - Write-Host " Приложения: $($NewApps -join ', ')" -ForegroundColor White - - # Перезапуск службы - Write-Host "`n🔄 Перезапуск службы для применения..." -ForegroundColor Cyan - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow - Start-Sleep -s 1 - Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow - Start-Sleep -s 2 - $svc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - Write-Host " Статус: $($svc.Status)" -ForegroundColor Green - exit 0 - } - "5" { - Write-Host "`n📋 Логи ProxiFyre:" -ForegroundColor Cyan - $logFiles = Get-ChildItem "$InstallPath\logs\*.log" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 - if ($logFiles) { - Get-Content $logFiles.FullName -Tail 50 - } - else { - Write-Host " Лог-файлы не найдены" -ForegroundColor Yellow - } - exit 0 - } - "6" { - Write-Host "`n📄 Конфиг ProxiFyre:" -ForegroundColor Cyan - if (Test-Path $configPath) { - Get-Content $configPath - } - else { - Write-Host " Конфиг не найден" -ForegroundColor Yellow - } - exit 0 - } - "7" { - Write-Host "`n🔧 Переустановка..." -ForegroundColor Cyan - $Force = $true - # Продолжаем выполнение скрипта для полной переустановки - } - default { - Write-Host "`n ℹ️ Выход" -ForegroundColor Gray - exit 0 - } - } -} - - -# --- ШАГ 1: КОНФИГУРАЦИЯ --- -# Если параметры переданы — используем их (неинтерактивный режим) -if ($Proxy -and $Apps.Count -gt 0) { - $UserProxy = $Proxy - $TargetApps = $Apps - if (-not $Silent) { - Write-Host "`n⚙️ Неинтерактивный режим:" -ForegroundColor Cyan - Write-Host " Прокси: $UserProxy" -ForegroundColor White - Write-Host " Приложения: $($TargetApps -join ', ')" -ForegroundColor White - } -} -else { - # Интерактивный режим — сначала выбор режима - Write-Host "" - Write-Host "==========================================" -ForegroundColor Cyan - Write-Host " 📡 ГДЕ РАБОТАЕТ ВАШ VPN-ПРОКСИ? " -ForegroundColor Cyan - Write-Host "==========================================" -ForegroundColor Cyan - Write-Host "" - Write-Host " [1] 🌐 УДАЛЁННЫЙ СЕРВЕР" -ForegroundColor White - Write-Host " Docker на VPS или другом ПК в сети" -ForegroundColor Gray - Write-Host " (UDP работает, просто укажите адрес)" -ForegroundColor Gray - Write-Host "" - Write-Host " [2] 💻 ЛОКАЛЬНЫЙ DOCKER НА WINDOWS" -ForegroundColor White - Write-Host " Docker Desktop на этом компьютере" -ForegroundColor Gray - Write-Host " (UDP НЕ работает, нужен нативный sing-box)" -ForegroundColor Gray - Write-Host "" - - $modeChoice = Read-Host "👉 Выбор (1-2)" - - if ($modeChoice -eq "2") { - # Локальный Docker — нужен нативный sing-box - Write-Host "" - Write-Host "==========================================" -ForegroundColor Yellow - Write-Host " ⚠️ ЛОКАЛЬНЫЙ DOCKER DESKTOP " -ForegroundColor Yellow - Write-Host "==========================================" -ForegroundColor Yellow - Write-Host "" - Write-Host "Docker Desktop на Windows НЕ поддерживает UDP!" -ForegroundColor Red - Write-Host "Для голосовых звонков Discord нужен нативный sing-box." -ForegroundColor Red - Write-Host "" - - # Проверяем, установлен ли уже нативный sing-box - $singboxInstalled = Test-Path "C:\Tools\sing-box\sing-box.exe" - $singboxTask = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue - - if ($singboxInstalled -and $singboxTask -and $singboxTask.State -eq "Running") { - Write-Host "✅ Нативный sing-box уже установлен и работает!" -ForegroundColor Green - Write-Host " Прокси: 127.0.0.1:1080" -ForegroundColor White - $UserProxy = "127.0.0.1:1080" - } - else { - Write-Host "Для установки нативного sing-box запустите:" -ForegroundColor Yellow - Write-Host " .\setup-singbox-native.ps1" -ForegroundColor Cyan - Write-Host "" - - $runSetup = Read-Host "Запустить setup-singbox-native.ps1 сейчас? (y/n)" - if ($runSetup -eq "y") { - $setupScript = Join-Path $PSScriptRoot "setup-singbox-native.ps1" - if (Test-Path $setupScript) { - & $setupScript - # После установки используем порт 1080 - $UserProxy = "127.0.0.1:1080" - } - else { - Write-Host "❌ Скрипт setup-singbox-native.ps1 не найден!" -ForegroundColor Red - exit 1 - } - } - else { - Write-Host "" - Write-Host "Установите sing-box вручную и повторите." -ForegroundColor Yellow - exit 0 - } - } - } - else { - # Удалённый прокси — просто спрашиваем адрес - Write-Host "`n🌐 SOCKS5 Прокси (IP:PORT):" -ForegroundColor Yellow - Write-Host " Примеры: 192.168.1.100:8080, myserver.com:8080" -ForegroundColor Gray - $UserProxy = Read-Host " [Enter] для 127.0.0.1:8080" - if ([string]::IsNullOrWhiteSpace($UserProxy)) { $UserProxy = "127.0.0.1:8080" } - } - - Write-Host "`n🎮 Что проксируем?" -ForegroundColor Yellow - Write-Host " [1] Vesktop" - Write-Host " [2] Discord" - Write-Host " [3] Vesktop + Discord" - $AppChoice = Read-Host "👉 Выбор (1-3)" - - switch ($AppChoice) { - "2" { $TargetApps = @("Discord") } - "3" { $TargetApps = @("Vesktop", "Discord") } - Default { $TargetApps = @("Vesktop") } - } -} - -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - -# --- ШАГ 2: ПОДГОТОВКА (ОЧИСТКА) --- -Write-Host "`n🧹 [0/3] Очистка процессов..." -ForegroundColor Magenta -# Убиваем любые старые процессы, чтобы они не держали драйвер -Stop-Process -Name "ProxiFyre" -Force -ErrorAction SilentlyContinue -Start-Sleep -s 1 - -# --- ШАГ 3: ДРАЙВЕР --- -Write-Host "⚙️ [1/3] Ставим драйвер (Packet Filter)..." -ForegroundColor Magenta -$MsiFile = "$env:TEMP\WinpkFilter.msi" - -try { - Invoke-WebRequest -Uri $DriverUrl -OutFile $MsiFile -ErrorAction Stop - $Proc = Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$MsiFile`" /qn /norestart" -Wait -PassThru - if ($Proc.ExitCode -eq 0) { Write-Host " ✅ Успешно." -ForegroundColor Green } - elseif ($Proc.ExitCode -eq 1603) { Write-Host " ⚠️ Уже установлен." -ForegroundColor Yellow } -} -catch { - Write-Error "❌ Ошибка скачивания драйвера: $_"; Exit -} - -# --- ШАГ 4: PROXIFYRE --- -Write-Host "`n⬇️ [2/3] Ставим ProxiFyre..." -ForegroundColor Magenta - -# Если папка есть, чистим всё, кроме конфига (если вдруг хотим сохранить), но проще пересоздать -if (Test-Path $InstallPath) { Remove-Item $InstallPath -Recurse -Force -ErrorAction SilentlyContinue } -New-Item -ItemType Directory -Force -Path $InstallPath | Out-Null - -try { - $ZipFile = "$env:TEMP\ProxiFyre.zip" - Invoke-WebRequest -Uri $AppUrl -OutFile $ZipFile -ErrorAction Stop - Expand-Archive -Path $ZipFile -DestinationPath $InstallPath -Force - Write-Host " ✅ Распаковано." -ForegroundColor Green -} -catch { - Write-Error "❌ Ошибка скачивания ProxiFyre: $_"; Exit -} - -# Вытаскиваем из подпапки если надо -$ExeItem = Get-ChildItem -Path $InstallPath -Filter "ProxiFyre.exe" -Recurse | Select-Object -First 1 -if ($ExeItem.DirectoryName -ne $InstallPath) { - Copy-Item -Path "$($ExeItem.DirectoryName)\*" -Destination $InstallPath -Recurse -Force -} - -# --- ШАГ 5: КОНФИГ --- -Write-Host "`n📝 [3/3] Генерируем конфиг..." -ForegroundColor Cyan -$ConfigPath = Join-Path -Path $InstallPath -ChildPath "app-config.json" -$ConfigData = @{ - logLevel = "Info" - proxies = @( - @{ - appNames = $TargetApps - socks5ProxyEndpoint = $UserProxy - username = "" - password = "" - supportedProtocols = @("TCP", "UDP") - } - ) - excludes = @() -} | ConvertTo-Json -Depth 4 -Set-Content -Path $ConfigPath -Value $ConfigData -Encoding UTF8 - -# --- ШАГ 6: УСТАНОВКА СЛУЖБЫ --- -Write-Host "`n🛡️ [4/3] Регистрация службы Windows..." -ForegroundColor Cyan -$ExePath = Join-Path -Path $InstallPath -ChildPath "ProxiFyre.exe" - -# 1. Удаляем старую службу если была -Start-Process -FilePath $ExePath -ArgumentList "uninstall" -Wait -NoNewWindow -Start-Sleep -s 1 - -# 2. Инсталлируем службу -Start-Process -FilePath $ExePath -ArgumentList "install" -Wait -NoNewWindow -Start-Sleep -s 1 - -# 3. Запускаем службу -Write-Host " 🚀 Запускаем службу..." -ForegroundColor Yellow -Start-Process -FilePath $ExePath -ArgumentList "start" -Wait -NoNewWindow -Start-Sleep -s 3 - -# 4. Проверка -# Важно: имя службы в системе именно "ProxiFyreService" (судя по твоим логам) -$Service = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - -if ($Service -and $Service.Status -eq 'Running') { - Write-Host "`n==========================================" -ForegroundColor Green - Write-Host "🎉 УСПЕХ! Служба работает в фоне." -ForegroundColor Green - Write-Host "📁 Логи тут: $InstallPath\logs" - Write-Host "==========================================" -} -else { - Write-Host "`n⚠️ Служба установлена, но статус: $($Service.Status). Проверь логи." -ForegroundColor Red - Write-Host "Попробуй вручную: net start ProxiFyreService" -} \ No newline at end of file diff --git a/install-docker-proxy.ps1 b/install-docker-proxy.ps1 deleted file mode 100644 index 36dba8f..0000000 --- a/install-docker-proxy.ps1 +++ /dev/null @@ -1,460 +0,0 @@ -# ========================================== -# 🐳 VPN-PROXY DOCKER INSTALLER ДЛЯ WINDOWS -# ========================================== -# Устанавливает VPN-прокси через Docker Compose -# и опционально настраивает Discord/Vesktop -# ========================================== - -param( - [switch]$SkipDockerCheck, - [switch]$SkipDiscord, - [switch]$Force # Принудительная переустановка -) - -# Цвета для красивого вывода -function Write-Step { param($msg) Write-Host "`n📦 $msg" -ForegroundColor Cyan } -function Write-Success { param($msg) Write-Host " ✅ $msg" -ForegroundColor Green } -function Write-Warning { param($msg) Write-Host " ⚠️ $msg" -ForegroundColor Yellow } -function Write-Error { param($msg) Write-Host " ❌ $msg" -ForegroundColor Red } -function Write-Info { param($msg) Write-Host " ℹ️ $msg" -ForegroundColor Gray } - -Clear-Host -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host " 🐳 VPN-PROXY DOCKER INSTALLER " -ForegroundColor Cyan -Write-Host "==========================================" -ForegroundColor Cyan - -# Определяем директорию скрипта -$ScriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path } -if (-not $ScriptDir) { $ScriptDir = Get-Location } - -Write-Info "Директория проекта: $ScriptDir" - -# ========================================== -# ШАГ 0: ПРОВЕРКА СУЩЕСТВУЮЩЕЙ УСТАНОВКИ -# ========================================== -Write-Step "Проверка существующей установки..." - -$existingContainer = docker ps -a --filter "name=sing-proxy" --format "{{.Names}}" 2>$null -$containerRunning = docker ps --filter "name=sing-proxy" --format "{{.Status}}" 2>$null - -if ($existingContainer -and -not $Force) { - Write-Host "" - Write-Host "==========================================" -ForegroundColor Green - Write-Host " ✅ VPN-PROXY УЖЕ УСТАНОВЛЕН! " -ForegroundColor Green - Write-Host "==========================================" -ForegroundColor Green - Write-Host "" - - # Статус контейнера - if ($containerRunning -match "Up") { - Write-Host "📊 Статус: " -NoNewline -ForegroundColor Yellow - Write-Host "РАБОТАЕТ" -ForegroundColor Green - Write-Host " Контейнер: sing-proxy" -ForegroundColor Gray - Write-Host " Uptime: $containerRunning" -ForegroundColor Gray - } - else { - Write-Host "📊 Статус: " -NoNewline -ForegroundColor Yellow - Write-Host "ОСТАНОВЛЕН" -ForegroundColor Red - $containerStatus = docker ps -a --filter "name=sing-proxy" --format "{{.Status}}" 2>$null - Write-Host " Контейнер: sing-proxy ($containerStatus)" -ForegroundColor Gray - } - - Write-Host "" - Write-Host "📡 Адреса подключения:" -ForegroundColor Yellow - Write-Host " Веб-интерфейс: http://localhost:3456" -ForegroundColor White - Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8080" -ForegroundColor White - Write-Host "" - Write-Host "📁 Расположение:" -ForegroundColor Yellow - Write-Host " Проект: $ScriptDir" -ForegroundColor White - Write-Host " Данные: $ScriptDir\data" -ForegroundColor White - Write-Host "" - - # Проверяем ProxiFyre - $proxifyreInstalled = Test-Path "C:\Tools\ProxiFyre\ProxiFyre.exe" - if ($proxifyreInstalled) { - $proxifyreService = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue - Write-Host "🛡️ ProxiFyre:" -ForegroundColor Yellow - Write-Host " Путь: C:\Tools\ProxiFyre" -ForegroundColor White - Write-Host " Статус: $($proxifyreService.Status)" -ForegroundColor White - - # Показываем настроенные приложения из конфига - $configPath = "C:\Tools\ProxiFyre\app-config.json" - if (Test-Path $configPath) { - try { - $config = Get-Content $configPath -Raw | ConvertFrom-Json - $apps = $config.proxies[0].appNames -join ", " - $proxy = $config.proxies[0].socks5ProxyEndpoint - Write-Host " Прокси: $proxy" -ForegroundColor White - Write-Host " Приложения: $apps" -ForegroundColor White - } - catch {} - } - Write-Host "" - } - - Write-Host "==========================================" -ForegroundColor Cyan - Write-Host "" - Write-Host "Что вы хотите сделать?" -ForegroundColor Yellow - Write-Host " [1] Запустить контейнер (если остановлен)" -ForegroundColor White - Write-Host " [2] Перезапустить контейнер" -ForegroundColor White - Write-Host " [3] Переустановить (пересобрать)" -ForegroundColor White - Write-Host " [4] Показать логи" -ForegroundColor White - Write-Host " [5] Открыть веб-интерфейс" -ForegroundColor White - Write-Host " [q] Выход" -ForegroundColor White - Write-Host "" - $choice = Read-Host "👉 Выбор (1-5/q)" - - switch ($choice) { - "1" { - Write-Step "Запуск контейнера..." - Push-Location $ScriptDir - docker compose start - Pop-Location - Write-Success "Контейнер запущен!" - Write-Host " Веб-интерфейс: http://localhost:3456" -ForegroundColor Green - exit 0 - } - "2" { - Write-Step "Перезапуск контейнера..." - Push-Location $ScriptDir - docker compose restart - Pop-Location - Write-Success "Контейнер перезапущен!" - exit 0 - } - "3" { - Write-Info "Переустановка..." - # Продолжаем выполнение скрипта - } - "4" { - Write-Step "Логи контейнера (последние 50 строк):" - docker logs --tail 50 sing-proxy - exit 0 - } - "5" { - Start-Process "http://localhost:3456" - exit 0 - } - default { - Write-Info "Выход" - exit 0 - } - } -} - -# ========================================== -# ШАГ 1: ПРОВЕРКА DOCKER -# ========================================== -Write-Step "Проверка Docker..." - -$DockerInstalled = $false -$DockerRunning = $false -$DockerComposeAvailable = $false - -# Проверяем, установлен ли Docker -try { - $dockerVersion = docker --version 2>&1 - if ($LASTEXITCODE -eq 0 -and $dockerVersion -match "Docker version") { - Write-Success "Docker установлен: $dockerVersion" - $DockerInstalled = $true - } -} -catch { - $DockerInstalled = $false -} - -if (-not $DockerInstalled -and -not $SkipDockerCheck) { - Write-Error "Docker не найден!" - Write-Host "" - Write-Host "📥 Установите Docker Desktop:" -ForegroundColor Yellow - Write-Host " https://www.docker.com/products/docker-desktop/" -ForegroundColor White - Write-Host "" - Write-Host "После установки:" -ForegroundColor Yellow - Write-Host " 1. Запустите Docker Desktop" -ForegroundColor White - Write-Host " 2. Дождитесь, пока появится зелёная иконка 🐳 в трее" -ForegroundColor White - Write-Host " 3. Запустите этот скрипт заново" -ForegroundColor White - Write-Host "" - - $openUrl = Read-Host "Открыть страницу загрузки Docker? (y/n)" - if ($openUrl -eq "y" -or $openUrl -eq "Y") { - Start-Process "https://www.docker.com/products/docker-desktop/" - } - exit 1 -} - -# Проверяем, запущен ли Docker -if ($DockerInstalled) { - try { - $dockerInfo = docker info 2>&1 - if ($LASTEXITCODE -eq 0) { - Write-Success "Docker daemon запущен" - $DockerRunning = $true - } - } - catch { - $DockerRunning = $false - } - - if (-not $DockerRunning -and -not $SkipDockerCheck) { - Write-Warning "Docker установлен, но не запущен!" - Write-Host "" - Write-Host "🚀 Запустите Docker Desktop и дождитесь, пока:" -ForegroundColor Yellow - Write-Host " - Появится зелёная иконка 🐳 в трее" -ForegroundColor White - Write-Host " - Или надпись 'Docker Desktop is running'" -ForegroundColor White - Write-Host "" - - $waitForDocker = Read-Host "Ожидать запуска Docker? (y/n)" - if ($waitForDocker -eq "y" -or $waitForDocker -eq "Y") { - Write-Info "Ожидание запуска Docker..." - $attempts = 0 - $maxAttempts = 60 # 5 минут макс - - while (-not $DockerRunning -and $attempts -lt $maxAttempts) { - Start-Sleep -Seconds 5 - $attempts++ - Write-Host "." -NoNewline - - try { - $dockerInfo = docker info 2>&1 - if ($LASTEXITCODE -eq 0) { - $DockerRunning = $true - } - } - catch {} - } - Write-Host "" - - if ($DockerRunning) { - Write-Success "Docker запустился!" - } - else { - Write-Error "Таймаут ожидания Docker. Запустите Docker Desktop вручную." - exit 1 - } - } - else { - exit 1 - } - } -} - -# Проверяем Docker Compose -if ($DockerRunning) { - try { - $composeVersion = docker compose version 2>&1 - if ($LASTEXITCODE -eq 0) { - Write-Success "Docker Compose доступен: $composeVersion" - $DockerComposeAvailable = $true - } - } - catch {} - - if (-not $DockerComposeAvailable) { - # Пробуем старый формат docker-compose - try { - $composeVersion = docker-compose --version 2>&1 - if ($LASTEXITCODE -eq 0) { - Write-Success "Docker Compose (legacy) доступен: $composeVersion" - $DockerComposeAvailable = $true - } - } - catch {} - } - - if (-not $DockerComposeAvailable -and -not $SkipDockerCheck) { - Write-Error "Docker Compose не найден!" - Write-Host "" - Write-Host "Docker Compose обычно входит в Docker Desktop." -ForegroundColor Yellow - Write-Host "Попробуйте переустановить Docker Desktop." -ForegroundColor Yellow - exit 1 - } -} - -# ========================================== -# ШАГ 2: ПРОВЕРКА ФАЙЛОВ ПРОЕКТА -# ========================================== -Write-Step "Проверка файлов проекта..." - -$dockerComposeFile = Join-Path $ScriptDir "docker-compose.yml" -$dockerDir = Join-Path $ScriptDir "docker" -$dockerFile = Join-Path $dockerDir "Dockerfile.singbox" - -if (-not (Test-Path $dockerComposeFile)) { - Write-Error "Не найден docker-compose.yml в $ScriptDir" - exit 1 -} -Write-Success "docker-compose.yml найден" - -if (-not (Test-Path $dockerFile)) { - Write-Error "Не найден docker/Dockerfile.singbox" - exit 1 -} -Write-Success "Dockerfile.singbox найден" - -# ========================================== -# ШАГ 3: СБОРКА И ЗАПУСК -# ========================================== -Write-Step "Сборка Docker-контейнера..." - -# Переходим в директорию проекта -Push-Location $ScriptDir - -try { - # Останавливаем старый контейнер если есть - Write-Info "Останавливаем старый контейнер (если есть)..." - docker compose down 2>&1 | Out-Null - - # Собираем образ - Write-Info "Сборка образа (может занять 1-2 минуты)..." - $buildOutput = docker compose build 2>&1 - if ($LASTEXITCODE -ne 0) { - Write-Error "Ошибка сборки Docker образа!" - Write-Host $buildOutput -ForegroundColor Red - Pop-Location - exit 1 - } - Write-Success "Образ собран" - - # Запускаем контейнер - Write-Info "Запуск контейнера..." - $upOutput = docker compose up -d 2>&1 - if ($LASTEXITCODE -ne 0) { - Write-Error "Ошибка запуска контейнера!" - Write-Host $upOutput -ForegroundColor Red - Pop-Location - exit 1 - } - Write-Success "Контейнер запущен" - -} -finally { - Pop-Location -} - -# Ждём немного, чтобы контейнер инициализировался -Start-Sleep -Seconds 3 - -# Проверяем статус -Write-Step "Проверка статуса..." -$containerStatus = docker ps --filter "name=sing-proxy" --format "{{.Status}}" 2>&1 -if ($containerStatus -match "Up") { - Write-Success "Контейнер sing-proxy работает: $containerStatus" -} -else { - Write-Warning "Контейнер может ещё запускаться. Проверьте через: docker ps" -} - -# ========================================== -# ШАГ 4: ИНФОРМАЦИЯ О ПОДКЛЮЧЕНИИ -# ========================================== -Write-Host "" -Write-Host "==========================================" -ForegroundColor Green -Write-Host " 🎉 УСТАНОВКА ЗАВЕРШЕНА! " -ForegroundColor Green -Write-Host "==========================================" -ForegroundColor Green -Write-Host "" -Write-Host "📡 Адреса подключения:" -ForegroundColor Yellow -Write-Host " Веб-интерфейс: http://localhost:3456" -ForegroundColor White -Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8080" -ForegroundColor White -Write-Host "" -Write-Host "📋 Следующие шаги:" -ForegroundColor Yellow -Write-Host " 1. Откройте http://localhost:3456 в браузере" -ForegroundColor White -Write-Host " 2. Вставьте VLESS ссылку или URL подписки" -ForegroundColor White -Write-Host " 3. Нажмите 'Применить'" -ForegroundColor White -Write-Host "" - -# ========================================== -# ШАГ 5: УСТАНОВКА СКРИПТА ДЛЯ DISCORD -# ========================================== -if (-not $SkipDiscord) { - Write-Host "==========================================" -ForegroundColor Cyan - Write-Host "" - Write-Host "🎮 Хотите установить ProxiFyre для Discord/Vesktop?" -ForegroundColor Yellow - Write-Host " Это позволит направить трафик Discord через прокси" -ForegroundColor Gray - Write-Host "" - Write-Host " [1] Да, установить для Discord" -ForegroundColor White - Write-Host " [2] Да, установить для Vesktop" -ForegroundColor White - Write-Host " [3] Да, установить для Discord + Vesktop" -ForegroundColor White - Write-Host " [n] Нет, пропустить" -ForegroundColor White - Write-Host "" - $discordChoice = Read-Host "👉 Выбор (1-3/n)" - - if ($discordChoice -match "^[123]$") { - # Проверяем права администратора - $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") - - if (-not $isAdmin) { - Write-Warning "Для установки ProxiFyre нужны права администратора!" - Write-Host "" - Write-Host "Запустите этот скрипт от имени администратора," -ForegroundColor Yellow - Write-Host "или запустите discord-windows-hack.ps1 отдельно:" -ForegroundColor Yellow - Write-Host "" - Write-Host " 1. Откройте PowerShell от имени Администратора" -ForegroundColor White - Write-Host " 2. Выполните:" -ForegroundColor White - Write-Host " cd `"$ScriptDir`"" -ForegroundColor Cyan - Write-Host " .\discord-windows-hack.ps1" -ForegroundColor Cyan - Write-Host "" - } - else { - # Запускаем скрипт с параметрами для неинтерактивного режима - $discordScript = Join-Path $ScriptDir "discord-windows-hack.ps1" - - if (Test-Path $discordScript) { - Write-Step "Запуск установки ProxiFyre для Discord..." - - # Определяем целевые приложения - $targetApps = switch ($discordChoice) { - "1" { @("Discord") } - "2" { @("Vesktop") } - "3" { @("Vesktop", "Discord") } - } - - # Вызываем discord-windows-hack.ps1 с параметрами (без дублирования кода) - & $discordScript -Proxy "127.0.0.1:8080" -Apps $targetApps -Force - - # Предупреждение о UDP - Write-Host "" - Write-Host "==========================================" -ForegroundColor Yellow - Write-Host " ⚠️ ВАЖНО: ГОЛОСОВЫЕ ЗВОНКИ DISCORD " -ForegroundColor Yellow - Write-Host "==========================================" -ForegroundColor Yellow - Write-Host "" - Write-Host "Docker Desktop на Windows НЕ ПОДДЕРЖИВАЕТ UDP!" -ForegroundColor Red - Write-Host "Голосовые звонки Discord могут не работать." -ForegroundColor Red - Write-Host "" - Write-Host "Для полной поддержки голоса запустите:" -ForegroundColor Cyan - Write-Host " .\setup-singbox-native.ps1" -ForegroundColor White - Write-Host "" - Write-Host "Этот скрипт установит нативный sing-box," -ForegroundColor Gray - Write-Host "который поддерживает UDP трафик." -ForegroundColor Gray - - } - else { - Write-Warning "Скрипт discord-windows-hack.ps1 не найден" - Write-Info "Скачайте его или создайте вручную" - } - } - } - else { - Write-Info "Установка Discord прокси пропущена" - } -} - -# ========================================== -# ФИНАЛЬНЫЕ ИНСТРУКЦИИ -# ========================================== -Write-Host "" -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host " 📋 ПОЛЕЗНЫЕ КОМАНДЫ " -ForegroundColor Cyan -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host "" -Write-Host "🐳 Docker:" -ForegroundColor Yellow -Write-Host " docker ps - статус контейнера" -ForegroundColor Gray -Write-Host " docker logs --tail 50 sing-proxy - логи VPN-прокси" -ForegroundColor Gray -Write-Host " docker compose restart - перезапуск" -ForegroundColor Gray -Write-Host " docker compose down - остановка" -ForegroundColor Gray -Write-Host "" -Write-Host "🛡️ ProxiFyre (если установлен):" -ForegroundColor Yellow -Write-Host " Get-Content C:\Tools\ProxiFyre\app-config.json - конфиг" -ForegroundColor Gray -Write-Host " Get-ChildItem C:\Tools\ProxiFyre\logs - список логов" -ForegroundColor Gray -Write-Host " Get-Content C:\Tools\ProxiFyre\logs\*.log -Tail 50 - последние логи" -ForegroundColor Gray -Write-Host " Get-Service ProxiFyreService - статус службы" -ForegroundColor Gray -Write-Host " Restart-Service ProxiFyreService - перезапуск службы" -ForegroundColor Gray -Write-Host "" diff --git a/manage.ps1 b/manage.ps1 new file mode 100644 index 0000000..4863bed --- /dev/null +++ b/manage.ps1 @@ -0,0 +1,65 @@ +# ========================================== +# 🚀 VPN PROXY CONTROL CENTER (WINDOWS) +# ========================================== +# Главный скрипт управления. Запускать от имени Администратора. + +$ScriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path } +$LibDir = "$ScriptDir\scripts\lib" + +# Проверка библиотек +if (!(Test-Path "$LibDir\Common.ps1")) { + Write-Host "❌ Ошибка: Не найдены библиотеки в $LibDir" -ForegroundColor Red + exit 1 +} + +. "$LibDir\Common.ps1" +. "$LibDir\System.ps1" + +Ensure-Admin + +while ($true) { + Write-Header "VPN PROXY CONTROL CENTER" + + # --- СБОР СТАТУСОВ --- + + # 1. Native Sing-box + $sbStatus = Get-TaskStatus -Name "SingBoxProxy" + $sbStr = if ($sbStatus -eq "Running") { "РАБОТАЕТ" } else { "ОСТАНОВЛЕН" } + $sbColor = if ($sbStatus -eq "Running") { "Green" } else { "Yellow" } + if (!$sbStatus) { $sbStr = "НЕ УСТАНОВЛЕН"; $sbColor = "Gray" } + + # 2. Discord Proxy + $discSvc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue + $discStr = if ($discSvc.Status -eq 'Running') { "АКТИВЕН" } else { "НЕ АКТИВЕН" } + $discColor = if ($discSvc.Status -eq 'Running') { "Green" } else { "Gray" } + + # --- ОТРИСОВКА МЕНЮ --- + + Write-Host " [1] 📦 VPN Клиент (Sing-box)" -NoNewline -ForegroundColor White + Write-Host " [$sbStr]" -ForegroundColor $sbColor + Write-Host " Основной способ. Поддерживает UDP и игры." -ForegroundColor Gray + Write-Host "" + + Write-Host " [2] 🎮 Настройка Discord/Vesktop" -NoNewline -ForegroundColor White + Write-Host " [$discStr]" -ForegroundColor $discColor + Write-Host " Маршрутизация приложений через прокси." -ForegroundColor Gray + Write-Host "" + + Write-Host " ---------------------------------------" -ForegroundColor DarkGray + + + Write-Host " [3] 🔄 Обновить статус" -ForegroundColor White + Write-Host " [U] ❌ Удалить всё (Uninstall)" -ForegroundColor Red + Write-Host " [q] Выход" -ForegroundColor White + Write-Host "" + + $choice = Read-Host "👉 Ваш выбор" + + switch ($choice) { + "1" { & "$ScriptDir\scripts\setup-singbox.ps1" } + "2" { & "$ScriptDir\scripts\setup-discord.ps1" } + "3" { continue } + "u" { & "$ScriptDir\scripts\uninstall-all.ps1" } + "q" { exit } + } +} diff --git a/scripts/lib/Common.ps1 b/scripts/lib/Common.ps1 new file mode 100644 index 0000000..0a18391 --- /dev/null +++ b/scripts/lib/Common.ps1 @@ -0,0 +1,59 @@ +# ========================================== +# 🛠️ COMMON UTILS +# ========================================== + +# --- ЦВЕТА И ВЫВОД --- + +function Write-Step { param($msg) Write-Host "`n📦 $msg" -ForegroundColor Cyan } +function Write-Success { param($msg) Write-Host " ✅ $msg" -ForegroundColor Green } +function Write-Warning { param($msg) Write-Host " ⚠️ $msg" -ForegroundColor Yellow } +function Write-Error { param($msg) Write-Host " ❌ $msg" -ForegroundColor Red } +function Write-Info { param($msg) Write-Host " ℹ️ $msg" -ForegroundColor Gray } + +function Write-Header { + param($Title) + Write-Host "" + Write-Host "==========================================" -ForegroundColor Cyan + Write-Host " $Title" -ForegroundColor Cyan + Write-Host "==========================================" -ForegroundColor Cyan + Write-Host "" +} + +# --- ПОЛЕЗНЫЕ ФУНКЦИИ --- + +function Get-ScriptDirectory { + if ($PSScriptRoot) { return $PSScriptRoot } + return Split-Path -Parent $MyInvocation.MyCommand.Path +} + +function Ensure-Admin { + $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") + if (-not $isAdmin) { + Write-Host "⛔ Требуются права АДМИНИСТРАТОРА!" -ForegroundColor Red + Write-Host " Пожалуйста, запустите скрипт от имени администратора." -ForegroundColor Gray + Start-Sleep -Seconds 3 + exit 1 + } +} + +function Show-Menu { + param( + [string]$Title, + [System.Collections.Specialized.OrderedDictionary]$Options, + [string]$Prompt = "👉 Ваш выбор" + ) + + if ($Title) { + Write-Host "`n$Title" -ForegroundColor Yellow + } + + $keys = $Options.Keys + foreach ($key in $keys) { + Write-Host " [$key] $($Options[$key])" -ForegroundColor White + } + Write-Host "" + + return Read-Host "$Prompt" +} + + diff --git a/scripts/lib/Net.ps1 b/scripts/lib/Net.ps1 new file mode 100644 index 0000000..1a0922f --- /dev/null +++ b/scripts/lib/Net.ps1 @@ -0,0 +1,140 @@ +# ========================================== +# 🌐 NET UTILS +# ========================================== + +# --- CONFIG --- +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +# --- ФУНКЦИИ --- + +$script:HwidFile = "C:\Tools\sing-box\hwid" +$script:AppName = "VPN-Proxy-Control by Dokril" + +function Get-HWID { + # Генерация или чтение HWID из файла + if (Test-Path $script:HwidFile) { + return (Get-Content $script:HwidFile -Raw).Trim() + } + + # Генерируем новый HWID + $hwid = [Guid]::NewGuid().ToString("N").Substring(0, 16) + + # Сохраняем + $dir = Split-Path $script:HwidFile -Parent + if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + Set-Content -Path $script:HwidFile -Value $hwid + + return $hwid +} + +function Get-SubscriptionHeaders { + # Формируем заголовки как в server.py + $osName = "windows" + $osVersion = [Environment]::OSVersion.Version.ToString() + + return @{ + "User-Agent" = "singbox" + "x-hwid" = (Get-HWID) + "x-device-os" = $osName + "x-ver-os" = $osVersion + "x-device-model" = $script:AppName + } +} + +function Download-File { + param( + [string]$Url, + [string]$Destination, + [string]$UserAgent = "VPN-Proxy-Installer" + ) + + try { + $req = [System.Net.HttpWebRequest]::Create($Url) + $req.UserAgent = $UserAgent + $resp = $req.GetResponse() + + $stream = $resp.GetResponseStream() + $fs = [System.IO.File]::Create($Destination) + $msgLen = $resp.ContentLength + + $buffer = New-Object byte[] 10240 + $count = 0 + $total = 0 + + do { + $count = $stream.Read($buffer, 0, $buffer.Length) + $fs.Write($buffer, 0, $count) + $total += $count + # Можно добавить прогресс бар, но пока просто качаем + } while ($count -gt 0) + + $fs.Close() + $stream.Close() + $resp.Close() + + return $true + } + catch { + Write-Error "Ошибка скачивания: $_" + return $false + } +} + +function Get-SubscriptionData { + param( + [string]$Url, + [string]$UserAgent = "singbox", + $Headers = @{} + ) + + Write-Info "Загружаю подписку..." + + $rawContent = $null + $userInfo = @{} + + # 1. Получаем ответ + try { + $response = Invoke-WebRequest -Uri $Url -Headers $Headers -TimeoutSec 15 -UseBasicParsing + $rawContent = $response.Content + + # Парсим subscription-userinfo header + $userInfoHeader = $response.Headers["subscription-userinfo"] + if ($userInfoHeader) { + $parts = $userInfoHeader -split ";" + foreach ($part in $parts) { + if ($part -match "(\w+)=(\d+)") { + $userInfo[$matches[1]] = [int64]$matches[2] + } + } + } + } + catch { + return @{ + success = $false + error = "Ошибка загрузки: $($_.Exception.Message)" + rawContent = $null + } + } + + # 2. Пробуем парсить как JSON + try { + $config = $rawContent | ConvertFrom-Json + return @{ + success = $true + config = $config + rawContent = $rawContent + userInfo = $userInfo + } + } + catch { + # JSON не распарсился — возвращаем rawContent для дальнейшей обработки + return @{ + success = $false + error = "Ответ не в формате JSON (возможно Base64 или список ссылок)" + rawContent = $rawContent + userInfo = $userInfo + } + } +} + + diff --git a/scripts/lib/System.ps1 b/scripts/lib/System.ps1 new file mode 100644 index 0000000..b3dc5b8 --- /dev/null +++ b/scripts/lib/System.ps1 @@ -0,0 +1,156 @@ +# ========================================== +# 🖥️ SYSTEM UTILS +# ========================================== + +# --- СИСТЕМНАЯ ИНФОРМАЦИЯ --- + +function Get-HWID { + param([string]$StoreDir) + + $hwidFile = "$StoreDir\hwid" + if (Test-Path $hwidFile) { + return (Get-Content $hwidFile -Raw).Trim() + } + + $hwid = [System.Guid]::NewGuid().ToString("N").Substring(0, 16) + + if (!(Test-Path $StoreDir)) { + New-Item -ItemType Directory -Path $StoreDir -Force | Out-Null + } + + Set-Content -Path $hwidFile -Value $hwid + return $hwid +} + +function Get-SystemInfo { + return @{ + os = "windows" + version = [System.Environment]::OSVersion.Version.Major.ToString() + } +} + +# --- DOCKER --- + +function Test-Docker { + $status = @{ + Installed = $false + Running = $false + Compose = $false + } + + try { + $ver = docker --version 2>&1 + if ($LASTEXITCODE -eq 0) { $status.Installed = $true } + } + catch {} + + if ($status.Installed) { + try { + $info = docker info 2>&1 + if ($LASTEXITCODE -eq 0) { $status.Running = $true } + } + catch {} + } + + if ($status.Running) { + try { + $comp = docker compose version 2>&1 + if ($LASTEXITCODE -eq 0) { $status.Compose = $true } + } + catch { + # Check legacy + try { + $comp = docker-compose --version 2>&1 + if ($LASTEXITCODE -eq 0) { $status.Compose = $true } + } + catch {} + } + } + + return $status +} + +# --- СЛУЖБЫ И ЗАДАЧИ --- + +function Manage-ScheduledTask { + param( + [string]$Name, + [string]$ExePath, + [string]$Arguments, + [string]$WorkDir, + [string]$Action = "Install" # Install, Uninstall, Start, Stop + ) + + switch ($Action) { + "Install" { + # Удаляем старую + Unregister-ScheduledTask -TaskName $Name -Confirm:$false -ErrorAction SilentlyContinue + + $act = New-ScheduledTaskAction -Execute "$ExePath" -Argument "$Arguments" -WorkingDirectory $WorkDir + $trig = New-ScheduledTaskTrigger -AtStartup + $princ = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + $sett = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) + + Register-ScheduledTask -TaskName $Name -Action $act -Trigger $trig -Principal $princ -Settings $sett -Force | Out-Null + return $true + } + "Uninstall" { + Unregister-ScheduledTask -TaskName $Name -Confirm:$false -ErrorAction SilentlyContinue + } + "Start" { + Start-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue + } + "Stop" { + Stop-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue + # Пытаемся убить процесс по имени exe + if ($ExePath) { + $procName = [System.IO.Path]::GetFileNameWithoutExtension($ExePath) + if ($procName) { + Stop-Process -Name $procName -Force -ErrorAction SilentlyContinue + } + } + } + } +} + +function Get-TaskStatus { + param([string]$Name) + $task = Get-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue + if ($task) { + # Если задача в статусе Running — возвращаем Running + if ($task.State -eq "Running") { + return "Running" + } + + # Если задача Ready — проверяем, работает ли процесс sing-box + # (scheduled task может быть Ready даже когда процесс работает) + $process = Get-Process -Name "sing-box" -ErrorAction SilentlyContinue + if ($process) { + return "Running" + } + + return $task.State + } + return $null +} + + + +function Ensure-FirewallPort { + param( + [int]$Port, + [string]$Name, + [string]$Protocol = "TCP" + ) + + $rule = Get-NetFirewallRule -DisplayName $Name -ErrorAction SilentlyContinue + if (-not $rule) { + New-NetFirewallRule -DisplayName $Name -Direction Inbound -LocalPort $Port -Protocol $Protocol -Action Allow -Profile Any | Out-Null + return $true + } + return $false +} + +function Get-LocalIPs { + return (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias * | Where-Object { $_.IPAddress -notmatch "^127\." -and $_.IPAddress -notmatch "^169\.254\." }).IPAddress +} diff --git a/scripts/setup-discord.ps1 b/scripts/setup-discord.ps1 new file mode 100644 index 0000000..19d8b29 --- /dev/null +++ b/scripts/setup-discord.ps1 @@ -0,0 +1,100 @@ +# ========================================== +# 🎮 DISCORD PROXY SETUP +# ========================================== + +param([switch]$Force) + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +. "$ScriptDir\lib\Common.ps1" +. "$ScriptDir\lib\Net.ps1" +. "$ScriptDir\lib\System.ps1" + +Write-Header "НАСТРОЙКА DISCORD / VESKTOP" + +Ensure-Admin + +$InstallPath = "C:\Tools\ProxiFyre" +$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" + +# Проверка Sing-box +$singboxStatus = Get-TaskStatus -Name "SingBoxProxy" +$localProxy = "127.0.0.1:1080" +$useLocal = $false + +if ($singboxStatus -eq "Running") { + Write-Info "Обнаружен работающий Native Sing-box." + $useLocal = $true +} +else { + Write-Warning "Native Sing-box не запущен!" + Write-Host " Для работы голосовых звонков он необходим." -ForegroundColor Gray + Write-Host " Вы можете вернуться в главное меню и настроить его." -ForegroundColor Gray + if ((Read-Host " Продолжить настройку БЕЗ него (голос может не работать)? (y/n)") -ne 'y') { exit } +} + +# Меню выбора приложений +Write-Host "`n🎮 Какие приложения проксировать?" -ForegroundColor Yellow +$appOpts = [Ordered]@{ + "1" = "Discord" + "2" = "Vesktop" + "3" = "Discord + Vesktop" +} +$appChoice = Show-Menu -Options $appOpts +$targetApps = switch ($appChoice) { + "1" { @("Discord") } + "2" { @("Vesktop") } + "3" { @("Vesktop", "Discord") } + default { @("Discord") } +} + +$proxyAddr = $localProxy +if (!$useLocal) { + $proxyAddr = Read-Host "Введите адрес прокси (хост:порт) [Enter для $localProxy]" + if ([string]::IsNullOrWhiteSpace($proxyAddr)) { $proxyAddr = $localProxy } +} + +# Установка драйвера +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..." +if (!(Test-Path $InstallPath) -or $Force) { + 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 + # Handle update folder structure if needed, simplified here assuming flat or check generic + $exe = Get-ChildItem $InstallPath -Recurse -Filter "ProxiFyre.exe" | Select -First 1 + if ($exe.DirectoryName -ne $InstallPath) { + Copy-Item "$($exe.DirectoryName)\*" $InstallPath -Recurse -Force + } + Write-Success "Распаковано" + } +} + +# Конфиг +$cfg = @{ + logLevel = "Info" + proxies = @(@{ + appNames = $targetApps + socks5ProxyEndpoint = $proxyAddr + supportedProtocols = @("TCP", "UDP") + }) + excludes = @() +} +$cfg | ConvertTo-Json -Depth 5 | Set-Content "$InstallPath\app-config.json" -Encoding UTF8 + +# Служба +Write-Step "Перезапуск службы..." +Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow +Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "install" -Wait -NoNewWindow +Start-Process "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow + +Write-Success "Готово! Discord должен работать через прокси." +Start-Sleep -Seconds 3 diff --git a/scripts/setup-singbox.ps1 b/scripts/setup-singbox.ps1 new file mode 100644 index 0000000..772df9e --- /dev/null +++ b/scripts/setup-singbox.ps1 @@ -0,0 +1,414 @@ +# ========================================== +# 📦 SING-BOX NATIVE INSTALLER +# ========================================== + +param( + [switch]$Force, + [string]$SubscriptionUrl = "" +) + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +. "$ScriptDir\lib\Common.ps1" +. "$ScriptDir\lib\Net.ps1" +. "$ScriptDir\lib\System.ps1" + +# --- CONFIG --- +$SingboxVersion = "1.11.4" +$InstallDir = "C:\Tools\sing-box" +$LocalProxyPort = 1080 +$SingboxUrl = "https://github.com/SagerNet/sing-box/releases/download/v$SingboxVersion/sing-box-$SingboxVersion-windows-amd64.zip" +$TaskName = "SingBoxProxy" + +Ensure-Admin + +# --- LOGIC --- + +function Select-Server { + param($Config) + + $outbounds = $Config.outbounds + $servers = @() + + foreach ($outbound in $outbounds) { + if ($outbound.type -in @("vless", "vmess", "trojan", "shadowsocks", "hysteria2")) { + $servers += @{ + tag = $outbound.tag + type = $outbound.type + server = $outbound.server + server_port = $outbound.server_port + outbound = $outbound + } + } + } + + if ($servers.Count -eq 0) { + Write-Error "Серверы не найдены в подписке!" + return $null + } + + $options = [Ordered]@{} + for ($i = 0; $i -lt $servers.Count; $i++) { + $s = $servers[$i] + $options["$($i+1)"] = "$($s.tag) ($($s.server):$($s.server_port))" + } + + $choice = Show-Menu -Title "🌐 Доступные серверы" -Options $options -Prompt "👉 Выберите сервер (номер)" + $index = [int]$choice - 1 + + if ($index -lt 0 -or $index -ge $servers.Count) { + Write-Error "Неверный выбор!" + return $null + } + + return $servers[$index] +} + +function New-SingboxConfig { + param($Outbound, $Port) + + return @{ + log = @{ level = "info"; timestamp = $true } + dns = @{ independent_cache = $true } + inbounds = @( + @{ + type = "socks" + tag = "socks-in" + listen = "0.0.0.0" + listen_port = $Port + } + ) + outbounds = @( + $Outbound, + @{ type = "direct"; tag = "direct" } + ) + route = @{ + final = $Outbound.tag + auto_detect_interface = $true + } + } +} + +function Parse-VlessUrl { + param([string]$Url) + + if (-not $Url.StartsWith("vless://")) { throw "URL должен начинаться с vless://" } + + # Remove scheme + $raw = $Url.Substring(8) + + # Split fragment + $tag = "reality" + if ($raw -match "#(.*)$") { + $tag = [System.Web.HttpUtility]::UrlDecode($matches[1]) + $raw = $raw -replace "#.*$", "" + } + + # Split query + $queryStr = "" + if ($raw -match "\?(.*)$") { + $queryStr = $matches[1] + $raw = $raw -replace "\?.*$", "" + } + + # Parse UUID@HOST:PORT + if ($raw -notmatch "([^@]+)@([^:]+):(\d+)") { throw "Неверный формат vless (ожидается uuid@host:port)" } + $uuid = $matches[1][0] + $serverHost = $matches[2][0] + $port = [int]$matches[3][0] # Fix for regex object access in PS + + if (-not $uuid) { + # Fallback if regex returns match info differently in different PS versions + $uuid = $matches[1] + $serverHost = $matches[2] + $port = [int]$matches[3] + } + + + # Parse Query + $params = @{} + if ($queryStr) { + $parts = $queryStr -split "&" + foreach ($p in $parts) { + $kv = $p -split "=" + if ($kv.Count -eq 2) { + $params[[System.Web.HttpUtility]::UrlDecode($kv[0])] = [System.Web.HttpUtility]::UrlDecode($kv[1]) + } + } + } + + # Extract + $pbk = if ($params["pbk"]) { $params["pbk"] } else { throw "Отсутствует параметр pbk (Public Key)" } + $sid = if ($params["sid"]) { $params["sid"] } else { throw "Отсутствует параметр sid (Short ID)" } + $sni = if ($params["sni"]) { $params["sni"] } else { $serverHost } + $fp = if ($params["fp"]) { $params["fp"] } else { "chrome" } + $flow = if ($params["flow"]) { $params["flow"] } else { "" } + + return @{ + uuid = $uuid + server = $serverHost + server_port = $port + tag = $tag + public_key = $pbk + short_id = $sid + server_name = $sni + fingerprint = $fp + flow = $flow + } +} + +# --- MAIN --- + +Write-Header "NATIVE SING-BOX (UDP ПОДДЕРЖКА)" + +$taskStatus = Get-TaskStatus -Name $TaskName + +if ($taskStatus -and -not $Force) { + Write-Info "Sing-box уже установлен." + Write-Host " Статус: $taskStatus" -ForegroundColor ($taskStatus -eq "Running" ? "Green" : "Red") + Write-Host "" + + $opts = [Ordered]@{ + "1" = "Сменить сервер (из подписки)" + "2" = "Ввести новую ссылку на подписку" + "3" = "Перезапустить службу" + "4" = "Остановить службу" + "5" = "Показать конфиг" + "6" = "Переустановить" + "b" = "Назад" + } + + $act = Show-Menu -Options $opts + + switch ($act) { + "1" { + # Reload existing sub logic could be added here, currently just re-runs install flow partially + # Simplification: treat as new setup but try to load saved sub url + $Force = $true + } + "2" { $SubscriptionUrl = ""; $Force = $true } + "3" { Manage-ScheduledTask -Name $TaskName -Action "Start"; Write-Success "Запущено!"; exit } + "4" { Manage-ScheduledTask -Name $TaskName -Action "Stop"; Write-Success "Остановлено!"; exit } + "5" { Get-Content "$InstallDir\config.json"; exit } + "6" { $Force = $true } + "b" { exit } + } +} + +if ($Force -or -not $taskStatus) { + # 1. Загрузка + Write-Step "Установка Sing-box..." + if (!(Test-Path "$InstallDir\sing-box.exe")) { + New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null + $zipCtx = "$env:TEMP\sing-box.zip" + if (Download-File -Url $SingboxUrl -Destination $zipCtx) { + Expand-Archive -Path $zipCtx -DestinationPath $env:TEMP -Force + $extracted = Get-ChildItem "$env:TEMP\sing-box-*" -Directory | Select -First 1 + Copy-Item "$($extracted.FullName)\sing-box.exe" "$InstallDir\sing-box.exe" -Force + Remove-Item $zipCtx; Remove-Item $extracted.FullName -Recurse -Force + Write-Success "Sing-box скачан" + } + else { + Read-Host "Нажмите Enter для выхода..." + exit 1 + } + } + + # 2. Подписка + if ([string]::IsNullOrWhiteSpace($SubscriptionUrl)) { + # Try load saved + $savedSub = "$InstallDir\sub_info.json" + if (Test-Path $savedSub) { + try { + $json = Get-Content $savedSub -Raw | ConvertFrom-Json + if ($json.url) { + Write-Info "Найдена сохраненная подписка: $($json.url)" + if ((Read-Host "Использовать? (y/n)") -eq 'y') { $SubscriptionUrl = $json.url } + } + } + catch {} + } + } + + if ([string]::IsNullOrWhiteSpace($SubscriptionUrl)) { + $SubscriptionUrl = Read-Host "`n🔗 Введите URL подписки (VLESS)" + } + + if ([string]::IsNullOrWhiteSpace($SubscriptionUrl)) { + Write-Error "Url не указан" + Read-Host "Нажмите Enter для выхода..." + exit + } + + # --- PARSING --- + $data = @{ success = $false; config = $null; error = "" } + + if ($SubscriptionUrl.StartsWith("vless://")) { + try { + $p = Parse-VlessUrl -Url $SubscriptionUrl + $outbound = [Ordered]@{ + type = "vless" + tag = $p.tag + server = $p.server + server_port = $p.server_port + uuid = $p.uuid + flow = $p.flow + tls = @{ + enabled = $true + server_name = $p.server_name + utls = @{ enabled = $true; fingerprint = $p.fingerprint } + reality = @{ + enabled = $true + public_key = $p.public_key + short_id = $p.short_id + } + } + packet_encoding = "xudp" + } + $data.success = $true + $data.config = @{ outbounds = @($outbound) } + } + catch { + $data.error = $_.Exception.Message + } + } + else { + $data = Get-SubscriptionData -Url $SubscriptionUrl -Headers (Get-SubscriptionHeaders) + } + + + # --- PARSING LOGIC ENHANCEMENT --- + if (-not $data.success) { + # Fallback: Try to handle non-JSON body (Base64 or Plain Text) + try { + Write-Info "JSON парсинг не удался, пробую как список ссылок..." + $content = $data.rawContent + + # Base64 decode if needed + if ($content -match "^[A-Za-z0-9+/=]+$") { + try { + $bytes = [System.Convert]::FromBase64String($content) + $content = [System.Text.Encoding]::UTF8.GetString($bytes) + } + catch {} + } + + # Try to find vless:// links + $links = $content -split "[\r\n]+" | Where-Object { $_ -match "^vless://" } + + if ($links.Count -gt 0) { + Write-Success "Найдено ссылок: $($links.Count)" + + # Mock a config object with these links as "outbounds" + # Note: We can't fully parsing VLESS query params in pure PS easily without a lot of regex + # So we will try a simpler approach: Let sing-box do it? No, sing-box needs config. + + # WORKAROUND: Create a minimal outbound for each link + # Parsing `vless://UUID@HOST:PORT?security=reality&...#NAME` + $parsedOutbounds = @() + + foreach ($link in $links) { + if ($link -match "vless://([^@]+)@([^:]+):(\d+)(\?.*)?(#.*)?") { + $uuid = $matches[1] + $server = $matches[2] + $port = [int]$matches[3] + $query = $matches[4] + $hash = $matches[5] + + $tag = if ($hash) { $hash.Substring(1) } else { "${server}:${port}" } + $tag = [System.Web.HttpUtility]::UrlDecode($tag) + + # Parse Query Params + $flow = ""; $fp = ""; $pbk = ""; $sid = ""; $sni = ""; $serviceName = "" + + if ($query) { + if ($query -match "flow=([^&]+)") { $flow = $matches[1] } + if ($query -match "fp=([^&]+)") { $fp = $matches[1] } + if ($query -match "pbk=([^&]+)") { $pbk = $matches[1] } + if ($query -match "sid=([^&]+)") { $sid = $matches[1] } + if ($query -match "sni=([^&]+)") { $sni = $matches[1] } + if ($query -match "serviceName=([^&]+)") { $serviceName = $matches[1] } + } + + # Construct Sing-box outbound (REALITY based assumption for modern vless) + $out = [Ordered]@{ + type = "vless" + tag = $tag + server = $server + server_port = $port + uuid = $uuid + flow = $flow + tls = @{ + enabled = $true + server_name = $sni + utls = @{ enabled = $true; fingerprint = $fp } + reality = @{ + enabled = $true + public_key = $pbk + short_id = $sid + } + } + packet_encoding = "xudp" + } + $parsedOutbounds += $out + } + } + + if ($parsedOutbounds.Count -gt 0) { + $data.success = $true + $data.config = @{ outbounds = $parsedOutbounds } + $data.error = $null + } + else { + throw "Не удалось распарсить VLESS ссылки" + } + + } + else { + throw $data.error + } + } + catch { + Write-Error "Ошибка обработки подписки: $_" + Write-Host " Скрипт поддерживает: SIP008 (JSON) или список VLESS+Reality ссылок." -ForegroundColor Yellow + Read-Host "Нажмите Enter для выхода..." + exit + } + } + + + # Save sub info + @{ url = $SubscriptionUrl } | ConvertTo-Json | Set-Content "$InstallDir\sub_info.json" + + # 3. Выбор сервера + $server = Select-Server -Config $data.config + if (!$server) { + Read-Host "Нажмите Enter для выхода..." + exit + } + + # 4. Конфиг + $cfg = New-SingboxConfig -Outbound $server.outbound -Port $LocalProxyPort + $cfg | ConvertTo-Json -Depth 10 | Set-Content "$InstallDir\config.json" -Encoding UTF8 + + # 5. Задача + Manage-ScheduledTask -Name $TaskName -ExePath "$InstallDir\sing-box.exe" -Arguments "run -c `"$InstallDir\config.json`"" -WorkDir $InstallDir -Action "Install" + Manage-ScheduledTask -Name $TaskName -Action "Start" + + # 6. Firewall + if (Ensure-FirewallPort -Port $LocalProxyPort -Name "SingBox-Proxy-Port") { + Write-Success "Правило Firewall создано (порт $LocalProxyPort)" + } + + Write-Success "Успешно установлено и запущено!" + Write-Info "Локальный прокси: 127.0.0.1:$LocalProxyPort" + + $ips = Get-LocalIPs + if ($ips) { + Write-Info "Доступно из сети по адресам:" + foreach ($ip in $ips) { + Write-Host " ${ip}:$LocalProxyPort" -ForegroundColor Gray + } + } + + Start-Sleep -Seconds 3 +} diff --git a/scripts/uninstall-all.ps1 b/scripts/uninstall-all.ps1 new file mode 100644 index 0000000..d1f8ff3 --- /dev/null +++ b/scripts/uninstall-all.ps1 @@ -0,0 +1,48 @@ +# ========================================== +# 🗑️ UNINSTALL ALL (CLEANUP) +# ========================================== + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +. "$ScriptDir\lib\Common.ps1" +. "$ScriptDir\lib\System.ps1" + +Write-Header "ПОЛНОЕ УДАЛЕНИЕ" + +Ensure-Admin + +Write-Warning "Это действие удалит весь установленный софт:" +Write-Host " - Sing-box (Служба и файлы)" -ForegroundColor Gray +Write-Host " - ProxiFyre (Служба и файлы)" -ForegroundColor Gray +Write-Host " - Драйвер WinPacketFilter" -ForegroundColor Gray +Write-Host "" + +if ((Read-Host "Вы уверены? (y/n)") -ne 'y') { exit } + +Write-Step "Удаление Sing-box..." +Manage-ScheduledTask -Name "SingBoxProxy" -Action "Stop" +Manage-ScheduledTask -Name "SingBoxProxy" -Action "Uninstall" + +if (Test-Path "C:\Tools\sing-box") { + Remove-Item "C:\Tools\sing-box" -Recurse -Force -ErrorAction SilentlyContinue + Write-Success "Файлы удалены" +} + +Write-Step "Удаление Discrod Proxy (ProxiFyre)..." +$pfDir = "C:\Tools\ProxiFyre" +if (Test-Path "$pfDir\ProxiFyre.exe") { + Start-Process "$pfDir\ProxiFyre.exe" -ArgumentList "uninstall" -Wait -NoNewWindow + Start-Sleep -Seconds 2 +} + +if (Test-Path $pfDir) { + Remove-Item $pfDir -Recurse -Force -ErrorAction SilentlyContinue + Write-Success "Файлы удалены" +} + +Write-Step "Удаление драйвера..." +# Тут сложно удалить MSI тихо без GUID, но попробуем через known path или пропустим, т.к. драйвер может быть нужен другим +Write-Info "Драйвер WinPacketFilter оставлен (он может использоваться другим ПО)." +Write-Info "Если нужно, удалите его через 'Установка и удаление программ'." + +Write-Success "Очистка завершена!" +Start-Sleep -Seconds 3 diff --git a/setup-singbox-native.ps1 b/setup-singbox-native.ps1 deleted file mode 100644 index 17eef4e..0000000 --- a/setup-singbox-native.ps1 +++ /dev/null @@ -1,439 +0,0 @@ -# ========================================== -# 🎯 SING-BOX NATIVE INSTALLER FOR WINDOWS -# ========================================== -# Устанавливает нативный sing-box для поддержки UDP (Discord голосовые) -# Используется когда Docker запущен ЛОКАЛЬНО на Windows -# (Docker Desktop не поддерживает UDP) -# ========================================== - -param( - [switch]$Force, # Принудительная переустановка - [string]$SubscriptionUrl = "" # URL подписки (для неинтерактивного режима) -) - -# ========================================== -# КОНФИГУРАЦИЯ -# ========================================== -$SingboxVersion = "1.11.4" -$InstallDir = "C:\Tools\sing-box" -$LocalProxyPort = 1080 - -# Ссылки для скачивания -$SingboxUrl = "https://github.com/SagerNet/sing-box/releases/download/v$SingboxVersion/sing-box-$SingboxVersion-windows-amd64.zip" - -# App Info (для заголовков подписки) -$AppName = "VPN-Proxy-Control by Dokril" - -# ========================================== -# ЦВЕТА И ВЫВОД -# ========================================== -function Write-Step { param($msg) Write-Host "`n📦 $msg" -ForegroundColor Cyan } -function Write-Success { param($msg) Write-Host " ✅ $msg" -ForegroundColor Green } -function Write-Warning { param($msg) Write-Host " ⚠️ $msg" -ForegroundColor Yellow } -function Write-Error { param($msg) Write-Host " ❌ $msg" -ForegroundColor Red } -function Write-Info { param($msg) Write-Host " ℹ️ $msg" -ForegroundColor Gray } - -# ========================================== -# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ -# ========================================== - -function Get-HWID { - $hwidFile = "$InstallDir\hwid" - if (Test-Path $hwidFile) { - return (Get-Content $hwidFile -Raw).Trim() - } - - $hwid = [System.Guid]::NewGuid().ToString("N").Substring(0, 16) - - if (!(Test-Path $InstallDir)) { - New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null - } - - Set-Content -Path $hwidFile -Value $hwid - return $hwid -} - -function Get-SystemInfo { - return @{ - os = "windows" - version = [System.Environment]::OSVersion.Version.Major.ToString() - } -} - -function Get-SubscriptionData { - param([string]$Url) - - Write-Info "Загружаю подписку..." - - $hwid = Get-HWID - $sysInfo = Get-SystemInfo - - $headers = @{ - "User-Agent" = "singbox" - "x-hwid" = $hwid - "x-device-os" = $sysInfo.os - "x-ver-os" = $sysInfo.version - "x-device-model" = $AppName - } - - try { - $response = Invoke-WebRequest -Uri $Url -Headers $headers -TimeoutSec 15 -UseBasicParsing - $config = $response.Content | ConvertFrom-Json - - $userInfo = @{} - $userInfoHeader = $response.Headers["subscription-userinfo"] - if ($userInfoHeader) { - $parts = $userInfoHeader -split ";" - foreach ($part in $parts) { - if ($part -match "(\w+)=(\d+)") { - $userInfo[$matches[1]] = [int64]$matches[2] - } - } - } - - return @{ - success = $true - config = $config - userInfo = $userInfo - } - } - catch { - return @{ - success = $false - error = $_.Exception.Message - } - } -} - -function Select-Server { - param($Config) - - $outbounds = $Config.outbounds - $servers = @() - - foreach ($outbound in $outbounds) { - if ($outbound.type -in @("vless", "vmess", "trojan", "shadowsocks", "hysteria2")) { - $servers += @{ - tag = $outbound.tag - type = $outbound.type - server = $outbound.server - server_port = $outbound.server_port - outbound = $outbound - } - } - } - - if ($servers.Count -eq 0) { - Write-Error "Серверы не найдены в подписке!" - return $null - } - - Write-Host "`n🌐 Доступные серверы:" -ForegroundColor Yellow - for ($i = 0; $i -lt $servers.Count; $i++) { - $s = $servers[$i] - Write-Host " [$($i+1)] $($s.tag) ($($s.type)) - $($s.server):$($s.server_port)" - } - - $choice = Read-Host "`n👉 Выберите сервер (1-$($servers.Count))" - $index = [int]$choice - 1 - - if ($index -lt 0 -or $index -ge $servers.Count) { - Write-Error "Неверный выбор!" - return $null - } - - return $servers[$index] -} - -function New-SingboxConfig { - param($Outbound, $Port) - - $config = @{ - log = @{ - level = "info" - timestamp = $true - } - dns = @{ - independent_cache = $true - } - inbounds = @( - @{ - type = "socks" - tag = "socks-in" - listen = "127.0.0.1" - listen_port = $Port - } - ) - outbounds = @( - $Outbound, - @{ - type = "direct" - tag = "direct" - } - ) - route = @{ - final = $Outbound.tag - auto_detect_interface = $true - } - } - - return $config -} - -function Install-SingboxTask { - Write-Step "Установка sing-box через Task Scheduler..." - - $exePath = "$InstallDir\sing-box.exe" - $configPath = "$InstallDir\config.json" - $taskName = "SingBoxProxy" - - # Удаляем старую задачу - Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue - - # Создаём новую - $action = New-ScheduledTaskAction -Execute "$exePath" -Argument "run -c `"$configPath`"" -WorkingDirectory $InstallDir - $trigger = New-ScheduledTaskTrigger -AtStartup - $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest - $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) - - Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null - - # Запускаем сразу - Start-ScheduledTask -TaskName $taskName - - Write-Success "Задача создана и запущена!" - return $true -} - -function Stop-SingboxTask { - Stop-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue - Stop-Process -Name "sing-box" -Force -ErrorAction SilentlyContinue -} - -# ========================================== -# ПРОВЕРКА ПРАВ АДМИНИСТРАТОРА -# ========================================== -if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { - Write-Host "⛔ Запустите скрипт от имени АДМИНИСТРАТОРА!" -ForegroundColor Red - Start-Sleep -Seconds 3 - Exit 1 -} - -Clear-Host -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host " 🎯 SING-BOX NATIVE INSTALLER " -ForegroundColor Cyan -Write-Host " для Discord UDP поддержки " -ForegroundColor Cyan -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host "" -Write-Host "Этот скрипт нужен когда Docker запущен" -ForegroundColor Gray -Write-Host "ЛОКАЛЬНО на Windows (Docker Desktop)." -ForegroundColor Gray -Write-Host "Docker Desktop не поддерживает UDP." -ForegroundColor Gray - -# ========================================== -# ПРОВЕРКА СУЩЕСТВУЮЩЕЙ УСТАНОВКИ -# ========================================== -$singboxExists = Test-Path "$InstallDir\sing-box.exe" -$taskExists = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue - -if ($singboxExists -and $taskExists -and -not $Force) { - Write-Host "" - Write-Host "==========================================" -ForegroundColor Green - Write-Host " ✅ SING-BOX УЖЕ УСТАНОВЛЕН! " -ForegroundColor Green - Write-Host "==========================================" -ForegroundColor Green - Write-Host "" - - $taskInfo = Get-ScheduledTask -TaskName "SingBoxProxy" - $taskState = $taskInfo.State - - Write-Host "📊 Статус: " -NoNewline -ForegroundColor Yellow - if ($taskState -eq "Running") { - Write-Host "РАБОТАЕТ" -ForegroundColor Green - } - else { - Write-Host "$taskState" -ForegroundColor Red - } - - Write-Host "" - Write-Host "📁 Расположение: $InstallDir" -ForegroundColor Yellow - Write-Host "🔌 Локальный SOCKS5: 127.0.0.1:$LocalProxyPort" -ForegroundColor Yellow - Write-Host "" - - Write-Host "Что вы хотите сделать?" -ForegroundColor Yellow - Write-Host " [1] Запустить" -ForegroundColor White - Write-Host " [2] Остановить" -ForegroundColor White - Write-Host " [3] Показать конфиг" -ForegroundColor White - Write-Host " [4] Переустановить" -ForegroundColor White - Write-Host " [q] Выход" -ForegroundColor White - Write-Host "" - - $choice = Read-Host "👉 Выбор (1-4/q)" - - switch ($choice) { - "1" { - Start-ScheduledTask -TaskName "SingBoxProxy" - Start-Sleep -Seconds 2 - Write-Success "Запущено!" - exit 0 - } - "2" { - Stop-SingboxTask - Write-Success "Остановлено!" - exit 0 - } - "3" { - Write-Host "`n📄 Конфигурация:" -ForegroundColor Cyan - Get-Content "$InstallDir\config.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10 - exit 0 - } - "4" { - Write-Info "Переустановка..." - } - default { - exit 0 - } - } -} - -# ========================================== -# УСТАНОВКА -# ========================================== - -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - -# ШАГ 1: Скачиваем sing-box -Write-Step "Скачиваю sing-box v$SingboxVersion..." - -if (!(Test-Path $InstallDir)) { - New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null -} - -$zipFile = "$env:TEMP\sing-box.zip" - -try { - Invoke-WebRequest -Uri $SingboxUrl -OutFile $zipFile -UseBasicParsing - Write-Success "Скачано!" -} -catch { - Write-Error "Ошибка скачивания: $_" - exit 1 -} - -Write-Info "Распаковываю..." -Expand-Archive -Path $zipFile -DestinationPath $env:TEMP -Force - -$extractedDir = Get-ChildItem "$env:TEMP\sing-box-*" -Directory | Select-Object -First 1 -Copy-Item "$($extractedDir.FullName)\sing-box.exe" "$InstallDir\sing-box.exe" -Force - -Remove-Item $zipFile -Force -ErrorAction SilentlyContinue -Remove-Item $extractedDir.FullName -Recurse -Force -ErrorAction SilentlyContinue - -Write-Success "sing-box установлен в $InstallDir" - -# ШАГ 2: Получаем подписку -Write-Step "Настройка подписки..." - -$savedSubFile = Join-Path $PSScriptRoot "data\subscription.json" -$subUrl = $SubscriptionUrl - -if ([string]::IsNullOrWhiteSpace($subUrl) -and (Test-Path $savedSubFile)) { - try { - $savedSub = Get-Content $savedSubFile -Raw | ConvertFrom-Json - if ($savedSub.url) { - Write-Info "Найдена сохранённая подписка" - Write-Host " URL: $($savedSub.url)" -ForegroundColor Gray - $useSaved = Read-Host " Использовать? (y/n)" - if ($useSaved -eq "y") { - $subUrl = $savedSub.url - } - } - } - catch {} -} - -if ([string]::IsNullOrWhiteSpace($subUrl)) { - Write-Host "`n🔗 Введите URL подписки:" -ForegroundColor Yellow - $subUrl = Read-Host "👉" -} - -if ([string]::IsNullOrWhiteSpace($subUrl)) { - Write-Error "URL подписки не указан!" - exit 1 -} - -$subResult = Get-SubscriptionData -Url $subUrl - -if (-not $subResult.success) { - Write-Error "Ошибка загрузки подписки: $($subResult.error)" - exit 1 -} - -Write-Success "Подписка загружена!" - -if ($subResult.userInfo.Count -gt 0) { - $ui = $subResult.userInfo - if ($ui.upload -and $ui.download -and $ui.total) { - $usedGB = [math]::Round(($ui.upload + $ui.download) / 1GB, 2) - $totalGB = [math]::Round($ui.total / 1GB, 2) - Write-Info "Трафик: $usedGB / $totalGB GB" - } -} - -# ШАГ 3: Выбираем сервер -$selectedServer = Select-Server -Config $subResult.config - -if (-not $selectedServer) { - exit 1 -} - -Write-Success "Выбран сервер: $($selectedServer.tag)" - -# ШАГ 4: Генерируем конфиг -Write-Step "Генерирую конфигурацию..." - -$config = New-SingboxConfig -Outbound $selectedServer.outbound -Port $LocalProxyPort -$configJson = $config | ConvertTo-Json -Depth 10 - -Set-Content -Path "$InstallDir\config.json" -Value $configJson -Encoding UTF8 -Write-Success "Конфиг сохранён: $InstallDir\config.json" - -# ШАГ 5: Запускаем -Stop-SingboxTask -Start-Sleep -Seconds 1 - -$installed = Install-SingboxTask - -if (-not $installed) { - Write-Error "Не удалось установить задачу!" - exit 1 -} - -Start-Sleep -Seconds 3 - -# Проверяем порт -Write-Info "Проверяю доступность порта..." -$portCheck = Test-NetConnection -ComputerName 127.0.0.1 -Port $LocalProxyPort -WarningAction SilentlyContinue - -if ($portCheck.TcpTestSucceeded) { - Write-Success "Порт $LocalProxyPort доступен!" -} -else { - Write-Warning "Порт $LocalProxyPort пока недоступен. Подождите несколько секунд." -} - -# Финал -Write-Host "" -Write-Host "==========================================" -ForegroundColor Green -Write-Host " 🎉 SING-BOX УСТАНОВЛЕН! " -ForegroundColor Green -Write-Host "==========================================" -ForegroundColor Green -Write-Host "" -Write-Host "📡 Локальный SOCKS5: 127.0.0.1:$LocalProxyPort" -ForegroundColor Yellow -Write-Host " Сервер: $($selectedServer.tag)" -ForegroundColor White -Write-Host "" -Write-Host "Теперь запустите discord-windows-hack.ps1" -ForegroundColor Cyan -Write-Host "и укажите прокси: 127.0.0.1:$LocalProxyPort" -ForegroundColor Cyan -Write-Host "" -Write-Host "📋 Полезные команды:" -ForegroundColor Gray -Write-Host " Статус: Get-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray -Write-Host " Запустить: Start-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray -Write-Host " Остановить: Stop-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray -Write-Host "" diff --git a/web/server.py b/web/server.py index be72e71..47d9da8 100644 --- a/web/server.py +++ b/web/server.py @@ -516,14 +516,16 @@ class ProxyControlHandler(http.server.BaseHTTPRequestHandler): } ) + config = None + config_text = "" + user_info = {} + try: with urllib.request.urlopen(req, timeout=15) as response: config_text = response.read().decode("utf-8") - config = json.loads(config_text) # Parse User Info header user_info_header = response.headers.get("subscription-userinfo", "") - user_info = {} if user_info_header: parts = user_info_header.split(';') for part in parts: @@ -541,6 +543,68 @@ class ProxyControlHandler(http.server.BaseHTTPRequestHandler): self.send_json({"success": False, "error": f"Ошибка подключения: {e.reason}"}, 400) return + # Try to parse as JSON first + try: + config = json.loads(config_text) + except json.JSONDecodeError: + # Not JSON - try Base64 decode or plain text VLESS links + content = config_text.strip() + + # Try Base64 decode + import base64 + import re + try: + # Check if it looks like Base64 + if re.match(r'^[A-Za-z0-9+/=\s]+$', content): + decoded = base64.b64decode(content).decode('utf-8') + content = decoded + except Exception: + pass # Not Base64, continue with original content + + # Parse VLESS links + lines = content.strip().split('\n') + vless_links = [line.strip() for line in lines if line.strip().startswith('vless://')] + + if not vless_links: + self.send_json({"success": False, "error": "Не найдены VLESS ссылки в ответе"}, 400) + return + + # Parse each VLESS link and create outbounds + outbounds = [] + for link in vless_links: + try: + params = parse_vless_url(link) + outbound = { + "type": "vless", + "tag": params['tag'], + "server": params['server'], + "server_port": params['server_port'], + "uuid": params['uuid'], + "flow": params['flow'], + "tls": { + "enabled": True, + "server_name": params['server_name'], + "utls": {"enabled": True, "fingerprint": params['fingerprint']}, + "reality": { + "enabled": True, + "public_key": params['public_key'], + "short_id": params['short_id'] + } + }, + "packet_encoding": "xudp" + } + outbounds.append(outbound) + except Exception as e: + print(f"[WebUI] Failed to parse VLESS link: {e}") + continue + + if not outbounds: + self.send_json({"success": False, "error": "Не удалось распарсить VLESS ссылки"}, 400) + return + + # Create a mock config with parsed outbounds + config = {"outbounds": outbounds} + # Extract outbound servers outbounds = config.get("outbounds", []) servers = []