# ========================================== # 🎯 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 ""