From 32bce43fcb13aa28c377a084626e5294c2bbf2b6 Mon Sep 17 00:00:00 2001 From: h404bi Date: Sat, 12 Jan 2019 10:44:25 +0800 Subject: [PATCH] refactor ssh plugin --- libexec/askpass.exe | Bin 14848 -> 0 bytes plugins/ssh.ps1 | 244 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 194 insertions(+), 50 deletions(-) delete mode 100644 libexec/askpass.exe diff --git a/libexec/askpass.exe b/libexec/askpass.exe deleted file mode 100644 index b58559c76740d1c16de04613cdf85f040b7b451c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14848 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 M#{IcXZ|8yk0|uyJ3;+NC diff --git a/plugins/ssh.ps1 b/plugins/ssh.ps1 index fd063b6..e5766d6 100644 --- a/plugins/ssh.ps1 +++ b/plugins/ssh.ps1 @@ -1,68 +1,212 @@ -# based on script from here: +# Based on scripts from here: # https://help.github.com/articles/working-with-ssh-key-passphrases#platform-windows +# https://github.com/dahlbyk/posh-sshell -# Note: $env:USERPROFILE/.ssh/environment should not be used, as it -# already has a different purpose in SSH. -$envfile="$env:USERPROFILE/.ssh/agent.env.ps1" - -try { gcm ssh-agent -ea stop > $null } catch { return } - -# Note: Don't bother checking SSH_AGENT_PID. It's not used -# by SSH itself, and it might even be incorrect -# (for example, when using agent-forwarding over SSH). -function agent_is_running() { - if($env:SSH_AUTH_SOCK) { - # ssh-add returns: - # 0 = agent running, has keys - # 1 = agent running, no keys - # 2 = agent not running - ssh-add -l 2>&1 > $null; - $lastexitcode -ne 2 - } else { - $false - } +# Note: the agent env file is for non win32-openssh (like, cygwin/msys openssh), +# win32-openssh doesn't need this, it runs as system service. +$agentEnvFile = "$env:USERPROFILE/.ssh/agent.env.ps1" + +function Import-AgentEnv() { + if (Test-Path $agentEnvFile) { + # Source the agent env file + . $agentEnvFile | Out-Null + } +} + +# Retrieve the current SSH agent PID (or zero). +# Can be used to determine if there is a running agent. +function Get-SshAgent() { + $agentPid = $env:SSH_AGENT_PID + if ($agentPid) { + $sshAgentProcess = Get-Process | Where-Object { + ($_.Id -eq $agentPid) -and ($_.Name -eq 'ssh-agent') + } + if ($null -ne $sshAgentProcess) { + return $agentPid + } + else { + # Remove SSH_AGENT_PID and SSH_AUTH_SOCK which is unavailable + $env:SSH_AGENT_PID = $null + $env:SSH_AUTH_SOCK = $null + if (Test-Path $agentEnvFile) { + Remove-Item $agentEnvFile + } + } + } + + return 0 } -function agent_has_keys { - ssh-add -l 2>&1 > $null; $lastexitcode -eq 0 +function Add-SshKey([switch]$Verbose) { + # Check to see if any keys have been added. Only add keys if it's empty. + (& ssh-add -l) | Out-Null + if ($LASTEXITCODE -eq 0) { + # Keys have already been added + if ($Verbose) { + Write-Host "Keys have already been added to the ssh-agent." + } + return + } + + # Run ssh-add, add the keys + & ssh-add +} + +function Test-Administrator { + return ([Security.Principal.WindowsPrincipal]` + [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` + [Security.Principal.WindowsBuiltInRole]::Administrator) +} + +function Get-NativeSshAgent() { + # Only works on Windows. PowerShell < 6 must be Windows PowerShell, + # $IsWindows is defined in PS Core. + if (($PSVersionTable.PSVersion.Major -lt 6) -or $IsWindows) { + # Native Windows ssh-agent service + $service = Get-Service "ssh-agent" -ErrorAction Ignore + # Native ssh.exe binary version must include "OpenSSH" + $nativeSsh = Get-Command "ssh.exe" -ErrorAction Ignore ` + | ForEach-Object FileVersionInfo ` + | Where-Object ProductVersion -match OpenSSH + + # hack for Scoop broken shims, the shim lost the information of the binary + if (!$nativeSsh) { + $shim = Get-Command "ssh.shim" -ErrorAction Ignore + if ($shim) { + $value = (Get-Content $shim.Source) -creplace 'path = ' + # Check original ssh.exe binary + $nativeSsh = Get-Command $value -ErrorAction Ignore ` + | ForEach-Object FileVersionInfo ` + | Where-Object ProductVersion -match OpenSSH + } + } + + # Ouptut error if native ssh.exe exists but without ssh-agent.service + if ($nativeSsh -and !$service) { + Write-Host "You have Win32-OpenSSH binaries installed but missed the ssh-agent service. Please fix it." -f DarkRed + } + + $result = @{} + $result.service = $service + $result.nativeSsh = $nativeSsh + return $result + } } -function agent_load_env { - if(test-path $envfile) { . $envfile > $null } +function Start-NativeSshAgent([switch]$Verbose) { + $result = Get-NativeSshAgent + $service = $result.service + $nativeSsh = $result.nativeSsh + + if (!$service) { + if ($nativeSsh) { + # ssh-agent service doesn't exist, but native ssh.exe found, + # exit with true so Start-SshAgent doesn't try to do any other work. + return $true + } else { + return $false + } + } + + # Native ssh doesn't need agentEnvFile, remove it. + if (Test-Path $agentEnvFile) { + Remove-Item $agentEnvFile + } + + # Enable the servivce if it's disabled and we're an admin + if ($service.StartType -eq "Disabled") { + if (Test-Administrator) { + Set-Service "ssh-agent" -StartupType 'Manual' + } else { + Write-Host "The ssh-agent service is disabled. Please enable the service and try again." -f DarkRed + # Exit with true so Start-SshAgent doesn't try to do any other work. + return $true + } + } + + # Start the service + if ($service.Status -ne "Running") { + if ($Verbose) { + Write-Host "Starting ssh-agent service." + } + Start-Service "ssh-agent" + } + + Add-SshKey -Verbose:$Verbose + + return $true } -function agent_start { - $script = ssh-agent +function Start-SshAgent([switch]$Verbose) { + # If we're using the native Open-SSH, we can just interact with the service directly. + if (Start-NativeSshAgent -Verbose:$Verbose) { + return + } + + # Import old ssh-agent envs if it exists + Import-AgentEnv - # translate bash script to powershell - $script = $script -creplace '([A-Z_]+)=([^;]+).*', '$$env:$1="$2"' ` - -creplace 'echo ([^;]+);', 'echo "$1"' + [int]$agentPid = Get-SshAgent + if ($agentPid -gt 0) { + if ($Verbose) { + $agentName = Get-Process -Id $agentPid | Select-Object -ExpandProperty Name + if (!$agentName) { $agentName = "SSH Agent" } + Write-Host "$agentName is already running (pid $($agentPid))" + } + return + } - if(!(test-path "$env:USERPROFILE/.ssh")) { mkdir "$env:USERPROFILE/.ssh" > $null } + # Start ssh-agent and get output, translate to + # powershell type and write into agent env file + (& ssh-agent) ` + -creplace '([A-Z_]+)=([^;]+).*', '$$env:$1="$2"' ` + -creplace 'echo ([^;]+);' ` + -creplace 'export ([^;]+);' ` + | Out-File -FilePath $agentEnvFile -Encoding ascii -Force + # And then import new ssh-agent envs + Import-AgentEnv - $script > $envfile - . $envfile > $null + Add-SshKey -Verbose:$Verbose } -function add_keys { - $env:SSH_ASKPASS = resolve-path "$psscriptroot\..\libexec\askpass.exe" - $env:DISPLAY = "localhost:0.0" +function Test-IsSshBinaryMissing([switch]$Verbose) { + # ssh-add + $sshAdd = Get-Command "ssh-add.exe" -TotalCount 1 -ErrorAction SilentlyContinue + if (!$sshAdd) { + if ($Verbose) { + Write-Warning 'Could not find ssh-add.' + } + return $true + } - $null | ssh-add + # ssh-agent + $sshAgent = Get-Command "ssh-agent.exe" -TotalCount 1 -ErrorAction SilentlyContinue + if (!$sshAgent) { + if ($Verbose) { + Write-Warning 'Could not find ssh-agent.' + } + return $true + } } # pshazz plugin entry point function pshazz:ssh:init { - if(!(agent_is_running)) { - agent_load_env - } - - if(!(agent_is_running)) { - agent_start - add_keys - } elseif(!(agent_has_keys)) { - add_keys - } - - $global:pshazz.completions.ssh = resolve-path "$psscriptroot\..\libexec\ssh-complete.ps1" -} \ No newline at end of file + if (!(Test-Path "$env:USERPROFILE/.ssh")) { + New-Item "$env:USERPROFILE/.ssh" -ItemType Directory | Out-Null + } + + $ssh = $global:pshazz.theme.ssh + $Verbose = $false + if ($ssh.verbose -eq "true") { + $Verbose = $true + } + if (Test-IsSshBinaryMissing -Verbose:$Verbose) { return } + Start-SshAgent -Verbose:$Verbose + + # ssh TabExpansion + $scoop = Get-Command "scoop" -TotalCount 1 -ErrorAction SilentlyContinue + if ($scoop) { + $pshazzPath = Resolve-Path (Split-Path (Split-Path (scoop which pshazz))) + $global:pshazz.completions.ssh = "$pshazzPath\libexec\ssh-complete.ps1" + } +}