<# Install-HonorProPlugins.ps1 ------------------------------------------------------------------------- One-shot setup on a MetaTrader 5 Windows server so the HonorPro platform can connect to it and cut over. Installs the three HonorPro server plugins, sets their tokens/ports, and opens a locked-down SSH path for the HonorPro gateway. No build step — the DLLs are shipped pre-compiled. Run in an ELEVATED PowerShell (Run as Administrator), from the folder that holds the three DLLs and this script: .\Install-HonorProPlugins.ps1 -PluginsDir "C:\Path\To\MT5\Plugins" What it does: 1. Copies honorpro-bridge.dll / honorpro-copy-trading.dll / honorpro-pick-the-level.dll into the MT5 Plugins directory. 2. Generates strong tokens (or uses ones you pass) and sets them, plus the ports, as MACHINE environment variables. The plugins read env first, so no values need typing into the MT5 Administrator. 3. Installs OpenSSH Server, creates a restricted forwarding-only user, installs HonorPro's public key locked to the three loopback ports, hardens sshd, and opens inbound SSH from HonorPro's IP only. 4. Writes honorpro-handoff.txt with exactly what to send back to HonorPro. After it finishes: in the MT5 Administrator, add + enable the three plugins (Plugins -> Add), then restart the affected server component. Then run Verify-HonorProPlugins.ps1. #> [CmdletBinding()] param( # MT5 server "Plugins" directory (where server plugin DLLs live). [Parameter(Mandatory = $true)] [string] $PluginsDir, # Folder holding the three DLLs (defaults to this script's folder). [string] $DllDir = $PSScriptRoot, # Restricted SSH user HonorPro's gateway logs in as. [string] $SshUser = "hnr", # HonorPro gateway public IP allowed to reach SSH. [string] $HonorProIP = "78.141.244.255", # Loopback ports for the three plugins. [int] $BridgePort = 8091, [int] $CopyPort = 8092, [int] $PtlPort = 8093, # Provide tokens to reuse existing ones; otherwise they are generated. [string] $BridgeToken = "", [string] $CopyToken = "", [string] $PtlToken = "", # Skip Pick The Level if you will not run its campaigns. [switch] $NoPtl ) $ErrorActionPreference = "Stop" # HonorPro gateway public key (ed25519). Safe to publish; it only permits # forwarding to the three loopback ports below. $HonorProPubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVhQNC74YcXfHC1xub2cS7XjljejUa5i3hCFgbQiR6d vps-to-mt5-bridge" function New-Token { $bytes = New-Object 'System.Byte[]' 32 [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes) return ([Convert]::ToBase64String($bytes)) -replace '[+/=]', '' } function Require-Admin { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) if (-not $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "Run this script in an elevated PowerShell (Run as Administrator)." } } Write-Host "== HonorPro MT5 plugin install ==" -ForegroundColor Cyan Require-Admin # ---- 1. Copy the plugin DLLs ------------------------------------------------ if (-not (Test-Path $PluginsDir)) { throw "Plugins directory not found: $PluginsDir" } $plugins = @( @{ Name = "Bridge"; Dll = "honorpro-bridge.dll"; Port = $BridgePort }, @{ Name = "Copy-Trading"; Dll = "honorpro-copy-trading.dll"; Port = $CopyPort } ) if (-not $NoPtl) { $plugins += @{ Name = "Pick The Level"; Dll = "honorpro-pick-the-level.dll"; Port = $PtlPort } } foreach ($p in $plugins) { $src = Join-Path $DllDir $p.Dll if (-not (Test-Path $src)) { throw "Missing DLL: $src" } Copy-Item $src -Destination (Join-Path $PluginsDir $p.Dll) -Force Write-Host (" copied {0} -> {1}" -f $p.Dll, $PluginsDir) } # ---- 2. Tokens + ports as MACHINE env vars (plugins read env first) --------- if (-not $BridgeToken) { $BridgeToken = New-Token } if (-not $CopyToken) { $CopyToken = New-Token } if (-not $PtlToken -and -not $NoPtl) { $PtlToken = New-Token } function Set-MachineEnv([string]$k, [string]$v) { [Environment]::SetEnvironmentVariable($k, $v, "Machine") } Set-MachineEnv "BRIDGE_TOKEN" $BridgeToken Set-MachineEnv "BRIDGE_PORT" "$BridgePort" Set-MachineEnv "COPY_TOKEN" $CopyToken Set-MachineEnv "COPY_PORT" "$CopyPort" if (-not $NoPtl) { Set-MachineEnv "PTL_TOKEN" $PtlToken Set-MachineEnv "PTL_PORT" "$PtlPort" } Write-Host " set BRIDGE_/COPY_/PTL_ TOKEN+PORT as machine environment variables" Write-Host " (the MT5 server must be restarted so the plugins inherit them)" # ---- 3. OpenSSH server + restricted forwarding-only user -------------------- Write-Host "== SSH access ==" -ForegroundColor Cyan $cap = Get-WindowsCapability -Online -Name "OpenSSH.Server*" if ($cap.State -ne "Installed") { Add-WindowsCapability -Online -Name $cap.Name | Out-Null } Set-Service -Name sshd -StartupType Automatic Start-Service sshd # Create the dedicated user if missing (random password; login is key-only). if (-not (Get-LocalUser -Name $SshUser -ErrorAction SilentlyContinue)) { $pw = ConvertTo-SecureString (New-Token) -AsPlainText -Force New-LocalUser -Name $SshUser -Password $pw -FullName "HonorPro tunnel" ` -Description "Restricted port-forwarding account for HonorPro" ` -PasswordNeverExpires -UserMayNotChangePassword | Out-Null Write-Host " created local user '$SshUser' (key-only login)" } else { Write-Host " local user '$SshUser' already exists" } # authorized_keys, restricted to forwarding the three loopback ports only. $permit = @("127.0.0.1:$BridgePort", "127.0.0.1:$CopyPort") if (-not $NoPtl) { $permit += "127.0.0.1:$PtlPort" } $permitClause = ($permit | ForEach-Object { "permitopen=`"$_`"" }) -join "," $keyLine = "restrict,port-forwarding,$permitClause $HonorProPubKey" $sshDir = "C:\Users\$SshUser\.ssh" New-Item -ItemType Directory -Force -Path $sshDir | Out-Null $akPath = Join-Path $sshDir "authorized_keys" Set-Content -Path $akPath -Value $keyLine -Encoding ascii # Lock ACL down to the user + SYSTEM (OpenSSH refuses group/other-writable keys). icacls $akPath /inheritance:r /grant "${SshUser}:R" "SYSTEM:F" "Administrators:F" | Out-Null Write-Host " installed HonorPro key in $akPath (forwarding-only, loopback ports)" # Harden sshd for this user (append a Match block once). $sshdConfig = "C:\ProgramData\ssh\sshd_config" if (Test-Path $sshdConfig) { $marker = "# HonorPro tunnel user" if (-not (Select-String -Path $sshdConfig -SimpleMatch $marker -Quiet)) { $permitOpenLine = "PermitOpen " + (($permit) -join " ") $block = @" $marker Match User $SshUser AllowTcpForwarding yes $permitOpenLine AllowAgentForwarding no X11Forwarding no PermitTTY no ForceCommand echo 'This account is for port forwarding only.' "@ Add-Content -Path $sshdConfig -Value $block Write-Host " appended Match block for '$SshUser' to sshd_config" } else { Write-Host " sshd_config already has the HonorPro block" } Restart-Service sshd } # ---- 4. Firewall: inbound SSH from HonorPro IP only ------------------------- $fwName = "HonorPro SSH" Get-NetFirewallRule -DisplayName $fwName -ErrorAction SilentlyContinue | Remove-NetFirewallRule -ErrorAction SilentlyContinue New-NetFirewallRule -DisplayName $fwName -Direction Inbound -Protocol TCP ` -LocalPort 22 -RemoteAddress $HonorProIP -Action Allow | Out-Null Write-Host " firewall: inbound TCP/22 allowed from $HonorProIP only" Write-Host " (ports $BridgePort/$CopyPort/$PtlPort are loopback — NOT opened in the firewall)" # ---- 5. Handoff file ------------------------------------------------------- $handoff = Join-Path $PSScriptRoot "honorpro-handoff.txt" $lines = @( "HonorPro MT5 connection details - send these to HonorPro over a secure channel.", "Generated: $(Get-Date -Format u)", "", "SSH host / public IP : ", "SSH port : 22", "SSH username : $SshUser", "Public key installed : yes (forwarding-only, loopback ports)", "", "Bridge port / token : $BridgePort / $BridgeToken", "Copy port / token : $CopyPort / $CopyToken" ) if (-not $NoPtl) { $lines += "PTL port / token : $PtlPort / $PtlToken" } $lines += @( "", "MT5 server build : ", "Server API version : 6090", "Test/demo account : " ) Set-Content -Path $handoff -Value $lines -Encoding utf8 Write-Host "" Write-Host "== Done ==" -ForegroundColor Green Write-Host "Handoff written to: $handoff" Write-Host "" Write-Host "NEXT STEPS (manual):" -ForegroundColor Yellow Write-Host " 1. In the MT5 Administrator: Plugins -> Add each HonorPro plugin, enable them." Write-Host " No parameters need typing - they read the environment variables set above." Write-Host " 2. Restart the affected MT5 server component so the plugins load and inherit the env." Write-Host " 3. Run: .\Verify-HonorProPlugins.ps1" Write-Host " 4. Fill in the blanks in honorpro-handoff.txt and send it to HonorPro."