diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7e9c4879..7e1bd76e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -5,7 +5,7 @@ --- -## ๐Ÿ“Š Stan Projektu (aktualizacja: 2026-02-08) +## ๐Ÿ“Š Stan Projektu (aktualizacja: 2026-02-11) ### Wersja Skryptรณw ALL-IN-ONE (v2.1.1) diff --git a/Dockerfile.console b/Dockerfile.console index 44cb3e30..9ccc0bd6 100644 --- a/Dockerfile.console +++ b/Dockerfile.console @@ -6,8 +6,11 @@ WORKDIR /app # Install system dependencies with DNS fallback for systems with resolver issues # This fixes "Temporary failure resolving 'deb.debian.org'" on some systems (e.g., AlmaLinux) -RUN echo "nameserver 8.8.8.8" >> /etc/resolv.conf && \ - echo "nameserver 1.1.1.1" >> /etc/resolv.conf && \ +# Skip DNS modification on Oracle Cloud VMs (oraclevcn) and read-only resolv.conf +RUN if [ -w /etc/resolv.conf ] && ! grep -q "oraclevcn" /etc/resolv.conf 2>/dev/null; then \ + echo "nameserver 8.8.8.8" >> /etc/resolv.conf; \ + echo "nameserver 1.1.1.1" >> /etc/resolv.conf; \ + fi && \ apt-get update && apt-get install -y \ sqlite3 \ curl \ diff --git a/betterdesk.ps1 b/betterdesk.ps1 index c0411972..28ac5a7d 100644 --- a/betterdesk.ps1 +++ b/betterdesk.ps1 @@ -1,470 +1,408 @@ -#=============================================================================== -# -# BetterDesk Console Manager v2.1.1 -# All-in-One Interactive Tool for Windows -# -# Features: -# - Fresh installation -# - Update existing installation -# - Repair/fix issues -# - Validate installation -# - Backup & restore -# - Reset admin password -# - Build custom binaries -# - Full diagnostics -# - SHA256 binary verification -# - Auto mode (non-interactive) -# -# Usage: Run as Administrator -# Interactive: .\betterdesk.ps1 -# Auto mode: .\betterdesk.ps1 -Auto -# -#=============================================================================== +#Requires -RunAsAdministrator +<# +.SYNOPSIS + BetterDesk Console Manager v2.1.1 - All-in-One Interactive Tool for Windows + +.DESCRIPTION + Features: + - Fresh installation + - Update existing installation + - Repair/fix issues + - Validate installation + - Backup & restore + - Reset admin password + - Build custom binaries + - Full diagnostics + - SHA256 binary verification + - Auto mode (non-interactive) + +.PARAMETER Auto + Run installation in automatic mode (non-interactive) + +.PARAMETER SkipVerify + Skip SHA256 verification of binaries + +.EXAMPLE + .\betterdesk.ps1 + Interactive mode + +.EXAMPLE + .\betterdesk.ps1 -Auto + Automatic installation without prompts + +.EXAMPLE + .\betterdesk.ps1 -SkipVerify + Skip binary verification +#> -[CmdletBinding()] param( [switch]$Auto, - [switch]$SkipVerify, - [switch]$Help + [switch]$SkipVerify ) -#Requires -RunAsAdministrator +#=============================================================================== +# Configuration +#=============================================================================== -$ErrorActionPreference = "Stop" -$Version = "2.1.1" +$script:VERSION = "2.1.1" +$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -# Show help -if ($Help) { - Write-Host "BetterDesk Console Manager v$Version" - Write-Host "" - Write-Host "Usage: .\betterdesk.ps1 [OPTIONS]" - Write-Host "" - Write-Host "Options:" - Write-Host " -Auto Run in automatic mode (non-interactive)" - Write-Host " -SkipVerify Skip SHA256 verification of binaries" - Write-Host " -Help Show this help message" - exit 0 -} +# Auto mode flags +$script:AUTO_MODE = $Auto +$script:SKIP_VERIFY = $SkipVerify # Binary checksums (SHA256) - v2.1.1 -$Script:HBBS_WINDOWS_SHA256 = "682AA117AEEC8A6408DB4462BD31EB9DE943D5F70F5C27F3383F1DF56028A6E3" -$Script:HBBR_WINDOWS_SHA256 = "B585D077D5512035132BBCE3CE6CBC9D034E2DAE0805A799B3196C7372D82BEA" +$script:HBBS_WINDOWS_X86_64_SHA256 = "682AA117AEEC8A6408DB4462BD31EB9DE943D5F70F5C27F3383F1DF56028A6E3" +$script:HBBR_WINDOWS_X86_64_SHA256 = "B585D077D5512035132BBCE3CE6CBC9D034E2DAE0805A799B3196C7372D82BEA" + +# Default paths +$script:RUSTDESK_PATH = if ($env:RUSTDESK_PATH) { $env:RUSTDESK_PATH } else { "C:\BetterDesk" } +$script:CONSOLE_PATH = if ($env:CONSOLE_PATH) { $env:CONSOLE_PATH } else { "C:\BetterDeskConsole" } +$script:BACKUP_DIR = if ($env:BACKUP_DIR) { $env:BACKUP_DIR } else { "C:\BetterDesk-Backups" } +$script:DB_PATH = "$script:RUSTDESK_PATH\db_v2.sqlite3" # API configuration -$Script:ApiPort = if ($env:API_PORT) { $env:API_PORT } else { "21114" } - -# Default paths (can be overridden by environment variables) -$Script:RustdeskPath = if ($env:RUSTDESK_PATH) { $env:RUSTDESK_PATH } else { "" } -$Script:ConsolePath = if ($env:CONSOLE_PATH) { $env:CONSOLE_PATH } else { "" } -$Script:DbPath = "" -$Script:BackupDir = if ($env:BACKUP_DIR) { $env:BACKUP_DIR } else { "C:\rustdesk-backups" } -$Script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$script:API_PORT = if ($env:API_PORT) { $env:API_PORT } else { "21114" } # Common installation paths to search -$Script:CommonRustdeskPaths = @( - "C:\rustdesk", - "C:\Program Files\rustdesk", - "C:\Program Files (x86)\rustdesk", - "$env:ProgramData\rustdesk", - "$env:LOCALAPPDATA\rustdesk", - "$env:USERPROFILE\rustdesk" +$script:COMMON_RUSTDESK_PATHS = @( + "C:\BetterDesk", + "C:\RustDesk", + "C:\Program Files\BetterDesk", + "C:\Program Files\RustDesk", + "$env:LOCALAPPDATA\BetterDesk" ) -$Script:CommonConsolePaths = @( +$script:COMMON_CONSOLE_PATHS = @( "C:\BetterDeskConsole", "C:\Program Files\BetterDeskConsole", - "$env:ProgramData\BetterDeskConsole", - "$env:USERPROFILE\BetterDeskConsole" + "$env:LOCALAPPDATA\BetterDeskConsole" ) +# Service names +$script:HBBS_SERVICE = "BetterDeskSignal" +$script:HBBR_SERVICE = "BetterDeskRelay" +$script:CONSOLE_SERVICE = "BetterDeskConsole" + # Status variables -$Script:InstallStatus = "none" -$Script:HbbsRunning = $false -$Script:HbbrRunning = $false -$Script:ConsoleRunning = $false -$Script:BinariesOk = $false -$Script:DatabaseOk = $false +$script:INSTALL_STATUS = "none" +$script:HBBS_RUNNING = $false +$script:HBBR_RUNNING = $false +$script:CONSOLE_RUNNING = $false +$script:BINARIES_OK = $false +$script:DATABASE_OK = $false + +# Logging +$script:LOG_FILE = "$env:TEMP\betterdesk_$(Get-Date -Format 'yyyyMMdd_HHmmss').log" #=============================================================================== # Helper Functions #=============================================================================== -function Write-Header { - Clear-Host - Write-Host "" - Write-Host " โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan - Write-Host " โ•‘ โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ• โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ• โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ• โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•— โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ• โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ Console Manager v$Version (Windows) โ•‘" -ForegroundColor Cyan - Write-Host " โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan - Write-Host "" +function Write-Log { + param([string]$Message) + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + "[$timestamp] $Message" | Out-File -FilePath $script:LOG_FILE -Append -Encoding UTF8 } -function Write-Success { param($Message) Write-Host " โœ“ $Message" -ForegroundColor Green } -function Write-Error2 { param($Message) Write-Host " โœ— $Message" -ForegroundColor Red } -function Write-Warning2 { param($Message) Write-Host " ! $Message" -ForegroundColor Yellow } -function Write-Info { param($Message) Write-Host " โ„น $Message" -ForegroundColor Blue } -function Write-Step { param($Message) Write-Host " โ–ถ $Message" -ForegroundColor Magenta } +function Print-Header { + Clear-Host + Write-Host @" +โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— +โ•‘ โ•‘ +โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•‘ +โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ•‘ +โ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ• โ•‘ +โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ• โ•‘ +โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•‘ +โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ• โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•— โ•‘ +โ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ• โ•‘ +โ•‘ โ•‘ +โ•‘ Console Manager v$($script:VERSION) โ•‘ +โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +"@ -ForegroundColor Cyan +} -function Wait-ForEnter { +function Print-Success { + param([string]$Message) + Write-Host "[OK] " -ForegroundColor Green -NoNewline + Write-Host $Message + Write-Log "SUCCESS: $Message" +} + +function Print-Error { + param([string]$Message) + Write-Host "[X] " -ForegroundColor Red -NoNewline + Write-Host $Message + Write-Log "ERROR: $Message" +} + +function Print-Warning { + param([string]$Message) + Write-Host "[!] " -ForegroundColor Yellow -NoNewline + Write-Host $Message + Write-Log "WARNING: $Message" +} + +function Print-Info { + param([string]$Message) + Write-Host "[i] " -ForegroundColor Blue -NoNewline + Write-Host $Message + Write-Log "INFO: $Message" +} + +function Print-Step { + param([string]$Message) + Write-Host "[>] " -ForegroundColor Magenta -NoNewline + Write-Host $Message + Write-Log "STEP: $Message" +} + +function Press-Enter { Write-Host "" - Write-Host " Press Enter to continue..." -ForegroundColor Cyan - Read-Host + Write-Host "Press Enter to continue..." -ForegroundColor Cyan + if (-not $script:AUTO_MODE) { + $null = Read-Host + } } function Confirm-Action { param([string]$Prompt = "Continue?") - $response = Read-Host " $Prompt [y/N]" - return $response -match "^[TtYy]$" + if ($script:AUTO_MODE) { return $true } + + $response = Read-Host "$Prompt [y/N]" + return $response -match "^[YyTt]" +} + +function Get-PublicIP { + try { + $ip = (Invoke-WebRequest -Uri "https://ifconfig.me/ip" -UseBasicParsing -TimeoutSec 10).Content.Trim() + return $ip + } catch { + try { + $ip = (Invoke-WebRequest -Uri "https://icanhazip.com" -UseBasicParsing -TimeoutSec 10).Content.Trim() + return $ip + } catch { + return "127.0.0.1" + } + } +} + +function Generate-RandomPassword { + param([int]$Length = 16) + $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + $password = -join ((1..$Length) | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] }) + return $password } #=============================================================================== # Detection Functions #=============================================================================== -# Auto-detect RustDesk installation paths -function Find-Paths { +function Detect-Installation { + $script:INSTALL_STATUS = "none" + $script:HBBS_RUNNING = $false + $script:HBBR_RUNNING = $false + $script:CONSOLE_RUNNING = $false + $script:BINARIES_OK = $false + $script:DATABASE_OK = $false + + # Check paths + if (Test-Path $script:RUSTDESK_PATH) { + if ((Test-Path "$script:RUSTDESK_PATH\hbbs.exe") -or (Test-Path "$script:RUSTDESK_PATH\hbbs-v8-api.exe")) { + $script:BINARIES_OK = $true + $script:INSTALL_STATUS = "partial" + } + } + + if (Test-Path "$script:RUSTDESK_PATH\db_v2.sqlite3") { + $script:DATABASE_OK = $true + } + + if ((Test-Path $script:CONSOLE_PATH) -and (Test-Path "$script:CONSOLE_PATH\app.py")) { + if ($script:BINARIES_OK) { + $script:INSTALL_STATUS = "complete" + } + } + + # Check services + $hbbsService = Get-Service -Name $script:HBBS_SERVICE -ErrorAction SilentlyContinue + if ($hbbsService -and $hbbsService.Status -eq 'Running') { + $script:HBBS_RUNNING = $true + } + + $hbbrService = Get-Service -Name $script:HBBR_SERVICE -ErrorAction SilentlyContinue + if ($hbbrService -and $hbbrService.Status -eq 'Running') { + $script:HBBR_RUNNING = $true + } + + $consoleService = Get-Service -Name $script:CONSOLE_SERVICE -ErrorAction SilentlyContinue + if ($consoleService -and $consoleService.Status -eq 'Running') { + $script:CONSOLE_RUNNING = $true + } +} + +function Auto-DetectPaths { $found = $false - # If RUSTDESK_PATH is already set (via env var), validate it - if ($Script:RustdeskPath -ne "") { - if ((Test-Path $Script:RustdeskPath) -and - ((Test-Path "$Script:RustdeskPath\hbbs.exe") -or (Test-Path "$Script:RustdeskPath\hbbs-v8-api.exe"))) { - Write-Info "Using configured RustDesk path: $Script:RustdeskPath" + # Check configured path first + if ($script:RUSTDESK_PATH -and (Test-Path $script:RUSTDESK_PATH)) { + if ((Test-Path "$script:RUSTDESK_PATH\hbbs.exe") -or (Test-Path "$script:RUSTDESK_PATH\hbbs-v8-api.exe")) { + Print-Info "Using configured RustDesk path: $script:RUSTDESK_PATH" $found = $true - } else { - Write-Warning2 "Configured RUSTDESK_PATH ($Script:RustdeskPath) is invalid" - $Script:RustdeskPath = "" } } # Auto-detect if not found - if ($Script:RustdeskPath -eq "") { - foreach ($path in $Script:CommonRustdeskPaths) { - if ((Test-Path $path) -and - ((Test-Path "$path\hbbs.exe") -or (Test-Path "$path\hbbs-v8-api.exe"))) { - $Script:RustdeskPath = $path - Write-Success "Detected RustDesk installation: $Script:RustdeskPath" + if (-not $found) { + foreach ($path in $script:COMMON_RUSTDESK_PATHS) { + if ((Test-Path $path) -and ((Test-Path "$path\hbbs.exe") -or (Test-Path "$path\hbbs-v8-api.exe"))) { + $script:RUSTDESK_PATH = $path + Print-Success "Detected RustDesk installation: $script:RUSTDESK_PATH" $found = $true break } } } - # If still not found, use default for new installations - if ($Script:RustdeskPath -eq "") { - $Script:RustdeskPath = "C:\rustdesk" - Write-Info "No installation detected. Default path: $Script:RustdeskPath" + # Default path for new installations + if (-not $found) { + $script:RUSTDESK_PATH = "C:\BetterDesk" + Print-Info "No installation detected. Default path: $script:RUSTDESK_PATH" } # Auto-detect Console path - if ($Script:ConsolePath -ne "") { - if ((Test-Path $Script:ConsolePath) -and (Test-Path "$Script:ConsolePath\app.py")) { - Write-Info "Using configured Console path: $Script:ConsolePath" - } else { - Write-Warning2 "Configured CONSOLE_PATH ($Script:ConsolePath) is invalid" - $Script:ConsolePath = "" + $consoleFound = $false + foreach ($path in $script:COMMON_CONSOLE_PATHS) { + if ((Test-Path $path) -and (Test-Path "$path\app.py")) { + $script:CONSOLE_PATH = $path + Print-Success "Detected Console installation: $script:CONSOLE_PATH" + $consoleFound = $true + break } } - if ($Script:ConsolePath -eq "") { - foreach ($path in $Script:CommonConsolePaths) { - if ((Test-Path $path) -and (Test-Path "$path\app.py")) { - $Script:ConsolePath = $path - Write-Success "Detected Console installation: $Script:ConsolePath" - break - } - } + if (-not $consoleFound) { + $script:CONSOLE_PATH = "C:\BetterDeskConsole" } - # Default Console path if not found - if ($Script:ConsolePath -eq "") { - $Script:ConsolePath = "C:\BetterDeskConsole" - } - - # Update DB_PATH based on detected RUSTDESK_PATH - $Script:DbPath = "$Script:RustdeskPath\db_v2.sqlite3" + # Update DB_PATH + $script:DB_PATH = "$script:RUSTDESK_PATH\db_v2.sqlite3" } -# Interactive path configuration -function Set-Paths { - Clear-Host - Write-Header +function Print-Status { + Detect-Installation + Write-Host "" - Write-Host " โ•โ•โ• Path Configuration โ•โ•โ•" -ForegroundColor White + Write-Host "=== System Status ===" -ForegroundColor White Write-Host "" - Write-Host " Current RustDesk path: $Script:RustdeskPath" -ForegroundColor Cyan - Write-Host " Current Console path: $Script:ConsolePath" -ForegroundColor Cyan - Write-Host " Database path: $Script:DbPath" -ForegroundColor Cyan + Write-Host " System: " -NoNewline; Write-Host "Windows $([System.Environment]::OSVersion.Version)" -ForegroundColor Cyan + Write-Host " Architecture: " -NoNewline; Write-Host $env:PROCESSOR_ARCHITECTURE -ForegroundColor Cyan Write-Host "" - Write-Host " Options:" -ForegroundColor Yellow - Write-Host " 1. Auto-detect installation paths" - Write-Host " 2. Set RustDesk server path manually" - Write-Host " 3. Set Console path manually" - Write-Host " 4. Reset to defaults" - Write-Host " 0. Back to main menu" + Write-Host "=== Configured Paths ===" -ForegroundColor White + Write-Host "" + Write-Host " RustDesk: " -NoNewline; Write-Host $script:RUSTDESK_PATH -ForegroundColor Cyan + Write-Host " Console: " -NoNewline; Write-Host $script:CONSOLE_PATH -ForegroundColor Cyan + Write-Host " Database: " -NoNewline; Write-Host $script:DB_PATH -ForegroundColor Cyan Write-Host "" - $choice = Read-Host " Select option [0-4]" - switch ($choice) { - "1" { - $Script:RustdeskPath = "" - $Script:ConsolePath = "" - Find-Paths - Wait-ForEnter - Set-Paths - } - "2" { - Write-Host "" - $newPath = Read-Host " Enter RustDesk server path (e.g., C:\rustdesk)" - if ($newPath -ne "") { - if (Test-Path $newPath) { - $Script:RustdeskPath = $newPath - $Script:DbPath = "$Script:RustdeskPath\db_v2.sqlite3" - Write-Success "RustDesk path set to: $Script:RustdeskPath" - } else { - Write-Warning2 "Directory does not exist: $newPath" - if (Confirm-Action "Create this directory?") { - New-Item -ItemType Directory -Path $newPath -Force | Out-Null - $Script:RustdeskPath = $newPath - $Script:DbPath = "$Script:RustdeskPath\db_v2.sqlite3" - Write-Success "Created and set RustDesk path: $Script:RustdeskPath" - } - } - } - Wait-ForEnter - Set-Paths - } - "3" { - Write-Host "" - $newPath = Read-Host " Enter Console path (e.g., C:\BetterDeskConsole)" - if ($newPath -ne "") { - if (Test-Path $newPath) { - $Script:ConsolePath = $newPath - Write-Success "Console path set to: $Script:ConsolePath" - } else { - Write-Warning2 "Directory does not exist: $newPath" - if (Confirm-Action "Create this directory?") { - New-Item -ItemType Directory -Path $newPath -Force | Out-Null - $Script:ConsolePath = $newPath - Write-Success "Created and set Console path: $Script:ConsolePath" - } - } - } - Wait-ForEnter - Set-Paths - } - "4" { - $Script:RustdeskPath = "C:\rustdesk" - $Script:ConsolePath = "C:\BetterDeskConsole" - $Script:DbPath = "$Script:RustdeskPath\db_v2.sqlite3" - Write-Success "Paths reset to defaults" - Wait-ForEnter - Set-Paths - } - "0" { - return - } - default { - Write-Error2 "Invalid option" - Wait-ForEnter - Set-Paths - } - } -} - -function Find-Installation { - $Script:InstallStatus = "none" - $Script:HbbsRunning = $false - $Script:HbbrRunning = $false - $Script:ConsoleRunning = $false - $Script:BinariesOk = $false - $Script:DatabaseOk = $false + Write-Host "=== Installation Status ===" -ForegroundColor White + Write-Host "" - # Check paths - if (Test-Path $Script:RustdeskPath) { - $Script:InstallStatus = "partial" - - # Check binaries - if ((Test-Path "$Script:RustdeskPath\hbbs.exe") -or (Test-Path "$Script:RustdeskPath\hbbs-v8-api.exe")) { - $Script:BinariesOk = $true - } - - # Check database - if (Test-Path $Script:DbPath) { - $Script:DatabaseOk = $true - } + switch ($script:INSTALL_STATUS) { + "complete" { Write-Host " Status: " -NoNewline; Write-Host "[OK] Installed" -ForegroundColor Green } + "partial" { Write-Host " Status: " -NoNewline; Write-Host "[!] Partial installation" -ForegroundColor Yellow } + "none" { Write-Host " Status: " -NoNewline; Write-Host "[X] Not installed" -ForegroundColor Red } } - if ((Test-Path $Script:ConsolePath) -and (Test-Path "$Script:ConsolePath\app.py")) { - if ($Script:BinariesOk -and $Script:DatabaseOk) { - $Script:InstallStatus = "complete" - } - } - - # Check services/processes - $hbbsProc = Get-Process -Name "hbbs*" -ErrorAction SilentlyContinue - $hbbrProc = Get-Process -Name "hbbr*" -ErrorAction SilentlyContinue - - $Script:HbbsRunning = $null -ne $hbbsProc - $Script:HbbrRunning = $null -ne $hbbrProc - - # Check if console is running (Python on port 5000) - try { - $conn = Get-NetTCPConnection -LocalPort 5000 -ErrorAction SilentlyContinue - $Script:ConsoleRunning = $null -ne $conn - } catch { - $Script:ConsoleRunning = $false - } -} - -function Write-Status { - Find-Installation - - Write-Host "" - Write-Host " โ•โ•โ• System status โ•โ•โ•" -ForegroundColor White - Write-Host "" - Write-Host " System: Windows $([System.Environment]::OSVersion.Version)" -ForegroundColor Cyan - Write-Host " Architecture: $env:PROCESSOR_ARCHITECTURE" -ForegroundColor Cyan - Write-Host "" - - Write-Host " โ•โ•โ• Configured Paths โ•โ•โ•" -ForegroundColor White - Write-Host "" - Write-Host " RustDesk: $Script:RustdeskPath" -ForegroundColor Cyan - Write-Host " Console: $Script:ConsolePath" -ForegroundColor Cyan - Write-Host " Database: $Script:DbPath" -ForegroundColor Cyan - Write-Host "" - - Write-Host " โ•โ•โ• Installation status โ•โ•โ•" -ForegroundColor White - Write-Host "" - - switch ($Script:InstallStatus) { - "complete" { Write-Host " Status: โœ“ Installed" -ForegroundColor Green } - "partial" { Write-Host " Status: ! Partial installation" -ForegroundColor Yellow } - "none" { Write-Host " Status: โœ— Not installed" -ForegroundColor Red } - } - - if ($Script:BinariesOk) { - Write-Host " Binaries: โœ“ OK" -ForegroundColor Green + if ($script:BINARIES_OK) { + Write-Host " Binaries: " -NoNewline; Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host " Binaries: โœ— Not found" -ForegroundColor Red + Write-Host " Binaries: " -NoNewline; Write-Host "[X] Not found" -ForegroundColor Red } - if ($Script:DatabaseOk) { - Write-Host " Database: โœ“ OK" -ForegroundColor Green + if ($script:DATABASE_OK) { + Write-Host " Database: " -NoNewline; Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host " Database: โœ— Not found" -ForegroundColor Red + Write-Host " Database: " -NoNewline; Write-Host "[X] Not found" -ForegroundColor Red } - if (Test-Path $Script:ConsolePath) { - Write-Host " Web Console: โœ“ OK" -ForegroundColor Green + if (Test-Path $script:CONSOLE_PATH) { + Write-Host " Web Console: " -NoNewline; Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host " Web Console: โœ— Not found" -ForegroundColor Red + Write-Host " Web Console: " -NoNewline; Write-Host "[X] Not found" -ForegroundColor Red } Write-Host "" - Write-Host " โ•โ•โ• Services Status โ•โ•โ•" -ForegroundColor White + Write-Host "=== Services Status ===" -ForegroundColor White Write-Host "" - if ($Script:HbbsRunning) { - Write-Host " HBBS (Signal): โ— Active" -ForegroundColor Green + if ($script:HBBS_RUNNING) { + Write-Host " HBBS (Signal): " -NoNewline; Write-Host "* Active" -ForegroundColor Green } else { - Write-Host " HBBS (Signal): โ—‹ Inactive" -ForegroundColor Red + Write-Host " HBBS (Signal): " -NoNewline; Write-Host "o Inactive" -ForegroundColor Red } - if ($Script:HbbrRunning) { - Write-Host " HBBR (Relay): โ— Active" -ForegroundColor Green + if ($script:HBBR_RUNNING) { + Write-Host " HBBR (Relay): " -NoNewline; Write-Host "* Active" -ForegroundColor Green } else { - Write-Host " HBBR (Relay): โ—‹ Inactive" -ForegroundColor Red + Write-Host " HBBR (Relay): " -NoNewline; Write-Host "o Inactive" -ForegroundColor Red } - if ($Script:ConsoleRunning) { - Write-Host " Web Console: โ— Active" -ForegroundColor Green + if ($script:CONSOLE_RUNNING) { + Write-Host " Web Console: " -NoNewline; Write-Host "* Active" -ForegroundColor Green } else { - Write-Host " Web Console: โ—‹ Inactive" -ForegroundColor Red + Write-Host " Web Console: " -NoNewline; Write-Host "o Inactive" -ForegroundColor Red } Write-Host "" } -#=============================================================================== -# Installation Functions -#=============================================================================== - -function Install-Dependencies { - Write-Step "Checking dependencies..." - - # Check Python - $python = Get-Command python -ErrorAction SilentlyContinue - if (-not $python) { - Write-Warning2 "Python is not installed!" - Write-Info "Downloading Python..." - - $pythonUrl = "https://www.python.org/ftp/python/3.11.0/python-3.11.0-amd64.exe" - $pythonInstaller = "$env:TEMP\python_installer.exe" - - Invoke-WebRequest -Uri $pythonUrl -OutFile $pythonInstaller - Start-Process -FilePath $pythonInstaller -ArgumentList "/quiet", "InstallAllUsers=1", "PrependPath=1" -Wait - - # Refresh PATH - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - } - - Write-Success "Python installed" -} - #=============================================================================== # Binary Verification Functions #=============================================================================== -function Test-BinaryChecksum { +function Verify-BinaryChecksum { param( [string]$FilePath, [string]$ExpectedHash ) - $fileName = Split-Path $FilePath -Leaf + $fileName = Split-Path -Leaf $FilePath if (-not (Test-Path $FilePath)) { - Write-Error2 "File not found: $FilePath" + Print-Error "File not found: $FilePath" return $false } - Write-Info "Verifying $fileName..." - $actualHash = (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash + Print-Info "Verifying $fileName..." + $actualHash = (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash.ToUpper() - if ($actualHash -eq $ExpectedHash) { - Write-Success "$fileName`: SHA256 OK" + if ($actualHash -eq $ExpectedHash.ToUpper()) { + Print-Success "$fileName`: SHA256 OK" return $true } else { - Write-Error2 "$fileName`: SHA256 MISMATCH!" - Write-Error2 " Expected: $ExpectedHash" - Write-Error2 " Got: $actualHash" + Print-Error "$fileName`: SHA256 MISMATCH!" + Print-Error " Expected: $ExpectedHash" + Print-Error " Got: $actualHash" return $false } } -function Test-Binaries { - Write-Step "Verifying BetterDesk binaries..." +function Verify-Binaries { + Print-Step "Verifying BetterDesk binaries..." - $binSource = Join-Path $Script:ScriptDir "hbbs-patch-v2" + $binSource = Join-Path $script:ScriptDir "hbbs-patch-v2" $errors = 0 - if ($SkipVerify) { - Write-Warning2 "Verification skipped (-SkipVerify)" + if ($script:SKIP_VERIFY) { + Print-Warning "Verification skipped (-SkipVerify)" return $true } @@ -473,21 +411,21 @@ function Test-Binaries { $hbbrPath = Join-Path $binSource "hbbr-windows-x86_64.exe" if (Test-Path $hbbsPath) { - if (-not (Test-BinaryChecksum -FilePath $hbbsPath -ExpectedHash $Script:HBBS_WINDOWS_SHA256)) { + if (-not (Verify-BinaryChecksum -FilePath $hbbsPath -ExpectedHash $script:HBBS_WINDOWS_X86_64_SHA256)) { $errors++ } } if (Test-Path $hbbrPath) { - if (-not (Test-BinaryChecksum -FilePath $hbbrPath -ExpectedHash $Script:HBBR_WINDOWS_SHA256)) { + if (-not (Verify-BinaryChecksum -FilePath $hbbrPath -ExpectedHash $script:HBBR_WINDOWS_X86_64_SHA256)) { $errors++ } } if ($errors -gt 0) { - Write-Error2 "Binary verification failed! $errors error(s)" - Write-Warning2 "Binaries may be corrupted or outdated." - if (-not $Auto) { + Print-Error "Binary verification failed! $errors error(s)" + Print-Warning "Binaries may be corrupted or outdated." + if (-not $script:AUTO_MODE) { if (-not (Confirm-Action "Continue anyway?")) { return $false } @@ -495,7 +433,7 @@ function Test-Binaries { return $false } } else { - Write-Success "All binaries verified" + Print-Success "All binaries verified" } return $true @@ -505,414 +443,343 @@ function Test-Binaries { # Installation Functions #=============================================================================== -function Install-Binaries { - Write-Step "Installing BetterDesk binaries..." +function Install-Dependencies { + Print-Step "Checking dependencies..." - if (-not (Test-Path $Script:RustdeskPath)) { - New-Item -ItemType Directory -Path $Script:RustdeskPath -Force | Out-Null + # Check Python + $pythonCmd = Get-Command python -ErrorAction SilentlyContinue + if (-not $pythonCmd) { + Print-Warning "Python not found! Please install Python 3.8+ from python.org" + Print-Info "Download: https://www.python.org/downloads/" + if (-not $script:AUTO_MODE) { + Press-Enter + } + return $false } - # Find binaries + $pythonVersion = python --version 2>&1 + Print-Info "Python: $pythonVersion" + + # Check pip + try { + $null = python -m pip --version 2>&1 + Print-Success "pip is available" + } catch { + Print-Warning "pip not found, attempting to install..." + python -m ensurepip --upgrade + } + + # Install bcrypt for password hashing + Print-Step "Installing Python packages..." + python -m pip install --quiet --upgrade pip + python -m pip install --quiet bcrypt flask flask-wtf flask-limiter requests markupsafe + + Print-Success "Dependencies installed" + return $true +} + +function Install-Binaries { + Print-Step "Installing BetterDesk binaries..." + + # Create directory + if (-not (Test-Path $script:RUSTDESK_PATH)) { + New-Item -ItemType Directory -Path $script:RUSTDESK_PATH -Force | Out-Null + } + + # Check for pre-compiled binaries $binSource = $null - $v2Path = Join-Path $Script:ScriptDir "hbbs-patch-v2" - if (Test-Path "$v2Path\hbbs-windows-x86_64.exe") { - $binSource = $v2Path - Write-Info "Found binaries in hbbs-patch-v2/" - } - - if (-not $binSource) { - Write-Error2 "BetterDesk binaries not found!" - Write-Info "Run 'Build binaries' option or download prebuilt files." + $hbbsPatchPath = Join-Path $script:ScriptDir "hbbs-patch-v2\hbbs-windows-x86_64.exe" + if (Test-Path $hbbsPatchPath) { + $binSource = Join-Path $script:ScriptDir "hbbs-patch-v2" + Print-Info "Found binaries in hbbs-patch-v2/" + } else { + Print-Error "BetterDesk binaries not found!" + Print-Info "Expected: $hbbsPatchPath" + Print-Info "Run 'Build binaries' option or download prebuilt files." return $false } # Verify binaries before installation - if (-not (Test-Binaries)) { - Write-Error2 "Aborting installation due to verification failure" + if (-not (Verify-Binaries)) { + Print-Error "Aborting installation due to verification failure" return $false } + # Stop services if running + Stop-Service -Name $script:HBBS_SERVICE -ErrorAction SilentlyContinue -Force + Stop-Service -Name $script:HBBR_SERVICE -ErrorAction SilentlyContinue -Force + Start-Sleep -Seconds 2 + # Copy binaries - Copy-Item "$binSource\hbbs-windows-x86_64.exe" "$Script:RustdeskPath\hbbs.exe" -Force - Write-Success "Installed hbbs.exe (signal server)" + Copy-Item -Path (Join-Path $binSource "hbbs-windows-x86_64.exe") -Destination (Join-Path $script:RUSTDESK_PATH "hbbs.exe") -Force + Print-Success "Installed hbbs.exe (signal server)" - Copy-Item "$binSource\hbbr-windows-x86_64.exe" "$Script:RustdeskPath\hbbr.exe" -Force - Write-Success "Installed hbbr.exe (relay server)" + Copy-Item -Path (Join-Path $binSource "hbbr-windows-x86_64.exe") -Destination (Join-Path $script:RUSTDESK_PATH "hbbr.exe") -Force + Print-Success "Installed hbbr.exe (relay server)" - Write-Success "BetterDesk binaries v$Version installed" + Print-Success "BetterDesk binaries v$script:VERSION installed" return $true } function Install-Console { - Write-Step "Installing Web Console..." + Print-Step "Installing Web Console..." - if (-not (Test-Path $Script:ConsolePath)) { - New-Item -ItemType Directory -Path $Script:ConsolePath -Force | Out-Null + # Create directory + if (-not (Test-Path $script:CONSOLE_PATH)) { + New-Item -ItemType Directory -Path $script:CONSOLE_PATH -Force | Out-Null } # Copy web files - $webSource = Join-Path $Script:ScriptDir "web" + $webSource = Join-Path $script:ScriptDir "web" if (Test-Path $webSource) { - Copy-Item "$webSource\*" $Script:ConsolePath -Recurse -Force + Copy-Item -Path "$webSource\*" -Destination $script:CONSOLE_PATH -Recurse -Force } else { - Write-Error2 "web/ folder not found in project!" + Print-Error "web/ folder not found in project!" return $false } - # Setup Python environment - Write-Step "Configuring Python environment..." + # Setup Python virtual environment + Print-Step "Configuring Python environment..." - Push-Location $Script:ConsolePath + Push-Location $script:CONSOLE_PATH + try { + python -m venv venv + + # Install requirements + & "$script:CONSOLE_PATH\venv\Scripts\pip.exe" install --quiet --upgrade pip + & "$script:CONSOLE_PATH\venv\Scripts\pip.exe" install --quiet -r requirements.txt + + Print-Success "Web Console installed" + } catch { + Print-Error "Failed to setup Python environment: $_" + return $false + } finally { + Pop-Location + } - python -m venv venv 2>$null - & "$Script:ConsolePath\venv\Scripts\pip.exe" install --quiet --upgrade pip - & "$Script:ConsolePath\venv\Scripts\pip.exe" install --quiet -r requirements.txt - - Pop-Location - - Write-Success "Web Console installed" return $true } -function Initialize-WindowsServices { - Write-Step "Configuring Windows services..." +function Setup-Services { + Print-Step "Configuring Windows services..." - # Get server IP - $serverIp = try { - (Invoke-WebRequest -Uri "https://ifconfig.me" -UseBasicParsing -TimeoutSec 5).Content.Trim() - } catch { - "127.0.0.1" - } + $serverIP = Get-PublicIP + Print-Info "Server IP: $serverIP" + Print-Info "API Port: $script:API_PORT" - Write-Info "Server IP: $serverIp" - Write-Info "API Port: $Script:ApiPort" + # Check for NSSM (Non-Sucking Service Manager) + $nssmPath = Get-Command nssm -ErrorAction SilentlyContinue - # Create start scripts with correct API port - $hbbsStartScript = @" -@echo off -cd /d "$Script:RustdeskPath" -hbbs.exe -r $serverIp -k _ --api-port $Script:ApiPort -"@ - - $hbbrStartScript = @" -@echo off -cd /d "$Script:RustdeskPath" -hbbr.exe -k _ -"@ - - $consoleStartScript = @" -@echo off -cd /d "$Script:ConsolePath" -call venv\Scripts\activate -set RUSTDESK_PATH=$Script:RustdeskPath -set API_PORT=$Script:ApiPort -python app.py -"@ - - Set-Content -Path "$Script:RustdeskPath\start-hbbs.bat" -Value $hbbsStartScript - Set-Content -Path "$Script:RustdeskPath\start-hbbr.bat" -Value $hbbrStartScript - Set-Content -Path "$Script:ConsolePath\start-console.bat" -Value $consoleStartScript - - # Create scheduled tasks for auto-start - $taskExists = Get-ScheduledTask -TaskName "BetterDesk-HBBS" -ErrorAction SilentlyContinue - if ($taskExists) { - Unregister-ScheduledTask -TaskName "BetterDesk-HBBS" -Confirm:$false - } - - $action = New-ScheduledTaskAction -Execute "$Script:RustdeskPath\start-hbbs.bat" - $trigger = New-ScheduledTaskTrigger -AtStartup - $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount - Register-ScheduledTask -TaskName "BetterDesk-HBBS" -Action $action -Trigger $trigger -Principal $principal -Description "BetterDesk Signal Server v$Version" | Out-Null - - $taskExists = Get-ScheduledTask -TaskName "BetterDesk-HBBR" -ErrorAction SilentlyContinue - if ($taskExists) { - Unregister-ScheduledTask -TaskName "BetterDesk-HBBR" -Confirm:$false - } - - $action = New-ScheduledTaskAction -Execute "$Script:RustdeskPath\start-hbbr.bat" - Register-ScheduledTask -TaskName "BetterDesk-HBBR" -Action $action -Trigger $trigger -Principal $principal -Description "BetterDesk Relay Server v$Version" | Out-Null - - Write-Success "Windows services configured" - Write-Info "Tasks: BetterDesk-HBBS, BetterDesk-HBBR" -} - -function Invoke-Migrations { - Write-Step "Running database migrations..." - - $migrationsPath = Join-Path $Script:ScriptDir "migrations" - if (Test-Path $migrationsPath) { - Get-ChildItem "$migrationsPath\v*.py" | ForEach-Object { - Write-Info "Migration: $($_.Name)" - & python $_.FullName $Script:DbPath 2>$null + if (-not $nssmPath) { + # Try to find NSSM in the project directory + $nssmLocalPath = Join-Path $script:ScriptDir "tools\nssm.exe" + if (Test-Path $nssmLocalPath) { + $nssmPath = $nssmLocalPath + } else { + Print-Warning "NSSM not found. Services will be created as scheduled tasks." + Print-Info "For proper Windows services, install NSSM from https://nssm.cc" + + # Create scheduled tasks as fallback + Setup-ScheduledTasks -ServerIP $serverIP + return } } - Write-Success "Migrations completed" + $nssm = if ($nssmPath -is [System.Management.Automation.ApplicationInfo]) { $nssmPath.Source } else { $nssmPath } + + # Remove existing services + & $nssm stop $script:HBBS_SERVICE 2>$null + & $nssm remove $script:HBBS_SERVICE confirm 2>$null + & $nssm stop $script:HBBR_SERVICE 2>$null + & $nssm remove $script:HBBR_SERVICE confirm 2>$null + & $nssm stop $script:CONSOLE_SERVICE 2>$null + & $nssm remove $script:CONSOLE_SERVICE confirm 2>$null + + Start-Sleep -Seconds 2 + + # HBBS Service (Signal Server with HTTP API) + $hbbsExe = Join-Path $script:RUSTDESK_PATH "hbbs.exe" + $hbbsArgs = "-r $serverIP -k _ --api-port $script:API_PORT" + + & $nssm install $script:HBBS_SERVICE $hbbsExe $hbbsArgs + & $nssm set $script:HBBS_SERVICE AppDirectory $script:RUSTDESK_PATH + & $nssm set $script:HBBS_SERVICE DisplayName "BetterDesk Signal Server v$script:VERSION" + & $nssm set $script:HBBS_SERVICE Description "BetterDesk/RustDesk Signal Server with HTTP API" + & $nssm set $script:HBBS_SERVICE Start SERVICE_AUTO_START + & $nssm set $script:HBBS_SERVICE AppStdout "$script:RUSTDESK_PATH\logs\hbbs.log" + & $nssm set $script:HBBS_SERVICE AppStderr "$script:RUSTDESK_PATH\logs\hbbs_error.log" + + # HBBR Service (Relay Server) + $hbbrExe = Join-Path $script:RUSTDESK_PATH "hbbr.exe" + $hbbrArgs = "-k _" + + & $nssm install $script:HBBR_SERVICE $hbbrExe $hbbrArgs + & $nssm set $script:HBBR_SERVICE AppDirectory $script:RUSTDESK_PATH + & $nssm set $script:HBBR_SERVICE DisplayName "BetterDesk Relay Server v$script:VERSION" + & $nssm set $script:HBBR_SERVICE Description "BetterDesk/RustDesk Relay Server" + & $nssm set $script:HBBR_SERVICE Start SERVICE_AUTO_START + & $nssm set $script:HBBR_SERVICE AppStdout "$script:RUSTDESK_PATH\logs\hbbr.log" + & $nssm set $script:HBBR_SERVICE AppStderr "$script:RUSTDESK_PATH\logs\hbbr_error.log" + + # Console Service (Web Interface) + $pythonExe = Join-Path $script:CONSOLE_PATH "venv\Scripts\python.exe" + $appPy = Join-Path $script:CONSOLE_PATH "app.py" + + & $nssm install $script:CONSOLE_SERVICE $pythonExe $appPy + & $nssm set $script:CONSOLE_SERVICE AppDirectory $script:CONSOLE_PATH + & $nssm set $script:CONSOLE_SERVICE DisplayName "BetterDesk Web Console" + & $nssm set $script:CONSOLE_SERVICE Description "BetterDesk Web Management Console" + & $nssm set $script:CONSOLE_SERVICE Start SERVICE_AUTO_START + & $nssm set $script:CONSOLE_SERVICE AppEnvironmentExtra "FLASK_ENV=production" "RUSTDESK_PATH=$script:RUSTDESK_PATH" "API_PORT=$script:API_PORT" + & $nssm set $script:CONSOLE_SERVICE AppStdout "$script:CONSOLE_PATH\logs\console.log" + & $nssm set $script:CONSOLE_SERVICE AppStderr "$script:CONSOLE_PATH\logs\console_error.log" + + # Create logs directories + New-Item -ItemType Directory -Path "$script:RUSTDESK_PATH\logs" -Force | Out-Null + New-Item -ItemType Directory -Path "$script:CONSOLE_PATH\logs" -Force | Out-Null + + Print-Success "Windows services configured" + Print-Info "Services: $script:HBBS_SERVICE, $script:HBBR_SERVICE, $script:CONSOLE_SERVICE" } -function New-AdminUser { - Write-Step "Creating admin user..." +function Setup-ScheduledTasks { + param([string]$ServerIP) - # Generate password - $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - $adminPassword = -join ((1..16) | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] }) + Print-Step "Creating scheduled tasks as service alternative..." - # Create admin via Python + # Remove existing tasks + Unregister-ScheduledTask -TaskName $script:HBBS_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + Unregister-ScheduledTask -TaskName $script:HBBR_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + Unregister-ScheduledTask -TaskName $script:CONSOLE_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + + # HBBS Task + $hbbsExe = Join-Path $script:RUSTDESK_PATH "hbbs.exe" + $hbbsAction = New-ScheduledTaskAction -Execute $hbbsExe -Argument "-r $ServerIP -k _ --api-port $script:API_PORT" -WorkingDirectory $script:RUSTDESK_PATH + $hbbsTrigger = New-ScheduledTaskTrigger -AtStartup + $hbbsPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + $hbbsSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) + Register-ScheduledTask -TaskName $script:HBBS_SERVICE -Action $hbbsAction -Trigger $hbbsTrigger -Principal $hbbsPrincipal -Settings $hbbsSettings -Description "BetterDesk Signal Server" | Out-Null + + # HBBR Task + $hbbrExe = Join-Path $script:RUSTDESK_PATH "hbbr.exe" + $hbbrAction = New-ScheduledTaskAction -Execute $hbbrExe -Argument "-k _" -WorkingDirectory $script:RUSTDESK_PATH + $hbbrTrigger = New-ScheduledTaskTrigger -AtStartup + $hbbrPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + $hbbrSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) + Register-ScheduledTask -TaskName $script:HBBR_SERVICE -Action $hbbrAction -Trigger $hbbrTrigger -Principal $hbbrPrincipal -Settings $hbbrSettings -Description "BetterDesk Relay Server" | Out-Null + + # Console Task + $pythonExe = Join-Path $script:CONSOLE_PATH "venv\Scripts\python.exe" + $appPy = Join-Path $script:CONSOLE_PATH "app.py" + $consoleAction = New-ScheduledTaskAction -Execute $pythonExe -Argument $appPy -WorkingDirectory $script:CONSOLE_PATH + $consoleTrigger = New-ScheduledTaskTrigger -AtStartup + $consolePrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + $consoleSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) + Register-ScheduledTask -TaskName $script:CONSOLE_SERVICE -Action $consoleAction -Trigger $consoleTrigger -Principal $consolePrincipal -Settings $consoleSettings -Description "BetterDesk Web Console" | Out-Null + + Print-Success "Scheduled tasks created" +} + +function Run-Migrations { + Print-Step "Running database migrations..." + + # Ensure database directory exists + $dbDir = Split-Path -Parent $script:DB_PATH + if (-not (Test-Path $dbDir)) { + New-Item -ItemType Directory -Path $dbDir -Force | Out-Null + } + + # Create database schema and add missing columns $pythonScript = @" import sqlite3 -import sys -sys.path.insert(0, '$($Script:ConsolePath -replace '\\', '\\\\')\\venv\\Lib\\site-packages') -import bcrypt +import os from datetime import datetime -conn = sqlite3.connect('$($Script:DbPath -replace '\\', '\\\\')') +db_path = r'$($script:DB_PATH)' + +# Ensure db directory exists +os.makedirs(os.path.dirname(db_path), exist_ok=True) + +conn = sqlite3.connect(db_path) cursor = conn.cursor() -cursor.execute('''CREATE TABLE IF NOT EXISTS users ( - id INTEGER PRIMARY KEY, - username TEXT UNIQUE NOT NULL, - password_hash TEXT NOT NULL, - role TEXT DEFAULT 'viewer', - is_active INTEGER DEFAULT 1, - created_at TEXT, - last_login TEXT -)''') +# Create peer table if not exists +cursor.execute(''' + CREATE TABLE IF NOT EXISTS peer ( + guid BLOB PRIMARY KEY NOT NULL, + id VARCHAR(100) NOT NULL, + uuid BLOB NOT NULL, + pk BLOB NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + user BLOB, + status INTEGER DEFAULT 0, + note VARCHAR(300), + info TEXT NOT NULL, + last_online TEXT, + is_deleted INTEGER DEFAULT 0, + deleted_at TEXT, + updated_at TEXT, + previous_ids TEXT, + id_changed_at TEXT, + is_banned INTEGER DEFAULT 0 + ) +''') -cursor.execute("SELECT id FROM users WHERE username='admin'") -if cursor.fetchone(): - print("Admin already exists") -else: - password_hash = bcrypt.hashpw('$adminPassword'.encode(), bcrypt.gensalt()).decode() - cursor.execute('''INSERT INTO users (username, password_hash, role, is_active, created_at) - VALUES ('admin', ?, 'admin', 1, ?)''', (password_hash, datetime.now().isoformat())) - conn.commit() - print("Admin created") +# Create indexes +cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS index_peer_id ON peer (id)') +cursor.execute('CREATE INDEX IF NOT EXISTS index_peer_user ON peer (user)') +cursor.execute('CREATE INDEX IF NOT EXISTS index_peer_created_at ON peer (created_at)') +cursor.execute('CREATE INDEX IF NOT EXISTS index_peer_status ON peer (status)') -conn.close() -"@ - - $pythonScript | & "$Script:ConsolePath\venv\Scripts\python.exe" 2>$null - - Write-Host "" - Write-Host " โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Green - Write-Host " โ•‘ PANEL LOGIN CREDENTIALS โ•‘" -ForegroundColor Green - Write-Host " โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ" -ForegroundColor Green - Write-Host " โ•‘ Login: admin โ•‘" -ForegroundColor Green - Write-Host " โ•‘ Password: $adminPassword โ•‘" -ForegroundColor Green - Write-Host " โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Green - Write-Host "" - - # Save credentials - "admin:$adminPassword" | Set-Content "$Script:RustdeskPath\.admin_credentials" - - Write-Info "Credentials saved in: $Script:RustdeskPath\.admin_credentials" -} +# Create users table +cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username VARCHAR(50) UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + role VARCHAR(20) NOT NULL DEFAULT 'viewer', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + last_login DATETIME, + is_active INTEGER NOT NULL DEFAULT 1, + CHECK (role IN ('admin', 'operator', 'viewer')) + ) +''') -function Start-Services { - Write-Step "Starting services..." - - # Start HBBS - Start-Process -FilePath "$Script:RustdeskPath\start-hbbs.bat" -WindowStyle Hidden - Start-Sleep -Seconds 2 - - # Start HBBR - Start-Process -FilePath "$Script:RustdeskPath\start-hbbr.bat" -WindowStyle Hidden - Start-Sleep -Seconds 2 - - # Start Console - Start-Process -FilePath "$Script:ConsolePath\start-console.bat" -WindowStyle Hidden - Start-Sleep -Seconds 3 - - Find-Installation - - if ($Script:HbbsRunning -and $Script:HbbrRunning) { - Write-Success "Services started" - } else { - Write-Warning2 "Some services might not be working properly" - } -} +# Create sessions table +cursor.execute(''' + CREATE TABLE IF NOT EXISTS sessions ( + token VARCHAR(64) PRIMARY KEY, + user_id INTEGER NOT NULL, + created_at DATETIME NOT NULL, + expires_at DATETIME NOT NULL, + last_activity DATETIME NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + ) +''') -function Stop-Services { - Write-Step "Stopping services..." - - Get-Process -Name "hbbs*" -ErrorAction SilentlyContinue | Stop-Process -Force - Get-Process -Name "hbbr*" -ErrorAction SilentlyContinue | Stop-Process -Force - - # Find and stop Python console process - $pythonProcesses = Get-Process -Name "python*" -ErrorAction SilentlyContinue - foreach ($proc in $pythonProcesses) { - try { - $cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)").CommandLine - if ($cmdLine -like "*app.py*") { - $proc | Stop-Process -Force - } - } catch {} - } - - Write-Success "Services stopped" -} +# Create audit_log table +cursor.execute(''' + CREATE TABLE IF NOT EXISTS audit_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + action VARCHAR(50) NOT NULL, + device_id VARCHAR(100), + details TEXT, + ip_address VARCHAR(50), + timestamp DATETIME NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL + ) +''') -function Invoke-Install { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FRESH INSTALLATION โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White - Write-Host "" - - Find-Installation - - if ($Script:InstallStatus -eq "complete") { - Write-Warning2 "BetterDesk is already installed!" - if (-not $Auto) { - if (-not (Confirm-Action "Do you want to reinstall?")) { - return - } - } - Invoke-BackupSilent - } - - Write-Host "" - Write-Info "Starting BetterDesk Console v$Version installation..." - Write-Host "" - - Install-Dependencies - if (-not (Install-Binaries)) { - Write-Error2 "Binary installation failed" - if (-not $Auto) { Wait-ForEnter } - return $false - } - if (-not (Install-Console)) { - if (-not $Auto) { Wait-ForEnter } - return $false - } - Initialize-WindowsServices - Invoke-Migrations - New-AdminUser - Start-Services - - Write-Host "" - Write-Success "Installation completed successfully!" - Write-Host "" - - $serverIp = try { - (Invoke-WebRequest -Uri "https://ifconfig.me" -UseBasicParsing -TimeoutSec 5).Content.Trim() - } catch { "YOUR_IP" } - - $publicKey = "" - if (Test-Path "$Script:RustdeskPath\id_ed25519.pub") { - $publicKey = Get-Content "$Script:RustdeskPath\id_ed25519.pub" -First 1 - } - - Write-Host " โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan - Write-Host " โ•‘ INSTALLATION INFO โ•‘" -ForegroundColor Cyan - Write-Host " โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ" -ForegroundColor Cyan - Write-Host " โ•‘ Web Panel: http://${serverIp}:5000 โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ API Port: $Script:ApiPort โ•‘" -ForegroundColor Cyan - Write-Host " โ•‘ Server ID: $serverIp โ•‘" -ForegroundColor Cyan - if ($publicKey) { - Write-Host " โ•‘ Key: $($publicKey.Substring(0, [Math]::Min(20, $publicKey.Length)))... โ•‘" -ForegroundColor Cyan - } - Write-Host " โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan - - if (-not $Auto) { - Wait-ForEnter - } - - return $true -} - -#=============================================================================== -# Update Functions -#=============================================================================== - -function Invoke-Update { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• UPDATE โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White - Write-Host "" - - Find-Installation - - if ($Script:InstallStatus -eq "none") { - Write-Error2 "BetterDesk is not installed!" - Write-Info "Use 'FRESH INSTALLATION' option" - Wait-ForEnter - return - } - - Write-Info "Creating backup before update..." - Invoke-BackupSilent - - Stop-Services - Install-Binaries - Install-Console - Run-Migrations - Start-Services - - Write-Success "UPDATE completed!" - Wait-ForEnter -} - -#=============================================================================== -# Repair Functions -#=============================================================================== - -function Invoke-Repair { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• REPAIR INSTALLATION โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White - Write-Host "" - - Find-Installation - Write-Status - - Write-Host "" - Write-Host " What do you want to repair?" -ForegroundColor White - Write-Host "" - Write-Host " 1. ๐Ÿ”ง Repair binaries (replace with BetterDesk)" - Write-Host " 2. ๐Ÿ—ƒ๏ธ Repair database" - Write-Host " 3. โš™๏ธ Repair Windows services" - Write-Host " 4. ๐Ÿ”„ Full repair (everything)" - Write-Host " 0. โ†ฉ๏ธ Back" - Write-Host "" - - $choice = Read-Host " Select option" - - switch ($choice) { - "1" { Repair-Binaries } - "2" { Repair-Database } - "3" { Setup-WindowsServices } - "4" { - Repair-Binaries - Repair-Database - Setup-WindowsServices - Write-Success "Full repair completed!" - } - "0" { return } - } - - Wait-ForEnter -} - -function Repair-Binaries { - Write-Step "Repair binaries..." - Stop-Services - Install-Binaries - Start-Services - Write-Success "Binaries repaired" -} - -function Repair-Database { - Write-Step "Repair database..." - - if (-not (Test-Path $Script:DbPath)) { - Write-Warning2 "Database does not exist, creating new one..." - New-Item -ItemType File -Path $Script:DbPath -Force | Out-Null - } - - $pythonScript = @" -import sqlite3 - -conn = sqlite3.connect('$($Script:DbPath -replace '\\', '\\\\')') -cursor = conn.cursor() +# Create indexes for auth tables +cursor.execute('CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id)') +cursor.execute('CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at)') +cursor.execute('CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_log(user_id)') +cursor.execute('CREATE INDEX IF NOT EXISTS idx_audit_device ON audit_log(device_id)') +cursor.execute('CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_log(timestamp)') +# Add missing columns to peer table columns_to_add = [ ('status', 'INTEGER DEFAULT 0'), ('last_online', 'TEXT'), @@ -922,6 +789,7 @@ columns_to_add = [ ('note', 'TEXT'), ('previous_ids', 'TEXT'), ('id_changed_at', 'TEXT'), + ('is_banned', 'INTEGER DEFAULT 0'), ] cursor.execute("PRAGMA table_info(peer)") @@ -932,244 +800,510 @@ for col_name, col_def in columns_to_add: try: cursor.execute(f"ALTER TABLE peer ADD COLUMN {col_name} {col_def}") print(f" Added column: {col_name}") - except: + except Exception as e: pass conn.commit() conn.close() -print("Database repaired") +print("Database migrations completed") "@ - $pythonScript | python 2>$null + $pythonScript | python - Write-Success "Database repaired" + Print-Success "Migrations completed" +} + +function Create-AdminUser { + Print-Step "Creating admin user..." + + $adminPassword = Generate-RandomPassword + + $pythonScript = @" +import sqlite3 +import bcrypt +from datetime import datetime + +db_path = r'$($script:DB_PATH)' +admin_password = '$adminPassword' + +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Check if admin exists +cursor.execute("SELECT id FROM users WHERE username='admin'") +if cursor.fetchone(): + print("Admin already exists") +else: + password_hash = bcrypt.hashpw(admin_password.encode(), bcrypt.gensalt()).decode() + cursor.execute('''INSERT INTO users (username, password_hash, role, is_active, created_at) + VALUES ('admin', ?, 'admin', 1, ?)''', (password_hash, datetime.now().isoformat())) + conn.commit() + print("Admin created") + +conn.close() +"@ + + $pythonScript | python + + Write-Host "" + Write-Host "============================================================" -ForegroundColor Green + Write-Host " PANEL LOGIN CREDENTIALS " -ForegroundColor Green + Write-Host "============================================================" -ForegroundColor Green + Write-Host " Login: " -NoNewline; Write-Host "admin" -ForegroundColor White + Write-Host " Password: " -NoNewline; Write-Host $adminPassword -ForegroundColor White + Write-Host "============================================================" -ForegroundColor Green + Write-Host "" + + # Save credentials + $credentialsFile = Join-Path $script:RUSTDESK_PATH ".admin_credentials" + "admin:$adminPassword" | Out-File -FilePath $credentialsFile -Encoding UTF8 + + Print-Info "Credentials saved in: $credentialsFile" + + return $adminPassword +} + +function Start-Services { + Print-Step "Starting services..." + + # Try to start as Windows services first + $serviceExists = Get-Service -Name $script:HBBS_SERVICE -ErrorAction SilentlyContinue + + if ($serviceExists) { + Start-Service -Name $script:HBBS_SERVICE -ErrorAction SilentlyContinue + Start-Service -Name $script:HBBR_SERVICE -ErrorAction SilentlyContinue + Start-Service -Name $script:CONSOLE_SERVICE -ErrorAction SilentlyContinue + } else { + # Start scheduled tasks + Start-ScheduledTask -TaskName $script:HBBS_SERVICE -ErrorAction SilentlyContinue + Start-ScheduledTask -TaskName $script:HBBR_SERVICE -ErrorAction SilentlyContinue + Start-ScheduledTask -TaskName $script:CONSOLE_SERVICE -ErrorAction SilentlyContinue + } + + Start-Sleep -Seconds 3 + + Detect-Installation + + if ($script:HBBS_RUNNING -and $script:HBBR_RUNNING) { + Print-Success "All services started" + } else { + Print-Warning "Some services may not be working properly" + Print-Info "Check logs in: $script:RUSTDESK_PATH\logs\" + } +} + +function Stop-AllServices { + Print-Step "Stopping services..." + + # Stop Windows services + Stop-Service -Name $script:HBBS_SERVICE -ErrorAction SilentlyContinue -Force + Stop-Service -Name $script:HBBR_SERVICE -ErrorAction SilentlyContinue -Force + Stop-Service -Name $script:CONSOLE_SERVICE -ErrorAction SilentlyContinue -Force + + # Stop scheduled tasks + Stop-ScheduledTask -TaskName $script:HBBS_SERVICE -ErrorAction SilentlyContinue + Stop-ScheduledTask -TaskName $script:HBBR_SERVICE -ErrorAction SilentlyContinue + Stop-ScheduledTask -TaskName $script:CONSOLE_SERVICE -ErrorAction SilentlyContinue + + # Kill processes directly + Get-Process -Name "hbbs" -ErrorAction SilentlyContinue | Stop-Process -Force + Get-Process -Name "hbbr" -ErrorAction SilentlyContinue | Stop-Process -Force + + Start-Sleep -Seconds 2 +} + +#=============================================================================== +# Main Installation Function +#=============================================================================== + +function Do-Install { + Print-Header + Write-Host "========== FRESH INSTALLATION ==========" -ForegroundColor White + Write-Host "" + + Detect-Installation + + if ($script:INSTALL_STATUS -eq "complete") { + Print-Warning "BetterDesk is already installed!" + if (-not $script:AUTO_MODE) { + if (-not (Confirm-Action "Do you want to reinstall?")) { + return + } + } + Do-BackupSilent + } + + Write-Host "" + Print-Info "Starting BetterDesk Console v$script:VERSION installation..." + Write-Host "" + + if (-not (Install-Dependencies)) { return } + if (-not (Install-Binaries)) { Print-Error "Binary installation failed"; return } + if (-not (Install-Console)) { Print-Error "Console installation failed"; return } + Setup-Services + Run-Migrations + $adminPassword = Create-AdminUser + Start-Services + + Write-Host "" + Print-Success "Installation completed successfully!" + Write-Host "" + + $serverIP = Get-PublicIP + $publicKey = "" + $pubKeyPath = Join-Path $script:RUSTDESK_PATH "id_ed25519.pub" + if (Test-Path $pubKeyPath) { + $publicKey = (Get-Content $pubKeyPath -Raw).Trim() + } + + Write-Host "============================================================" -ForegroundColor Cyan + Write-Host " INSTALLATION INFO " -ForegroundColor Cyan + Write-Host "============================================================" -ForegroundColor Cyan + Write-Host " Panel Web: " -NoNewline; Write-Host "http://${serverIP}:5000" -ForegroundColor White + Write-Host " API Port: " -NoNewline; Write-Host $script:API_PORT -ForegroundColor White + Write-Host " Server ID: " -NoNewline; Write-Host $serverIP -ForegroundColor White + if ($publicKey) { + Write-Host " Key: " -NoNewline; Write-Host "$($publicKey.Substring(0, [Math]::Min(20, $publicKey.Length)))..." -ForegroundColor White + } + Write-Host "============================================================" -ForegroundColor Cyan + + if (-not $script:AUTO_MODE) { + Press-Enter + } +} + +#=============================================================================== +# Update Functions +#=============================================================================== + +function Do-Update { + Print-Header + Write-Host "========== UPDATE ==========" -ForegroundColor White + Write-Host "" + + Detect-Installation + + if ($script:INSTALL_STATUS -eq "none") { + Print-Error "BetterDesk is not installed!" + Print-Info "Use 'FRESH INSTALLATION' option" + Press-Enter + return + } + + Print-Info "Creating backup before update..." + Do-BackupSilent + + Stop-AllServices + + if (-not (Install-Binaries)) { Print-Error "Binary update failed"; return } + if (-not (Install-Console)) { Print-Error "Console update failed"; return } + Run-Migrations + + Start-Services + + Print-Success "Update completed!" + Press-Enter +} + +#=============================================================================== +# Repair Functions +#=============================================================================== + +function Do-Repair { + Print-Header + Write-Host "========== REPAIR INSTALLATION ==========" -ForegroundColor White + Write-Host "" + + Detect-Installation + Print-Status + + Write-Host "" + Write-Host "What do you want to repair?" -ForegroundColor White + Write-Host "" + Write-Host " 1. Repair binaries (replace with BetterDesk)" + Write-Host " 2. Repair database (add missing columns)" + Write-Host " 3. Repair Windows services" + Write-Host " 4. Full repair (all of the above)" + Write-Host " 0. Back" + Write-Host "" + + $choice = Read-Host "Select option" + + switch ($choice) { + "1" { Repair-Binaries } + "2" { Repair-Database } + "3" { Repair-Services } + "4" { + Repair-Binaries + Repair-Database + Repair-Services + Print-Success "Full repair completed!" + } + "0" { return } + } + + Press-Enter +} + +function Repair-Binaries { + Print-Step "Repairing binaries..." + + Stop-AllServices + Install-Binaries | Out-Null + Start-Services + + Print-Success "Binaries repaired" +} + +function Repair-Database { + Print-Step "Repairing database..." + + Run-Migrations + + Print-Success "Database repaired" +} + +function Repair-Services { + Print-Step "Repairing Windows services..." + + Setup-Services + Start-Services + + Print-Success "Services repaired" } #=============================================================================== # Validation Functions #=============================================================================== -function Invoke-Validate { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• INSTALLATION VALIDATION โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White +function Do-Validate { + Print-Header + Write-Host "========== INSTALLATION VALIDATION ==========" -ForegroundColor White Write-Host "" $errors = 0 $warnings = 0 - Find-Installation + Detect-Installation - Write-Host " Checking components..." -ForegroundColor White + Write-Host "Checking components..." -ForegroundColor White Write-Host "" # Check directories - Write-Host -NoNewline " RustDesk directory ($Script:RustdeskPath): " - if (Test-Path $Script:RustdeskPath) { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " RustDesk directory ($script:RUSTDESK_PATH): " -NoNewline + if (Test-Path $script:RUSTDESK_PATH) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "โœ— Not found" -ForegroundColor Red + Write-Host "[X] Not found" -ForegroundColor Red $errors++ } - Write-Host -NoNewline " Console directory ($Script:ConsolePath): " - if (Test-Path $Script:ConsolePath) { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " Console directory ($script:CONSOLE_PATH): " -NoNewline + if (Test-Path $script:CONSOLE_PATH) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "โœ— Not found" -ForegroundColor Red + Write-Host "[X] Not found" -ForegroundColor Red $errors++ } # Check binaries - Write-Host -NoNewline " HBBS binary: " - if (Test-Path "$Script:RustdeskPath\hbbs.exe") { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " HBBS binary: " -NoNewline + if (Test-Path (Join-Path $script:RUSTDESK_PATH "hbbs.exe")) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "โœ— Not found" -ForegroundColor Red + Write-Host "[X] Not found" -ForegroundColor Red $errors++ } - Write-Host -NoNewline " HBBR binary: " - if (Test-Path "$Script:RustdeskPath\hbbr.exe") { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " HBBR binary: " -NoNewline + if (Test-Path (Join-Path $script:RUSTDESK_PATH "hbbr.exe")) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "โœ— Not found" -ForegroundColor Red + Write-Host "[X] Not found" -ForegroundColor Red $errors++ } # Check database - Write-Host -NoNewline " Database: " - if (Test-Path $Script:DbPath) { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " Database: " -NoNewline + if (Test-Path $script:DB_PATH) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "โœ— Not found" -ForegroundColor Red + Write-Host "[X] Not found" -ForegroundColor Red $errors++ } # Check keys - Write-Host -NoNewline " Public key: " - if (Test-Path "$Script:RustdeskPath\id_ed25519.pub") { - Write-Host "โœ“" -ForegroundColor Green + Write-Host " Public key: " -NoNewline + $pubKeyPath = Join-Path $script:RUSTDESK_PATH "id_ed25519.pub" + if (Test-Path $pubKeyPath) { + Write-Host "[OK]" -ForegroundColor Green } else { - Write-Host "! Will be generated on first start" -ForegroundColor Yellow + Write-Host "[!] Will be generated on first start" -ForegroundColor Yellow $warnings++ } + # Check services Write-Host "" - Write-Host " Checking processes..." -ForegroundColor White + Write-Host "Checking services..." -ForegroundColor White Write-Host "" - Write-Host -NoNewline " HBBS (Signal): " - if ($Script:HbbsRunning) { - Write-Host "โ— Active" -ForegroundColor Green - } else { - Write-Host "โ—‹ Inactive" -ForegroundColor Red - $errors++ - } - - Write-Host -NoNewline " HBBR (Relay): " - if ($Script:HbbrRunning) { - Write-Host "โ— Active" -ForegroundColor Green - } else { - Write-Host "โ—‹ Inactive" -ForegroundColor Red - $errors++ - } - - Write-Host -NoNewline " Web Console: " - if ($Script:ConsoleRunning) { - Write-Host "โ— Active" -ForegroundColor Green - } else { - Write-Host "โ—‹ Inactive" -ForegroundColor Red - $errors++ + $services = @($script:HBBS_SERVICE, $script:HBBR_SERVICE, $script:CONSOLE_SERVICE) + foreach ($service in $services) { + Write-Host " ${service}: " -NoNewline + $svc = Get-Service -Name $service -ErrorAction SilentlyContinue + if ($svc) { + if ($svc.Status -eq 'Running') { + Write-Host "[OK] Running" -ForegroundColor Green + } else { + Write-Host "[!] Not running ($($svc.Status))" -ForegroundColor Yellow + $warnings++ + } + } else { + $task = Get-ScheduledTask -TaskName $service -ErrorAction SilentlyContinue + if ($task) { + if ($task.State -eq 'Running') { + Write-Host "[OK] Running (task)" -ForegroundColor Green + } else { + Write-Host "[!] Task exists but not running" -ForegroundColor Yellow + $warnings++ + } + } else { + Write-Host "[X] Not found" -ForegroundColor Red + $errors++ + } + } } # Check ports Write-Host "" - Write-Host " Checking ports..." -ForegroundColor White + Write-Host "Checking ports..." -ForegroundColor White Write-Host "" - foreach ($port in @(21114, 21115, 21116, 21117, 5000)) { - Write-Host -NoNewline " Port ${port}: " - $conn = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue - if ($conn) { - Write-Host "โ— Listening" -ForegroundColor Green + $ports = @(21114, 21115, 21116, 21117, 5000) + foreach ($port in $ports) { + Write-Host " Port ${port}: " -NoNewline + $connection = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue + if ($connection) { + Write-Host "[OK] Listening" -ForegroundColor Green } else { - Write-Host "โ—‹ Free" -ForegroundColor Yellow + Write-Host "[!] Not listening" -ForegroundColor Yellow $warnings++ } } # Summary Write-Host "" - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor White + Write-Host "=======================================" -ForegroundColor White if ($errors -eq 0 -and $warnings -eq 0) { - Write-Host " โœ“ Installation correct - no problems found" -ForegroundColor Green + Write-Host "[OK] Installation correct - no problems found" -ForegroundColor Green } elseif ($errors -eq 0) { - Write-Host " ! Found $warnings warnings" -ForegroundColor Yellow + Write-Host "[!] Found $warnings warning(s)" -ForegroundColor Yellow } else { - Write-Host " โœ— Found $errors errors and $warnings warnings" -ForegroundColor Red - Write-Host "" - Write-Host " Use 'REPAIR INSTALLATION' option to fix problems" -ForegroundColor Cyan + Write-Host "[X] Found $errors error(s) and $warnings warning(s)" -ForegroundColor Red + Write-Host "Use 'REPAIR INSTALLATION' option to fix problems" -ForegroundColor Cyan } - Wait-ForEnter + Press-Enter } #=============================================================================== # Backup Functions #=============================================================================== -function Invoke-Backup { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• BACKUP โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White +function Do-Backup { + Print-Header + Write-Host "========== BACKUP ==========" -ForegroundColor White Write-Host "" - Invoke-BackupSilent + Do-BackupSilent - Write-Success "Backup completed!" - Wait-ForEnter + Print-Success "Backup completed!" + Press-Enter } -function Invoke-BackupSilent { +function Do-BackupSilent { $backupName = "betterdesk_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" - $backupPath = Join-Path $Script:BackupDir $backupName + $backupPath = Join-Path $script:BACKUP_DIR $backupName - if (-not (Test-Path $Script:BackupDir)) { - New-Item -ItemType Directory -Path $Script:BackupDir -Force | Out-Null + if (-not (Test-Path $script:BACKUP_DIR)) { + New-Item -ItemType Directory -Path $script:BACKUP_DIR -Force | Out-Null } New-Item -ItemType Directory -Path $backupPath -Force | Out-Null - Write-Step "Creating backup: $backupName" + Print-Step "Creating backup: $backupName" # Backup database - if (Test-Path $Script:DbPath) { - Copy-Item $Script:DbPath $backupPath - Write-Info " - Database" + if (Test-Path $script:DB_PATH) { + Copy-Item -Path $script:DB_PATH -Destination $backupPath + Print-Info " - Database" } # Backup keys - if (Test-Path "$Script:RustdeskPath\id_ed25519") { - Copy-Item "$Script:RustdeskPath\id_ed25519*" $backupPath - Write-Info " - Keys" + $keyPath = Join-Path $script:RUSTDESK_PATH "id_ed25519" + if (Test-Path $keyPath) { + Copy-Item -Path $keyPath -Destination $backupPath + Copy-Item -Path "$keyPath.pub" -Destination $backupPath -ErrorAction SilentlyContinue + Print-Info " - Keys" } # Backup API key - if (Test-Path "$Script:RustdeskPath\.api_key") { - Copy-Item "$Script:RustdeskPath\.api_key" $backupPath - Write-Info " - API key" + $apiKeyPath = Join-Path $script:RUSTDESK_PATH ".api_key" + if (Test-Path $apiKeyPath) { + Copy-Item -Path $apiKeyPath -Destination $backupPath + Print-Info " - API key" } # Backup credentials - if (Test-Path "$Script:RustdeskPath\.admin_credentials") { - Copy-Item "$Script:RustdeskPath\.admin_credentials" $backupPath - Write-Info " - Login credentials" + $credPath = Join-Path $script:RUSTDESK_PATH ".admin_credentials" + if (Test-Path $credPath) { + Copy-Item -Path $credPath -Destination $backupPath + Print-Info " - Login credentials" } - # Create archive - Compress-Archive -Path $backupPath -DestinationPath "$Script:BackupDir\$backupName.zip" -Force - Remove-Item $backupPath -Recurse -Force + # Create zip archive + $zipPath = "$backupPath.zip" + Compress-Archive -Path $backupPath -DestinationPath $zipPath -Force + Remove-Item -Path $backupPath -Recurse -Force - Write-Success "Backup saved: $Script:BackupDir\$backupName.zip" + Print-Success "Backup saved: $zipPath" } #=============================================================================== -# Password Reset Functions +# Password Reset Function #=============================================================================== -function Reset-AdminPassword { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ADMIN PASSWORD RESET โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White +function Do-ResetPassword { + Print-Header + Write-Host "========== ADMIN PASSWORD RESET ==========" -ForegroundColor White Write-Host "" - if (-not (Test-Path $Script:DbPath)) { - Write-Error2 "Database does not exist!" - Wait-ForEnter + if (-not (Test-Path $script:DB_PATH)) { + Print-Error "Database not found: $script:DB_PATH" + Print-Info "Run installation first" + Press-Enter return } - Write-Host " Select option:" + Write-Host "Select option:" Write-Host "" - Write-Host " 1. Generate new random password" - Write-Host " 2. Set custom password" - Write-Host " 0. Back" + Write-Host " 1. Generate new random password" + Write-Host " 2. Set custom password" + Write-Host " 0. Back" Write-Host "" - $choice = Read-Host " Choice" + $choice = Read-Host "Choice" - $newPassword = "" + $newPassword = $null switch ($choice) { - "1" { - $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - $newPassword = -join ((1..16) | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] }) - } - "2" { - Write-Host "" - $newPassword = Read-Host " Enter new password (min. 8 characters)" + "1" { $newPassword = Generate-RandomPassword } + "2" { + $newPassword = Read-Host "Enter new password (min 8 chars)" if ($newPassword.Length -lt 8) { - Write-Error2 "Password must be at least 8 characters!" - Wait-ForEnter + Print-Error "Password too short!" + Press-Enter return } } @@ -1177,16 +1311,19 @@ function Reset-AdminPassword { default { return } } + if (-not $newPassword) { return } + $pythonScript = @" import sqlite3 -import sys -sys.path.insert(0, '$($Script:ConsolePath -replace '\\', '\\\\')\\venv\\Lib\\site-packages') import bcrypt -conn = sqlite3.connect('$($Script:DbPath -replace '\\', '\\\\')') +db_path = r'$($script:DB_PATH)' +new_password = '$newPassword' + +conn = sqlite3.connect(db_path) cursor = conn.cursor() -password_hash = bcrypt.hashpw('$newPassword'.encode(), bcrypt.gensalt()).decode() +password_hash = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode() cursor.execute("UPDATE users SET password_hash = ? WHERE username = 'admin'", (password_hash,)) if cursor.rowcount == 0: @@ -1195,167 +1332,128 @@ if cursor.rowcount == 0: conn.commit() conn.close() +print("Password updated") "@ - $pythonScript | & "$Script:ConsolePath\venv\Scripts\python.exe" 2>$null + $pythonScript | python Write-Host "" - Write-Host " โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Green - Write-Host " โ•‘ NEW LOGIN CREDENTIALS โ•‘" -ForegroundColor Green - Write-Host " โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ" -ForegroundColor Green - Write-Host " โ•‘ Login: admin โ•‘" -ForegroundColor Green - Write-Host " โ•‘ Password: $newPassword โ•‘" -ForegroundColor Green - Write-Host " โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Green + Write-Host "============================================================" -ForegroundColor Green + Write-Host " NEW LOGIN CREDENTIALS " -ForegroundColor Green + Write-Host "============================================================" -ForegroundColor Green + Write-Host " Login: " -NoNewline; Write-Host "admin" -ForegroundColor White + Write-Host " Password: " -NoNewline; Write-Host $newPassword -ForegroundColor White + Write-Host "============================================================" -ForegroundColor Green - "admin:$newPassword" | Set-Content "$Script:RustdeskPath\.admin_credentials" + # Save credentials + $credentialsFile = Join-Path $script:RUSTDESK_PATH ".admin_credentials" + "admin:$newPassword" | Out-File -FilePath $credentialsFile -Encoding UTF8 - Wait-ForEnter + Press-Enter } #=============================================================================== -# Build Functions +# Diagnostics Function #=============================================================================== -function Invoke-Build { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• Build binaries โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White +function Do-Diagnostics { + Print-Header + Write-Host "========== DIAGNOSTICS ==========" -ForegroundColor White Write-Host "" - # Check Rust - $cargo = Get-Command cargo -ErrorAction SilentlyContinue - if (-not $cargo) { - Write-Warning2 "Rust is not installed!" - Write-Host "" - if (Confirm-Action "Do you want to install Rust?") { - Write-Info "Downloading Rust..." - $rustupUrl = "https://win.rustup.rs/x86_64" - $rustupInstaller = "$env:TEMP\rustup-init.exe" - Invoke-WebRequest -Uri $rustupUrl -OutFile $rustupInstaller - Start-Process -FilePath $rustupInstaller -ArgumentList "-y" -Wait - - # Refresh PATH - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - } else { - Wait-ForEnter - return - } - } + Detect-Installation + Print-Status - Write-Info "Rust: $(cargo --version)" + Write-Host "" + Write-Host "=== Process Information ===" -ForegroundColor White Write-Host "" - $buildDir = "$env:TEMP\betterdesk_build_$(Get-Random)" - New-Item -ItemType Directory -Path $buildDir -Force | Out-Null - - Push-Location $buildDir - - Write-Step "Downloading RustDesk Server sources..." - git clone --depth 1 --branch 1.1.14 https://github.com/rustdesk/rustdesk-server.git - Set-Location rustdesk-server - git submodule update --init --recursive - - Write-Step "Applying BetterDesk modifications..." - - $srcPath = Join-Path $Script:ScriptDir "hbbs-patch-v2\src" - if (Test-Path $srcPath) { - Copy-Item "$srcPath\main.rs" "src\" -Force -ErrorAction SilentlyContinue - Copy-Item "$srcPath\http_api.rs" "src\" -Force -ErrorAction SilentlyContinue - Copy-Item "$srcPath\database.rs" "src\" -Force -ErrorAction SilentlyContinue - Copy-Item "$srcPath\peer.rs" "src\" -Force -ErrorAction SilentlyContinue - Copy-Item "$srcPath\rendezvous_server.rs" "src\" -Force -ErrorAction SilentlyContinue + $hbbsProc = Get-Process -Name "hbbs" -ErrorAction SilentlyContinue + if ($hbbsProc) { + Write-Host " HBBS: PID $($hbbsProc.Id), Memory $('{0:N0}' -f ($hbbsProc.WorkingSet64/1MB)) MB" -ForegroundColor Green } else { - Write-Error2 "Modified sources not found in hbbs-patch-v2\src\" - Pop-Location - Remove-Item $buildDir -Recurse -Force - Wait-ForEnter - return + Write-Host " HBBS: Not running" -ForegroundColor Red } - Write-Step "Compiling (may take several minutes)..." - cargo build --release - - Write-Step "Copying binaries..." - - $destPath = Join-Path $Script:ScriptDir "hbbs-patch-v2" - Copy-Item "target\release\hbbs.exe" "$destPath\hbbs-windows-x86_64.exe" -Force - Copy-Item "target\release\hbbr.exe" "$destPath\hbbr-windows-x86_64.exe" -Force - - Pop-Location - Remove-Item $buildDir -Recurse -Force - - Write-Success "Compilation completed!" - Write-Info "Binaries saved in: $destPath" - - Write-Host "" - if (Confirm-Action "Do you want to install the new binaries?") { - Stop-Services - Install-Binaries - Start-Services + $hbbrProc = Get-Process -Name "hbbr" -ErrorAction SilentlyContinue + if ($hbbrProc) { + Write-Host " HBBR: PID $($hbbrProc.Id), Memory $('{0:N0}' -f ($hbbrProc.WorkingSet64/1MB)) MB" -ForegroundColor Green + } else { + Write-Host " HBBR: Not running" -ForegroundColor Red } - Wait-ForEnter -} - -#=============================================================================== -# Diagnostics Functions -#=============================================================================== - -function Invoke-Diagnostics { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• DIAGNOSTICS โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White + Write-Host "" + Write-Host "=== Database Statistics ===" -ForegroundColor White Write-Host "" - Write-Status - - Write-Host "" - Write-Host " โ•โ•โ• Database statistics โ•โ•โ•" -ForegroundColor White - Write-Host "" - - if (Test-Path $Script:DbPath) { + if (Test-Path $script:DB_PATH) { + $fileInfo = Get-Item $script:DB_PATH + Write-Host " Size: $('{0:N2}' -f ($fileInfo.Length/1KB)) KB" + Write-Host " Modified: $($fileInfo.LastWriteTime)" + + # Get database counts $pythonScript = @" import sqlite3 -conn = sqlite3.connect('$($Script:DbPath -replace '\\', '\\\\')') +db_path = r'$($script:DB_PATH)' +conn = sqlite3.connect(db_path) cursor = conn.cursor() + try: cursor.execute("SELECT COUNT(*) FROM peer WHERE is_deleted = 0") devices = cursor.fetchone()[0] + print(f" Devices: {devices}") +except: + print(" Devices: Unable to query") + +try: cursor.execute("SELECT COUNT(*) FROM peer WHERE status = 1 AND is_deleted = 0") online = cursor.fetchone()[0] + print(f" Online: {online}") +except: + pass + +try: cursor.execute("SELECT COUNT(*) FROM users") users = cursor.fetchone()[0] - print(f" Devices: {devices}") - print(f" Online: {online}") - print(f" Users: {users}") + print(f" Users: {users}") except: - print(" Database read error") + pass + conn.close() "@ - $pythonScript | python 2>$null + $pythonScript | python } else { - Write-Host " Database does not exist" + Write-Host " Database does not exist" } Write-Host "" - Write-Host " โ•โ•โ• Network connections โ•โ•โ•" -ForegroundColor White + Write-Host "=== Network Connections ===" -ForegroundColor White Write-Host "" - Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | - Where-Object { $_.LocalPort -in @(21114, 21115, 21116, 21117, 5000) } | - Format-Table LocalPort, State, OwningProcess -AutoSize + $portsToCheck = @(21114, 21115, 21116, 21117, 5000) + foreach ($port in $portsToCheck) { + $conn = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue + if ($conn) { + Write-Host " Port ${port}: Listening (PID: $($conn[0].OwningProcess))" -ForegroundColor Green + } + } - Wait-ForEnter + Write-Host "" + Write-Host "Diagnostics log saved: $script:LOG_FILE" -ForegroundColor Cyan + + Press-Enter } #=============================================================================== -# Uninstall Functions +# Uninstall Function #=============================================================================== -function Invoke-Uninstall { - Write-Header - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• UNINSTALL โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor Red +function Do-Uninstall { + Print-Header + Write-Host "========== UNINSTALL ==========" -ForegroundColor Red Write-Host "" - Write-Warning2 "This operation will remove BetterDesk Console!" + Print-Warning "This operation will remove BetterDesk Console!" Write-Host "" if (-not (Confirm-Action "Are you sure you want to continue?")) { @@ -1363,27 +1461,204 @@ function Invoke-Uninstall { } if (Confirm-Action "Create backup before uninstall?") { - Invoke-BackupSilent + Do-BackupSilent } - Stop-Services + Print-Step "Stopping services..." + Stop-AllServices - Write-Step "Removing scheduled tasks..." - Unregister-ScheduledTask -TaskName "BetterDesk-HBBS" -Confirm:$false -ErrorAction SilentlyContinue - Unregister-ScheduledTask -TaskName "BetterDesk-HBBR" -Confirm:$false -ErrorAction SilentlyContinue + Print-Step "Removing services..." - if (Confirm-Action "Remove installation files ($Script:RustdeskPath)?") { - Remove-Item $Script:RustdeskPath -Recurse -Force -ErrorAction SilentlyContinue - Write-Info "Removed: $Script:RustdeskPath" + # Remove Windows services (NSSM) + $nssmPath = Get-Command nssm -ErrorAction SilentlyContinue + if ($nssmPath) { + $nssm = if ($nssmPath -is [System.Management.Automation.ApplicationInfo]) { $nssmPath.Source } else { $nssmPath } + & $nssm remove $script:HBBS_SERVICE confirm 2>$null + & $nssm remove $script:HBBR_SERVICE confirm 2>$null + & $nssm remove $script:CONSOLE_SERVICE confirm 2>$null } - if (Confirm-Action "Remove Web Console ($Script:ConsolePath)?") { - Remove-Item $Script:ConsolePath -Recurse -Force -ErrorAction SilentlyContinue - Write-Info "Removed: $Script:ConsolePath" + # Remove scheduled tasks + Unregister-ScheduledTask -TaskName $script:HBBS_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + Unregister-ScheduledTask -TaskName $script:HBBR_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + Unregister-ScheduledTask -TaskName $script:CONSOLE_SERVICE -Confirm:$false -ErrorAction SilentlyContinue + + if (Confirm-Action "Remove installation files ($script:RUSTDESK_PATH)?") { + Remove-Item -Path $script:RUSTDESK_PATH -Recurse -Force -ErrorAction SilentlyContinue + Print-Info "Removed: $script:RUSTDESK_PATH" } - Write-Success "BetterDesk has been uninstalled" - Wait-ForEnter + if (Confirm-Action "Remove Web Console ($script:CONSOLE_PATH)?") { + Remove-Item -Path $script:CONSOLE_PATH -Recurse -Force -ErrorAction SilentlyContinue + Print-Info "Removed: $script:CONSOLE_PATH" + } + + Print-Success "BetterDesk has been uninstalled" + Press-Enter +} + +#=============================================================================== +# Path Configuration +#=============================================================================== + +function Configure-Paths { + Print-Header + Write-Host "" + Write-Host "=== Path Configuration ===" -ForegroundColor White + Write-Host "" + Write-Host " Current RustDesk path: " -NoNewline; Write-Host $script:RUSTDESK_PATH -ForegroundColor Cyan + Write-Host " Current Console path: " -NoNewline; Write-Host $script:CONSOLE_PATH -ForegroundColor Cyan + Write-Host " Database path: " -NoNewline; Write-Host $script:DB_PATH -ForegroundColor Cyan + Write-Host "" + + Write-Host "Options:" -ForegroundColor Yellow + Write-Host " 1. Auto-detect installation paths" + Write-Host " 2. Set RustDesk server path manually" + Write-Host " 3. Set Console path manually" + Write-Host " 4. Reset to defaults" + Write-Host " 0. Back to main menu" + Write-Host "" + + $choice = Read-Host "Select option [0-4]" + + switch ($choice) { + "1" { + $script:RUSTDESK_PATH = "" + $script:CONSOLE_PATH = "" + Auto-DetectPaths + Press-Enter + Configure-Paths + } + "2" { + Write-Host "" + $newPath = Read-Host "Enter RustDesk server path (e.g., C:\BetterDesk)" + if ($newPath) { + if (Test-Path $newPath) { + $script:RUSTDESK_PATH = $newPath + $script:DB_PATH = "$script:RUSTDESK_PATH\db_v2.sqlite3" + Print-Success "RustDesk path set to: $script:RUSTDESK_PATH" + } else { + Print-Warning "Directory does not exist: $newPath" + if (Confirm-Action "Create this directory?") { + New-Item -ItemType Directory -Path $newPath -Force | Out-Null + $script:RUSTDESK_PATH = $newPath + $script:DB_PATH = "$script:RUSTDESK_PATH\db_v2.sqlite3" + Print-Success "Created and set RustDesk path: $script:RUSTDESK_PATH" + } + } + } + Press-Enter + Configure-Paths + } + "3" { + Write-Host "" + $newPath = Read-Host "Enter Console path (e.g., C:\BetterDeskConsole)" + if ($newPath) { + if (Test-Path $newPath) { + $script:CONSOLE_PATH = $newPath + Print-Success "Console path set to: $script:CONSOLE_PATH" + } else { + Print-Warning "Directory does not exist: $newPath" + if (Confirm-Action "Create this directory?") { + New-Item -ItemType Directory -Path $newPath -Force | Out-Null + $script:CONSOLE_PATH = $newPath + Print-Success "Created and set Console path: $script:CONSOLE_PATH" + } + } + } + Press-Enter + Configure-Paths + } + "4" { + $script:RUSTDESK_PATH = "C:\BetterDesk" + $script:CONSOLE_PATH = "C:\BetterDeskConsole" + $script:DB_PATH = "$script:RUSTDESK_PATH\db_v2.sqlite3" + Print-Success "Paths reset to defaults" + Press-Enter + Configure-Paths + } + "0" { return } + default { + Print-Error "Invalid option" + Start-Sleep -Seconds 1 + Configure-Paths + } + } +} + +#=============================================================================== +# Build Functions +#=============================================================================== + +function Do-Build { + Print-Header + Write-Host "========== BUILD BINARIES ==========" -ForegroundColor White + Write-Host "" + + # Check Rust + $cargoCmd = Get-Command cargo -ErrorAction SilentlyContinue + if (-not $cargoCmd) { + Print-Error "Rust is not installed!" + Print-Info "Install from: https://rustup.rs" + if (Confirm-Action "Open Rust installation page?") { + Start-Process "https://rustup.rs" + } + Press-Enter + return + } + + $rustVersion = rustc --version + Print-Info "Rust: $rustVersion" + Write-Host "" + + $buildDir = Join-Path $env:TEMP "betterdesk_build_$((Get-Date).Ticks)" + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null + + Push-Location $buildDir + + try { + Print-Step "Downloading RustDesk Server sources..." + git clone --depth 1 --branch 1.1.14 https://github.com/rustdesk/rustdesk-server.git + Set-Location "rustdesk-server" + git submodule update --init --recursive + + Print-Step "Applying BetterDesk modifications..." + + $srcDir = Join-Path $script:ScriptDir "hbbs-patch-v2\src" + if (Test-Path $srcDir) { + Copy-Item -Path "$srcDir\main.rs" -Destination "src\main.rs" -Force + Copy-Item -Path "$srcDir\http_api.rs" -Destination "src\http_api.rs" -Force + Copy-Item -Path "$srcDir\database.rs" -Destination "src\database.rs" -Force + Copy-Item -Path "$srcDir\peer.rs" -Destination "src\peer.rs" -Force -ErrorAction SilentlyContinue + Copy-Item -Path "$srcDir\rendezvous_server.rs" -Destination "src\rendezvous_server.rs" -Force -ErrorAction SilentlyContinue + } else { + Print-Error "Source modifications not found: $srcDir" + return + } + + Print-Step "Compiling (may take several minutes)..." + cargo build --release + + Print-Step "Copying binaries..." + + $outputDir = Join-Path $script:ScriptDir "hbbs-patch-v2" + Copy-Item -Path "target\release\hbbs.exe" -Destination "$outputDir\hbbs-windows-x86_64.exe" -Force + Copy-Item -Path "target\release\hbbr.exe" -Destination "$outputDir\hbbr-windows-x86_64.exe" -Force + + Print-Success "Compilation completed!" + Print-Info "Binaries saved in: $outputDir" + + } finally { + Pop-Location + Remove-Item -Path $buildDir -Recurse -Force -ErrorAction SilentlyContinue + } + + Write-Host "" + if (Confirm-Action "Install newly compiled binaries?") { + Do-Update + } + + Press-Enter } #=============================================================================== @@ -1391,68 +1666,68 @@ function Invoke-Uninstall { #=============================================================================== function Show-Menu { - Write-Header - Write-Status + Print-Header + Print-Status - Write-Host " โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• MAIN MENU โ•โ•โ•โ•โ•โ•โ•โ•โ•=" -ForegroundColor White + Write-Host "========== MAIN MENU ==========" -ForegroundColor White Write-Host "" - Write-Host " 1. ๐Ÿš€ FRESH INSTALLATION" - Write-Host " 2. โฌ†๏ธ UPDATE" - Write-Host " 3. ๐Ÿ”ง REPAIR INSTALLATION" - Write-Host " 4. โœ… INSTALLATION VALIDATION" - Write-Host " 5. ๐Ÿ’พ Backup" - Write-Host " 6. ๐Ÿ” Reset admin password" - Write-Host " 7. ๐Ÿ”จ Build binaries" - Write-Host " 8. ๐Ÿ“Š DIAGNOSTICS" - Write-Host " 9. ๐Ÿ—‘๏ธ UNINSTALL" + Write-Host " 1. FRESH INSTALLATION" + Write-Host " 2. UPDATE" + Write-Host " 3. REPAIR INSTALLATION" + Write-Host " 4. INSTALLATION VALIDATION" + Write-Host " 5. Backup" + Write-Host " 6. Reset admin password" + Write-Host " 7. Build binaries" + Write-Host " 8. DIAGNOSTICS" + Write-Host " 9. UNINSTALL" Write-Host "" - Write-Host " S. โš™๏ธ Settings (paths)" - Write-Host " 0. โŒ Exit" + Write-Host " S. Settings (paths)" + Write-Host " 0. Exit" Write-Host "" } -# Auto-detect paths on startup -Write-Host " Detecting installation..." -ForegroundColor Cyan -Find-Paths -Write-Host "" -Start-Sleep -Seconds 1 - -# Auto mode - run installation directly -if ($Auto) { - Write-Info "Running in AUTO mode..." - $result = Invoke-Install - if ($result) { +function Main { + # Auto-detect paths on startup + Write-Host "Detecting installation..." -ForegroundColor Cyan + Auto-DetectPaths + Write-Host "" + Start-Sleep -Seconds 1 + + # Auto mode - run installation directly + if ($script:AUTO_MODE) { + Print-Info "Running in AUTO mode..." + Do-Install exit 0 - } else { - exit 1 + } + + while ($true) { + Show-Menu + $choice = Read-Host "Select option" + + switch ($choice) { + "1" { Do-Install } + "2" { Do-Update } + "3" { Do-Repair } + "4" { Do-Validate } + "5" { Do-Backup } + "6" { Do-ResetPassword } + "7" { Do-Build } + "8" { Do-Diagnostics } + "9" { Do-Uninstall } + "S" { Configure-Paths } + "s" { Configure-Paths } + "0" { + Write-Host "" + Print-Info "Goodbye!" + exit 0 + } + default { + Print-Warning "Invalid option" + Start-Sleep -Seconds 1 + } + } } } -# Interactive Main Menu -while ($true) { - Show-Menu - $choice = Read-Host " Select option" - - switch ($choice) { - "1" { Invoke-Install } - "2" { Invoke-Update } - "3" { Invoke-Repair } - "4" { Invoke-Validate } - "5" { Invoke-Backup } - "6" { Reset-AdminPassword } - "7" { Invoke-Build } - "8" { Invoke-Diagnostics } - "9" { Invoke-Uninstall } - "S" { Set-Paths } - "s" { Set-Paths } - "0" { - Write-Host "" - Write-Info "Goodbye!" - exit - } - default { - Write-Warning2 "Invalid option" - Start-Sleep -Seconds 1 - } - } -} +# Run +Main diff --git a/build-betterdesk.ps1 b/build-betterdesk.ps1 index c948bb02..1324e160 100644 --- a/build-betterdesk.ps1 +++ b/build-betterdesk.ps1 @@ -1,112 +1,145 @@ -# ============================================================================= -# BetterDesk Server - Interactive Build Script (Windows) -# ============================================================================= -# This script automates building BetterDesk enhanced binaries from source. -# It handles downloading RustDesk sources, applying BetterDesk modifications, -# and compiling the final binaries. -# -# Usage: -# .\build-betterdesk.ps1 # Interactive mode -# .\build-betterdesk.ps1 -Auto # Non-interactive (use defaults) -# .\build-betterdesk.ps1 -Clean # Clean build directory -# .\build-betterdesk.ps1 -Help # Show help -# -# Requirements: -# - Rust toolchain (rustup) -# - Visual Studio Build Tools with C++ support -# - Git -# ============================================================================= +<# +.SYNOPSIS + BetterDesk Server - Interactive Build Script for Windows + +.DESCRIPTION + This script automates building BetterDesk enhanced binaries from source. + It handles downloading RustDesk sources, applying BetterDesk modifications, + and compiling the final binaries. + +.PARAMETER Auto + Non-interactive mode (use default settings) + +.PARAMETER Clean + Clean build directory and exit + +.PARAMETER Version + Specify RustDesk version (default: 1.1.14) + +.EXAMPLE + .\build-betterdesk.ps1 + Interactive build + +.EXAMPLE + .\build-betterdesk.ps1 -Auto + Build with defaults + +.EXAMPLE + .\build-betterdesk.ps1 -Version 1.1.15 + Build specific version +#> param( [switch]$Auto, [switch]$Clean, [string]$Version = "", - [string]$Platform = "", [switch]$Help ) -$ErrorActionPreference = "Stop" - +# ============================================================================ # Configuration -$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$BuildDir = Join-Path $ScriptDir "build" -$PatchesDir = Join-Path $ScriptDir "hbbs-patch-v2\src" -$OutputDir = Join-Path $ScriptDir "hbbs-patch-v2" +# ============================================================================ -# Default RustDesk version -$DefaultRustDeskVersion = "1.1.14" -$RustDeskRepo = "https://github.com/rustdesk/rustdesk-server.git" +$Script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$Script:BuildDir = Join-Path $Script:ScriptDir "build" +$Script:PatchesDir = Join-Path $Script:ScriptDir "hbbs-patch-v2\src" +$Script:OutputDir = Join-Path $Script:ScriptDir "hbbs-patch-v2" -# State -$RustDeskVersion = $DefaultRustDeskVersion -$TargetPlatform = "windows-x64" +$Script:DefaultRustDeskVersion = "1.1.14" +$Script:RustDeskRepo = "https://github.com/rustdesk/rustdesk-server.git" -# ============================================================================= +$Script:RustDeskVersion = "" +$Script:TargetPlatform = "windows-x64" + +# ============================================================================ # Helper Functions -# ============================================================================= +# ============================================================================ function Write-Header { - param([string]$Message) + param([string]$Title) Write-Host "" - Write-Host "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan - Write-Host "โ•‘ $Message" -ForegroundColor Cyan - Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan + Write-Host " ========================================================" -ForegroundColor Cyan + Write-Host " $Title" -ForegroundColor Cyan + Write-Host " ========================================================" -ForegroundColor Cyan Write-Host "" } -function Write-Success { param([string]$Msg) Write-Host "โœ“ $Msg" -ForegroundColor Green } -function Write-Error2 { param([string]$Msg) Write-Host "โœ— $Msg" -ForegroundColor Red } -function Write-Warning2 { param([string]$Msg) Write-Host "โš  $Msg" -ForegroundColor Yellow } -function Write-Info { param([string]$Msg) Write-Host "โ„น $Msg" -ForegroundColor Blue } -function Write-Step { param([string]$Msg) Write-Host "โ†’ $Msg" -ForegroundColor Cyan } +function Write-Success { + param([string]$Message) + Write-Host "[OK] " -ForegroundColor Green -NoNewline + Write-Host $Message +} -function Show-Help { - Write-Host "BetterDesk Server - Build Script (Windows)" +function Write-Error2 { + param([string]$Message) + Write-Host "[ERROR] " -ForegroundColor Red -NoNewline + Write-Host $Message +} + +function Write-Warning2 { + param([string]$Message) + Write-Host "[WARNING] " -ForegroundColor Yellow -NoNewline + Write-Host $Message +} + +function Write-Info { + param([string]$Message) + Write-Host "[INFO] " -ForegroundColor Blue -NoNewline + Write-Host $Message +} + +function Write-Step { + param([string]$Message) + Write-Host ">> " -ForegroundColor Magenta -NoNewline + Write-Host $Message +} + +function Show-HelpMessage { + Write-Host "BetterDesk Server - Build Script" Write-Host "" Write-Host "Usage: .\build-betterdesk.ps1 [OPTIONS]" Write-Host "" Write-Host "Options:" Write-Host " -Auto Non-interactive mode (use default settings)" Write-Host " -Clean Clean build directory and exit" - Write-Host " -Version VER Specify RustDesk version (default: $DefaultRustDeskVersion)" - Write-Host " -Platform PLT Target platform: windows-x64, linux-x64" + Write-Host " -Version VER Specify RustDesk version (default: $Script:DefaultRustDeskVersion)" Write-Host " -Help Show this help message" Write-Host "" Write-Host "Examples:" - Write-Host " .\build-betterdesk.ps1 # Interactive build" - Write-Host " .\build-betterdesk.ps1 -Auto # Build with defaults" - Write-Host " .\build-betterdesk.ps1 -Version 1.1.15 # Build specific version" + Write-Host " .\build-betterdesk.ps1 # Interactive build" + Write-Host " .\build-betterdesk.ps1 -Auto # Build with defaults" + Write-Host " .\build-betterdesk.ps1 -Version 1.1.15 # Build specific version" Write-Host "" } -# ============================================================================= +# ============================================================================ # Dependency Checks -# ============================================================================= +# ============================================================================ -function Test-Dependencies { +function Check-Dependencies { Write-Header "Checking Dependencies" $missing = 0 # Check Rust - $cargo = Get-Command cargo -ErrorAction SilentlyContinue - if ($cargo) { + $cargoCmd = Get-Command cargo -ErrorAction SilentlyContinue + if ($cargoCmd) { $rustVersion = & rustc --version 2>&1 Write-Success "Rust/Cargo: $rustVersion" } else { Write-Error2 "Rust/Cargo not found" - Write-Host " Install from: https://rustup.rs/" + Write-Host " Install from: https://rustup.rs" $missing++ } # Check Git - $git = Get-Command git -ErrorAction SilentlyContinue - if ($git) { + $gitCmd = Get-Command git -ErrorAction SilentlyContinue + if ($gitCmd) { $gitVersion = & git --version 2>&1 Write-Success "Git: $gitVersion" } else { Write-Error2 "Git not found" - Write-Host " Install from: https://git-scm.com/" + Write-Host " Install from: https://git-scm.com/download/win" $missing++ } @@ -117,33 +150,43 @@ function Test-Dependencies { if ($vsPath) { Write-Success "Visual Studio Build Tools found" } else { - Write-Warning2 "Visual Studio C++ Build Tools may not be installed" - Write-Host " Install from: https://visualstudio.microsoft.com/visual-cpp-build-tools/" + Write-Warning2 "Visual Studio C++ tools may not be installed" + Write-Host " Install Visual Studio Build Tools with C++ support" } } else { - Write-Warning2 "Could not verify Visual Studio Build Tools" + Write-Warning2 "vswhere not found - cannot verify Visual Studio" + } + + # Check CMake (optional but helpful) + $cmakeCmd = Get-Command cmake -ErrorAction SilentlyContinue + if ($cmakeCmd) { + $cmakeVersion = & cmake --version 2>&1 | Select-Object -First 1 + Write-Success "CMake: $cmakeVersion" + } else { + Write-Info "CMake not found (optional for some builds)" } if ($missing -gt 0) { Write-Host "" Write-Error2 "Missing dependencies. Please install them first." Write-Host "" - Write-Host "Required:" - Write-Host " 1. Rust: https://rustup.rs/" - Write-Host " 2. Git: https://git-scm.com/" - Write-Host " 3. Visual Studio Build Tools with C++ support" + Write-Host "Quick install:" -ForegroundColor Yellow + Write-Host " 1. Install Rust from https://rustup.rs" + Write-Host " 2. Install Git from https://git-scm.com/download/win" + Write-Host " 3. Install Visual Studio Build Tools with C++ workload" Write-Host "" - exit 1 + return $false } Write-Success "All dependencies satisfied!" + return $true } -# ============================================================================= +# ============================================================================ # Interactive Configuration -# ============================================================================= +# ============================================================================ -function Get-Configuration { +function Interactive-Config { Write-Header "Build Configuration" # Select RustDesk version @@ -154,52 +197,36 @@ function Get-Configuration { Write-Host "" if ($Auto) { - $script:RustDeskVersion = $DefaultRustDeskVersion - Write-Info "Auto mode: Using version $RustDeskVersion" - } elseif ($Version) { - $script:RustDeskVersion = $Version + $Script:RustDeskVersion = $Script:DefaultRustDeskVersion + Write-Info "Auto mode: Using version $Script:RustDeskVersion" } else { - $choice = Read-Host "Select version [1]" - switch ($choice) { - "2" { $script:RustDeskVersion = "1.1.13" } - "3" { $script:RustDeskVersion = Read-Host "Enter version (e.g., 1.1.15)" } - default { $script:RustDeskVersion = $DefaultRustDeskVersion } + $versionChoice = Read-Host "Select version [1]" + switch ($versionChoice) { + "2" { $Script:RustDeskVersion = "1.1.13" } + "3" { + $Script:RustDeskVersion = Read-Host "Enter version (e.g., 1.1.15)" + } + default { $Script:RustDeskVersion = $Script:DefaultRustDeskVersion } } } - Write-Success "Selected RustDesk version: $RustDeskVersion" + Write-Success "Selected RustDesk version: $Script:RustDeskVersion" Write-Host "" - # Select target platform - Write-Host "Target platform:" -ForegroundColor White - Write-Host " 1) Windows x86_64 (native)" - Write-Host " 2) Linux x86_64 (cross-compile, requires WSL)" - Write-Host "" - - if ($Auto) { - $script:TargetPlatform = "windows-x64" - Write-Info "Auto mode: Building for $TargetPlatform" - } elseif ($Platform) { - $script:TargetPlatform = $Platform - } else { - $choice = Read-Host "Select platform [1]" - switch ($choice) { - "2" { $script:TargetPlatform = "linux-x64" } - default { $script:TargetPlatform = "windows-x64" } - } - } - - Write-Success "Target platform: $TargetPlatform" + # Target platform is always Windows x64 on Windows + $Script:TargetPlatform = "windows-x64" + Write-Success "Target platform: $Script:TargetPlatform" Write-Host "" # Confirm if (-not $Auto) { Write-Host "Build Summary:" -ForegroundColor White - Write-Host " RustDesk Version: $RustDeskVersion" - Write-Host " Target Platform: $TargetPlatform" - Write-Host " Build Directory: $BuildDir" - Write-Host " Output Directory: $OutputDir" + Write-Host " RustDesk Version: $Script:RustDeskVersion" + Write-Host " Target Platform: $Script:TargetPlatform" + Write-Host " Build Directory: $Script:BuildDir" + Write-Host " Output Directory: $Script:OutputDir" Write-Host "" + $confirm = Read-Host "Continue with build? [Y/n]" if ($confirm -match "^[Nn]$") { Write-Host "Build cancelled." @@ -208,14 +235,14 @@ function Get-Configuration { } } -# ============================================================================= +# ============================================================================ # Download RustDesk Sources -# ============================================================================= +# ============================================================================ -function Get-RustDeskSources { +function Download-RustDesk { Write-Header "Downloading RustDesk Server Sources" - $sourceDir = Join-Path $BuildDir "rustdesk-server-$RustDeskVersion" + $sourceDir = Join-Path $Script:BuildDir "rustdesk-server-$Script:RustDeskVersion" if (Test-Path $sourceDir) { Write-Info "Source directory exists: $sourceDir" @@ -224,259 +251,306 @@ function Get-RustDeskSources { $redownload = Read-Host "Re-download sources? [y/N]" if ($redownload -notmatch "^[Yy]$") { Write-Success "Using existing sources" - return + return $true } } else { Write-Info "Auto mode: Using existing sources" - return + return $true } - Remove-Item $sourceDir -Recurse -Force + Remove-Item -Path $sourceDir -Recurse -Force } - if (-not (Test-Path $BuildDir)) { - New-Item -ItemType Directory -Path $BuildDir | Out-Null + if (-not (Test-Path $Script:BuildDir)) { + New-Item -ItemType Directory -Path $Script:BuildDir -Force | Out-Null } - Push-Location $BuildDir + Push-Location $Script:BuildDir - Write-Step "Cloning rustdesk-server repository..." - & git clone --depth 1 --branch $RustDeskVersion $RustDeskRepo "rustdesk-server-$RustDeskVersion" - - Set-Location "rustdesk-server-$RustDeskVersion" - - Write-Step "Initializing submodules..." - & git submodule update --init --recursive - - Pop-Location - - Write-Success "RustDesk sources downloaded successfully" + try { + Write-Step "Cloning rustdesk-server repository..." + & git clone --depth 1 --branch $Script:RustDeskVersion $Script:RustDeskRepo "rustdesk-server-$Script:RustDeskVersion" 2>&1 + + Set-Location "rustdesk-server-$Script:RustDeskVersion" + + Write-Step "Initializing submodules..." + & git submodule update --init --recursive 2>&1 + + Write-Success "RustDesk sources downloaded successfully" + return $true + } catch { + Write-Error2 "Failed to download sources: $_" + return $false + } finally { + Pop-Location + } } -# ============================================================================= +# ============================================================================ # Apply BetterDesk Modifications -# ============================================================================= +# ============================================================================ function Apply-Modifications { Write-Header "Applying BetterDesk Modifications" - $sourceDir = Join-Path $BuildDir "rustdesk-server-$RustDeskVersion" + $sourceDir = Join-Path $Script:BuildDir "rustdesk-server-$Script:RustDeskVersion" if (-not (Test-Path $sourceDir)) { Write-Error2 "Source directory not found: $sourceDir" - exit 1 + return $false } Push-Location $sourceDir - # List of files to copy from patches - $patchFiles = @( - "main.rs", - "http_api.rs", - "database.rs", - "database_fixed.rs", - "peer.rs", - "peer_fixed.rs", - "rendezvous_server_core.rs" - ) - - Write-Step "Copying BetterDesk modifications..." - - foreach ($file in $patchFiles) { - $patchPath = Join-Path $PatchesDir $file - if (Test-Path $patchPath) { - $targetPath = Join-Path "src" $file - Copy-Item $patchPath $targetPath -Force - Write-Success "Applied: $file" - } else { - Write-Warning2 "Patch file not found: $file" + try { + # List of files to copy from patches + $patchFiles = @( + "main.rs", + "http_api.rs", + "database.rs", + "database_fixed.rs", + "peer.rs", + "peer_fixed.rs", + "rendezvous_server_core.rs" + ) + + Write-Step "Copying BetterDesk modifications..." + + foreach ($file in $patchFiles) { + $srcPath = Join-Path $Script:PatchesDir $file + + if (Test-Path $srcPath) { + switch ($file) { + "main.rs" { + Copy-Item -Path $srcPath -Destination "src\main.rs" -Force + Write-Success "Applied: main.rs (HTTP API integration)" + } + "http_api.rs" { + Copy-Item -Path $srcPath -Destination "src\http_api.rs" -Force + Write-Success "Applied: http_api.rs (REST API module)" + } + default { + Copy-Item -Path $srcPath -Destination "src\$file" -Force + Write-Success "Applied: $file" + } + } + } else { + Write-Warning2 "Patch file not found: $file" + } } + + # Update Cargo.toml if needed + Write-Step "Checking Cargo.toml dependencies..." + + $cargoPath = "Cargo.toml" + $cargoContent = Get-Content $cargoPath -Raw + + if ($cargoContent -notmatch "axum") { + Write-Info "Adding HTTP API dependencies to Cargo.toml..." + + # This is a simplified approach - may need manual adjustment + Write-Warning2 "Please verify Cargo.toml has required dependencies (axum, chrono)" + } else { + Write-Info "Cargo.toml already has required dependencies" + } + + Write-Success "BetterDesk modifications applied successfully" + return $true + } catch { + Write-Error2 "Failed to apply modifications: $_" + return $false + } finally { + Pop-Location } - - Pop-Location - - Write-Success "BetterDesk modifications applied successfully" } -# ============================================================================= +# ============================================================================ # Build Binaries -# ============================================================================= +# ============================================================================ function Build-Binaries { Write-Header "Building BetterDesk Binaries" - $sourceDir = Join-Path $BuildDir "rustdesk-server-$RustDeskVersion" + $sourceDir = Join-Path $Script:BuildDir "rustdesk-server-$Script:RustDeskVersion" + Push-Location $sourceDir - $targetFlag = "" - $binarySuffix = "-windows-x86_64.exe" - - if ($TargetPlatform -eq "linux-x64") { - Write-Step "Setting up Linux cross-compilation..." - & rustup target add x86_64-unknown-linux-gnu - $targetFlag = "--target x86_64-unknown-linux-gnu" - $binarySuffix = "-linux-x86_64" - } - - Write-Step "Building HBBS (Signal Server)..." - if ($targetFlag) { - & cargo build --release $targetFlag -p hbbs - } else { - & cargo build --release -p hbbs - } - - Write-Step "Building HBBR (Relay Server)..." - if ($targetFlag) { - & cargo build --release $targetFlag -p hbbr - } else { - & cargo build --release -p hbbr - } - - # Find binaries - $targetDir = "target\release" - if ($targetFlag) { - $targetDir = "target\$($targetFlag -replace '--target ','')\release" - } - - $hbbsBinary = Join-Path $targetDir "hbbs.exe" - $hbbrBinary = Join-Path $targetDir "hbbr.exe" - - if ($TargetPlatform -eq "linux-x64") { - $hbbsBinary = Join-Path $targetDir "hbbs" - $hbbrBinary = Join-Path $targetDir "hbbr" - } - - if (-not (Test-Path $hbbsBinary) -or -not (Test-Path $hbbrBinary)) { - Write-Error2 "Build failed - binaries not found" + try { + Write-Step "Building HBBS (Signal Server)..." + $result = & cargo build --release 2>&1 + + if ($LASTEXITCODE -ne 0) { + Write-Error2 "Build failed!" + Write-Host $result + return $false + } + + # Check for binaries + $hbbsBinary = "target\release\hbbs.exe" + $hbbrBinary = "target\release\hbbr.exe" + + if (-not (Test-Path $hbbsBinary) -or -not (Test-Path $hbbrBinary)) { + Write-Error2 "Build failed - binaries not found" + return $false + } + + Write-Success "Build completed successfully!" + + # Copy to output directory + Write-Step "Copying binaries to output directory..." + + if (-not (Test-Path $Script:OutputDir)) { + New-Item -ItemType Directory -Path $Script:OutputDir -Force | Out-Null + } + + $hbbsDst = Join-Path $Script:OutputDir "hbbs-windows-x86_64.exe" + $hbbrDst = Join-Path $Script:OutputDir "hbbr-windows-x86_64.exe" + + Copy-Item -Path $hbbsBinary -Destination $hbbsDst -Force + Copy-Item -Path $hbbrBinary -Destination $hbbrDst -Force + + Write-Success "Binaries saved to:" + Write-Host " - $hbbsDst" + Write-Host " - $hbbrDst" + + return $true + } catch { + Write-Error2 "Build error: $_" + return $false + } finally { Pop-Location - exit 1 } - - Write-Success "Build completed successfully!" - - # Copy to output directory - Write-Step "Copying binaries to output directory..." - - $hbbsOutput = Join-Path $OutputDir "hbbs$binarySuffix" - $hbbrOutput = Join-Path $OutputDir "hbbr$binarySuffix" - - Copy-Item $hbbsBinary $hbbsOutput -Force - Copy-Item $hbbrBinary $hbbrOutput -Force - - Pop-Location - - Write-Success "Binaries saved to:" - Write-Host " - $hbbsOutput" - Write-Host " - $hbbrOutput" } -# ============================================================================= +# ============================================================================ # Generate Checksums -# ============================================================================= +# ============================================================================ -function New-Checksums { +function Generate-Checksums { Write-Header "Generating Checksums" - $checksumsFile = Join-Path $OutputDir "CHECKSUMS.md" - $dateNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + Push-Location $Script:OutputDir - $content = @" + try { + $checksumFile = "CHECKSUMS.md" + $dateNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + + $content = @" # BetterDesk Server - Binary Checksums Generated: $dateNow -RustDesk Base Version: $RustDeskVersion +RustDesk Base Version: $Script:RustDeskVersion BetterDesk Version: 2.0.0 ## SHA256 Checksums `````` "@ - - Get-ChildItem $OutputDir -Filter "hbbs-*" | ForEach-Object { - $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash - $content += "$hash $($_.Name)`n" + + $binaries = Get-ChildItem -Filter "hbbs-*" -File + $binaries += Get-ChildItem -Filter "hbbr-*" -File + + foreach ($binary in $binaries) { + $hash = (Get-FileHash -Path $binary.FullName -Algorithm SHA256).Hash + $content += "$hash $($binary.Name)`n" + } + + $content += "```" + + $content | Out-File -FilePath $checksumFile -Encoding UTF8 + + Write-Success "Checksums saved to: $Script:OutputDir\$checksumFile" + } catch { + Write-Warning2 "Could not generate checksums: $_" + } finally { + Pop-Location } - - Get-ChildItem $OutputDir -Filter "hbbr-*" | ForEach-Object { - $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash - $content += "$hash $($_.Name)`n" - } - - $content += "``````" - - $content | Out-File $checksumsFile -Encoding UTF8 - - Write-Success "Checksums saved to: $checksumsFile" } -# ============================================================================= +# ============================================================================ # Clean Build -# ============================================================================= +# ============================================================================ -function Clear-Build { +function Clean-Build { Write-Header "Cleaning Build Directory" - if (Test-Path $BuildDir) { - Write-Step "Removing: $BuildDir" - Remove-Item $BuildDir -Recurse -Force + if (Test-Path $Script:BuildDir) { + Write-Step "Removing: $Script:BuildDir" + Remove-Item -Path $Script:BuildDir -Recurse -Force Write-Success "Build directory cleaned" } else { Write-Info "Build directory does not exist" } } -# ============================================================================= +# ============================================================================ # Main -# ============================================================================= +# ============================================================================ function Main { - # Handle help + # Show help if ($Help) { - Show-Help + Show-HelpMessage exit 0 } - # Handle clean mode + # Clean mode if ($Clean) { - Clear-Build + Clean-Build exit 0 } - # Banner + # Use provided version or default + if ($Version) { + $Script:RustDeskVersion = $Version + } + Write-Host "" - Write-Host "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" -ForegroundColor Cyan - Write-Host "โ•‘ BetterDesk Server - Build from Source (Windows) โ•‘" -ForegroundColor Cyan - Write-Host "โ•‘ Enhanced RustDesk with HTTP API & Management โ•‘" -ForegroundColor Cyan - Write-Host "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Cyan + Write-Host " ========================================================" -ForegroundColor Cyan + Write-Host " BetterDesk Server - Build Script (Windows) " -ForegroundColor Cyan + Write-Host " ========================================================" -ForegroundColor Cyan Write-Host "" - # Run build steps - Test-Dependencies - Get-Configuration - Get-RustDeskSources - Apply-Modifications - Build-Binaries - New-Checksums + # Check dependencies + if (-not (Check-Dependencies)) { + exit 1 + } - # Final message - Write-Header "Build Complete!" + # Interactive configuration + Interactive-Config + + # Download sources + if (-not (Download-RustDesk)) { + exit 1 + } + + # Apply modifications + if (-not (Apply-Modifications)) { + exit 1 + } + + # Build + if (-not (Build-Binaries)) { + exit 1 + } + + # Generate checksums + Generate-Checksums - Write-Host "BetterDesk binaries have been built successfully!" -ForegroundColor Green Write-Host "" - Write-Host "Output location: $OutputDir" + Write-Success "Build process completed successfully!" Write-Host "" - Write-Host "Next steps:" + Write-Host "Binaries are available in: $Script:OutputDir" -ForegroundColor Cyan + Write-Host "" + Write-Host "Next steps:" -ForegroundColor Yellow Write-Host " 1. Test the binaries:" - Write-Host " cd $OutputDir" Write-Host " .\hbbs-windows-x86_64.exe --help" + Write-Host " .\hbbr-windows-x86_64.exe --help" Write-Host "" - Write-Host " 2. Run the installer to deploy:" - Write-Host " .\install-improved.ps1" - Write-Host "" - Write-Host " 3. Or manually start the servers:" - Write-Host " .\hbbs-windows-x86_64.exe -k _ --api-port 21114" - Write-Host " .\hbbr-windows-x86_64.exe" + Write-Host " 2. Install using betterdesk.ps1:" + Write-Host " .\betterdesk.ps1" Write-Host "" } +# Run Main diff --git a/docs/DOCKER_TROUBLESHOOTING.md b/docs/DOCKER_TROUBLESHOOTING.md index ae69d354..a4aef09f 100644 --- a/docs/DOCKER_TROUBLESHOOTING.md +++ b/docs/DOCKER_TROUBLESHOOTING.md @@ -97,6 +97,53 @@ The BetterDesk binaries in `hbbs-patch-v2/` include: --- +## Problem: Build Fails on Oracle Cloud VM (Read-only resolv.conf) + +### Symptom +``` +/bin/sh: 1: cannot create /etc/resolv.conf: Read-only file system +target betterdesk-console: failed to solve: process "/bin/sh -c echo \"nameserver 8.8.8.8\" >> /etc/resolv.conf... +``` + +### Cause +Oracle Cloud VMs have `/etc/resolv.conf` managed by `oraclevcn` service and it's **read-only**. The Dockerfile tries to modify DNS settings which fails. + +### โœ… Solution + +**This is now fixed in the latest version.** The Dockerfile.console now checks if the file is writable before attempting to modify it: + +```dockerfile +RUN if [ -w /etc/resolv.conf ] && ! grep -q "oraclevcn" /etc/resolv.conf 2>/dev/null; then \ + echo "nameserver 8.8.8.8" >> /etc/resolv.conf; \ + echo "nameserver 1.1.1.1" >> /etc/resolv.conf; \ + fi && \ + apt-get update && apt-get install -y ... +``` + +If you have an older version: +```bash +# Update to latest +git pull origin main + +# Rebuild images +docker compose build --no-cache +docker compose up -d +``` + +**Alternative for Oracle Cloud (if DNS issues persist):** +```bash +# Configure Docker daemon to use Google DNS +sudo mkdir -p /etc/docker +sudo tee /etc/docker/daemon.json > /dev/null <