Last active
June 5, 2016 09:04
-
-
Save tcely/e96d179c5e96de11122d8e1390081818 to your computer and use it in GitHub Desktop.
Mac OS X ssh-askpass in AppleScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if [ -s ~/.bashrc ]; then | |
. ~/.bashrc | |
fi | |
# Additions to fix the lack of confirmation when keys are added from the Keychain | |
if [ -s ~/.ssh/ssh-agent.pid ]; then | |
. ~/.ssh/ssh-agent.pid | |
if [ -n "$SSH_AGENT_PID" ] && ! kill -0 "$SSH_AGENT_PID" &>/dev/null; then | |
rm -f ~/.ssh/ssh-agent.pid | |
unset -v SSH_AGENT_PID | |
fi | |
fi | |
if [ -z "$SSH_AGENT_PID" ]; then | |
if ssh-add -l &>/dev/null; then | |
declare _ssh_agent_bash_tmpfile="$(mktemp -q "${TMPDIR:-/tmp}/bash.XXXXXXXX" || echo ~/.ssh/bash.$$)" | |
printf > "$_ssh_agent_bash_tmpfile" -- '%s\n' 'declare -a sshKeyFiles' | |
ssh-add -l | awk >> "$_ssh_agent_bash_tmpfile" ' | |
/^[[:digit:]]+ / { | |
$1=$2=$NF=""; | |
sub(/^ /, ""); | |
sub(/ $/, ""); | |
sub(/\047/, "\047\\\047\047"); | |
printf "sshKeyFiles+=(\047%s\047)\n", $0; | |
}' | |
. "$_ssh_agent_bash_tmpfile" && | |
ssh-add </dev/null -c "${sshKeyFiles[@]}" | |
rm -f "$_ssh_agent_bash_tmpfile" | |
unset -v sshKeyFiles _ssh_agent_bash_tmpfile | |
fi | |
declare -x SSH_AGENT_PID="$(pgrep -U "$USER" -f -o -x '/usr/bin/ssh-agent -l')" | |
declare -p SSH_AGENT_PID > ~/.ssh/ssh-agent.pid | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env osascript | |
# To be installed as: /opt/X11/bin/ssh-askpass | |
# If you don't already have XQuartz installed you might need to run: | |
# sudo /usr/libexec/x11-select /opt/X11 | |
on run argv | |
set Approved to "no" | |
set notifyOnApproval to true | |
set argText to "Allow use of key in your SSH agent?" | |
if 0 < (count argv) then | |
set argText to my textJoin("\n", argv) | |
set parsedResults to my parsePrompts(argText) | |
if prompted of parsedResults or keychain of parsedResults then | |
return passphrase of parsedResults | |
end if | |
end if | |
try | |
set alertResult to display alert argText as critical buttons {"Reject", "Approve"} cancel button "Reject" giving up after 30 | |
on error number -128 | |
set alertResult to {gave up:false, button returned:"Reject"} | |
end try | |
if "Approve" is equal to button returned of alertResult then | |
set Approved to "yes" | |
set soundName to "Pop" | |
set reason to "Signing Request Authorized" | |
if not notifyOnApproval then | |
return Approved | |
end if | |
else | |
set soundName to "Basso" | |
set reason to "Access to key DENIED" | |
if gave up of alertResult then | |
set reason to "Timed Out" | |
set soundName to "Submarine" | |
end if | |
end if | |
set notifyText to my messageDisector(argText) | |
if soundName is equal to missing value then | |
display notification notifyText with title "ssh-askpass" subtitle reason | |
else | |
display notification notifyText with title "ssh-askpass" subtitle reason sound name soundName | |
end if | |
delay 1 | |
return Approved | |
end run | |
to parsePrompts(argText) | |
set foundInKeychain to false | |
set inputPassphrase to missing value | |
set promptForPassphrase to false | |
if argText contains "Enter passphrase for" then | |
try | |
set keyPath to my parseKeyFile(argText) | |
# TODO: It'd be better to do this in AppleScript directly. | |
set inputPassphrase to do shell script "security find-generic-password -w -s SSH -a " & quoted form of keyPath | |
set foundInKeychain to true | |
on error number 44 | |
set promptForPassphrase to true | |
end try | |
else if argText contains "Bad passphrase, try again for" then | |
set promptForPassphrase to true | |
end if | |
if promptForPassphrase then | |
set inputPassphrase to text returned of (display dialog argText default answer "" hidden answer true buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with title "ssh-askpass" giving up after 600) | |
end if | |
return {keychain:foundInKeychain, passphrase:inputPassphrase, prompted:promptForPassphrase} | |
end parsePrompts | |
to parseKeyFile(argText) | |
if argText contains "(will confirm each use):" then | |
set argWords to my textSplit(" ", argText) | |
set endItem to ((count argWords) - 5) | |
else | |
set argColonParts to my textSplit(":", argText) | |
set withoutEndColon to my textJoin(":", items 1 thru ((count argColonParts) - 1) of argColonParts) | |
set argWords to my textSplit(" ", withoutEndColon) | |
set endItem to (count argWords) | |
end if | |
return my textJoin(" ", items 4 thru endItem of argWords) | |
end parseKeyFile | |
to messageDisector(argText) | |
copy argText to retText | |
set LinesList to my textSplit("\n", retText) | |
set parts to my textSplit("?", item 1 of LinesList) | |
set LineOne to item 1 of parts | |
set wordsLineOne to my textSplit(" ", LineOne) | |
if 5 ≤ (count wordsLineOne) then | |
set keyFile to my textJoin(" ", items 5 thru (count wordsLineOne) of wordsLineOne) | |
set parts to my textSplit("/", keyFile) | |
set keyFile to item (count parts) of parts | |
set retText to "Key " & keyFile | |
if 1 = (count parts) then | |
set retText to retText & "." | |
end if | |
end if | |
if 1 < (count LinesList) then | |
set wordsLineTwo to my textSplit(" ", item 2 of LinesList) | |
if 3 ≤ (count wordsLineTwo) then | |
set fingerprint to my textJoin(" ", items 3 thru (count wordsLineTwo) of wordsLineTwo) | |
set retText to retText & " with fingerprint " & fingerprint | |
end if | |
end if | |
return retText | |
end messageDisector | |
to textSplit(argDelim, argStr) | |
set savedDelims to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to argDelim | |
set retList to argStr's text items | |
set AppleScript's text item delimiters to savedDelims | |
return retList | |
end textSplit | |
to textJoin(argSep, argList) | |
set savedDelims to AppleScript's text item delimiters | |
set AppleScript's text item delimiters to argSep | |
set retStr to argList as string | |
set AppleScript's text item delimiters to savedDelims | |
return retStr | |
end textJoin |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment