$ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (-not (Get-Command ssh.exe -ErrorAction SilentlyContinue)) { throw 'Please install Windows OpenSSH Client first.' } $sshDir = Join-Path $HOME '.ssh' $tools = Join-Path $sshDir 'leco-tools' $configDir = Join-Path $sshDir 'config.d' New-Item -ItemType Directory -Force $tools, $configDir | Out-Null $archive = Join-Path $tools 'wstunnel.tar.gz' Invoke-WebRequest -UseBasicParsing 'https://ssh.nvlit.asia/downloads/wstunnel_11.0.0_windows_amd64.tar.gz' -OutFile $archive if ((Get-FileHash $archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne '024323c9c2dd1ed1c6f38d417d9b2776e2f0083bba507e80d4a8124c8451b164') { throw 'Download checksum mismatch.' } tar.exe -xzf $archive -C $tools if ($LASTEXITCODE -ne 0) { throw 'Cannot extract wstunnel.' } $exe = (Join-Path $tools 'wstunnel.exe').Replace('\','/') $knownHosts = (Join-Path $sshDir 'known_hosts_leco_https').Replace('\','/') $hostConfig = (Join-Path $configDir 'leco-https.conf').Replace('\','/') $utf8 = New-Object System.Text.UTF8Encoding($false) [IO.File]::WriteAllText($knownHosts, "leco-https ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIANitDBXBwtIDPaY/1Nboc7MhBvQPcDhuJrLF2r+W5cx`n", $utf8) $block = @" Host leco-https HostName 10.7.0.21 User leco Port 22 ProxyCommand "$exe" client --log-lvl OFF --tls-verify-certificate --dns-resolver system://0.0.0.0 -L stdio://10.7.0.21:22 wss://ssh.nvlit.asia HostKeyAlias leco-https UserKnownHostsFile "$knownHosts" StrictHostKeyChecking yes IdentityFile ~/.ssh/id_ed25519_leco IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes BatchMode yes ConnectTimeout 20 ServerAliveInterval 30 ServerAliveCountMax 3 "@ [IO.File]::WriteAllText($hostConfig, $block, $utf8) $configPath = Join-Path $sshDir 'config' $include = 'Include "' + $hostConfig + '"' $current = if (Test-Path $configPath) { [IO.File]::ReadAllText($configPath) } else { '' } if (-not $current.Contains($include)) { if (Test-Path $configPath) { Copy-Item $configPath ($configPath + '.backup-' + (Get-Date -Format 'yyyyMMddHHmmss')) } [IO.File]::WriteAllText($configPath, $include + "`r`n" + $current, $utf8) } Write-Host 'Configured: ssh leco-https "hostname; whoami"' $pubs = @((Join-Path $sshDir 'id_ed25519_leco.pub'), (Join-Path $sshDir 'id_ed25519.pub')) $found = $false foreach ($pub in $pubs) { if (Test-Path $pub) { Write-Host "Send this PUBLIC key to the server administrator ($pub):"; Get-Content $pub; $found = $true; break } } if (-not $found) { Write-Host 'Next: ssh-keygen -t ed25519 -f "$HOME\.ssh\id_ed25519_leco"'; Write-Host 'Then send ONLY the .pub file content for authorization. For unattended use, load a passphrase-protected key into ssh-agent.' }