fix: final review fixes for sshinstall (elevation guard, Win8 drop, authorized_keys newline, style)

Final whole-branch review pass before merge:

1. sshinstall.ps1: #Requires -RunAsAdministrator doesn't enforce under
   `irm ... | iex` (piping into Invoke-Expression). Add an explicit
   WindowsPrincipal/IsInRole elevation check before anything else runs,
   so a non-elevated run fails fast instead of silently falling through
   Get-WindowsCapability's -ErrorAction SilentlyContinue into the
   unsupported-OS branch.

2. sshinstall.ps1: drop the Windows 8 portable Win32-OpenSSH fallback —
   it depends on Expand-Archive (PS 5.0+) and implicit TLS 1.2, neither
   present on stock Windows 8's PS 3.0/4.0, so the one path that existed
   for Windows 8 was guaranteed to fail on Windows 8. Replaced with a
   clear unsupported-OS failure. Windows support is now 10 (1809+)/11
   only; README table updated to match.

3. sshinstall.sh: guarantee a trailing newline before appending the
   admin key to authorized_keys, so a pre-existing file without one
   doesn't get its last line glued to the new key (which also defeats
   the grep -qF idempotency check on every future run). Added the
   equivalent guard to sshinstall.ps1's Add-Content path too — its
   WriteLine only guarantees a trailing newline after what it writes,
   not before, so a hand-edited or externally-written
   administrators_authorized_keys has the same exposure.

4. sshinstall.sh: pacman -Sy -> -S (drop the partial-upgrade footgun,
   matches apps.sh's install-vs-explicit-update convention); chown -R
   now sets both user and group explicitly (matches apps.sh/
   netdrivelink.sh convention).

5. sshinstall.ps1: rename the firewall rule this script creates to
   OpenSSH-Server-In-TCP-sshinstall — the previous name collided with
   the exact rule name Microsoft's own Add-WindowsCapability OpenSSH
   install uses, so a disabled Microsoft-created rule of that name
   would cause New-NetFirewallRule to throw under
   $ErrorActionPreference = "Stop" and kill the script before the key
   was deployed.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
edemilovandClaude Sonnet 5 committed 2026-09-17 15:27:30 +03:00
1 parent 93d9ead905
commit 337a209713
3 files changed
+32 -19

No files matched your search

+1 -1
View File
@@ -29,7 +29,7 @@ irm https://git.edemilov.ru/edemilov/scripts/raw/branch/master/sshinstall.ps1 |
| `netdrivelink.sh` | Mount vanga Samba shares + 2nd drive symlinks | Same |
| `apps.ps1` | Windows equivalent via winget + map network drives | Windows 10/11 |
| `sshinstall.sh` | Install/enable SSH server + deploy admin key | Arch, Debian, Ubuntu, RHEL, Fedora |
| `sshinstall.ps1` | Windows equivalent | Windows 8, 10, 11 |
| `sshinstall.ps1` | Windows equivalent | Windows 10, 11 |
| `gitea-ct-setup.sh` | Create CT116 with Gitea on Proxmox host | Proxmox 8+ |
## Samba shares (vanga — 10.0.99.100)
+25 -16
View File
@@ -16,6 +16,16 @@ function Write-Success { param($t) Write-Host "[✓] $t" -ForegroundColor Green
function Write-Skip { param($t) Write-Host "[~] $t (already done)" -ForegroundColor Magenta }
function Write-Warn { param($t) Write-Host "[!] $t" -ForegroundColor Yellow }
# ── Require elevation ────────────────────────────────────────────
# #Requires -RunAsAdministrator above does not enforce under
# `irm ... | iex` (piping into Invoke-Expression is widely reported not to
# trigger the #Requires check), so this explicit check is the real guard.
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Warn "Must be run as Administrator — re-run PowerShell as Administrator"
exit 1
}
$AdminKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH/hWD8YgjVzA/9V364W4w2HiEpuPjKMQ/Id3SRlyriM edemilov@laptop"
Write-Host ""
@@ -38,21 +48,8 @@ if ($capability -and $capability.State -eq "Installed") {
} elseif (Test-Path $sshdPath) {
Write-Skip "OpenSSH Server (portable install found at $sshdPath)"
} else {
Write-Warn "Windows capability not available (likely Windows 8) — falling back to portable Win32-OpenSSH install"
$zipUrl = "https://github.com/PowerShell/Win32-OpenSSH/releases/latest/download/OpenSSH-Win64.zip"
$zipPath = "$env:TEMP\OpenSSH-Win64.zip"
$installDir = "$env:ProgramFiles\OpenSSH"
Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath
Expand-Archive -Path $zipPath -DestinationPath $env:ProgramFiles -Force
if (Test-Path "$env:ProgramFiles\OpenSSH-Win64") {
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
Move-Item "$env:ProgramFiles\OpenSSH-Win64\*" $installDir -Force
Remove-Item "$env:ProgramFiles\OpenSSH-Win64" -Recurse -Force
}
Push-Location $installDir
& "$installDir\install-sshd.ps1"
Pop-Location
Write-Success "Portable OpenSSH Server installed to $installDir"
Write-Warn "OpenSSH Server capability is not available on this Windows version. This script supports Windows 10 (1809+) and Windows 11 only."
exit 1
}
# ── Enable + start service ────────────────────────────────────────
@@ -77,7 +74,7 @@ if ($rule) {
Write-Skip "Inbound firewall rule for port 22"
} else {
Write-Info "Adding inbound firewall rule for port 22..."
New-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -DisplayName "OpenSSH Server (sshinstall)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 | Out-Null
New-NetFirewallRule -Name "OpenSSH-Server-In-TCP-sshinstall" -DisplayName "OpenSSH Server (sshinstall)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 | Out-Null
Write-Success "Firewall rule added"
}
@@ -95,6 +92,18 @@ $keyDir = Split-Path $keyFile
if (-not (Test-Path $keyDir)) { New-Item -ItemType Directory -Path $keyDir -Force | Out-Null }
if (-not (Test-Path $keyFile)) { New-Item -ItemType File -Path $keyFile -Force | Out-Null }
# Add-Content resumes writing at the file's current end-of-file position and only
# guarantees a trailing newline after what IT writes — it does not fix up a pre-existing
# last line that lacks one (e.g. a hand-edited or externally-written file). Without this
# guard that can glue the new key onto the end of the last existing line, corrupting both,
# same as the bash >> case this fix wave addresses.
if ((Get-Item $keyFile).Length -gt 0) {
$existingRaw = Get-Content -Path $keyFile -Raw
if ($existingRaw.Length -gt 0 -and $existingRaw[-1] -ne "`n") {
Add-Content -Path $keyFile -Value ""
}
}
$existing = Get-Content $keyFile -ErrorAction SilentlyContinue
if ($existing -contains $AdminKey) {
Write-Skip "admin key in $keyFile"
+6 -2
View File
@@ -55,7 +55,7 @@ case $FAMILY in
skip "openssh"
else
info "Installing openssh..."
pacman -Sy --noconfirm --needed openssh
pacman -S --noconfirm --needed openssh
success "openssh installed"
fi
;;
@@ -130,7 +130,11 @@ mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"
touch "$AUTH_KEYS"
chmod 600 "$AUTH_KEYS"
chown -R "$REAL_USER" "$SSH_DIR"
chown -R "$REAL_USER:$REAL_USER" "$SSH_DIR"
if [[ -s "$AUTH_KEYS" ]] && [[ -n "$(tail -c1 "$AUTH_KEYS")" ]]; then
echo >> "$AUTH_KEYS"
fi
if grep -qF "$ADMIN_KEY" "$AUTH_KEYS" 2>/dev/null; then
skip "admin key in $AUTH_KEYS"