aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillermo Ramos2023-11-07 12:52:40 +0100
committerGuillermo Ramos2023-11-07 12:52:45 +0100
commitd67aa99ef627fd028da6059ad5610866e6332877 (patch)
treeef51ccc4604980bef6d3c8683fd03db84908c736
parentd5d95d418f5959a70f7fe79210562f98c3fad5e9 (diff)
downloadcli-d67aa99ef627fd028da6059ad5610866e6332877.tar.gz
ssf: almost full rewrite with pass support
-rwxr-xr-xinstall.sh2
-rwxr-xr-xpassh34
-rwxr-xr-xssf86
3 files changed, 81 insertions, 41 deletions
diff --git a/install.sh b/install.sh
index 824daec..8343cde 100755
--- a/install.sh
+++ b/install.sh
@@ -1,4 +1,4 @@
#!/bin/sh
mkdir -p ~/.local/bin
-stow -v "$(dirname "$0")" -t ~/.local/bin --ignore='.*.sh$'
+stow -v "$(dirname "$0")" -t ~/.local/bin --ignore='.*\.sh$'
diff --git a/passh b/passh
new file mode 100755
index 0000000..765c0c9
--- /dev/null
+++ b/passh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+PASS_PREFIX="tc/ssh/"
+
+host="$1"
+
+# Open an "anonymous" fifo in fd 3
+pipe="$(mktemp -u)" # get random path
+mkfifo "$pipe" # create a fifo there
+exec 3<> "$pipe" # open fifo rw at fd 3
+rm "$pipe" # remove file
+
+echo -n "Trying to get password from 'pass'... "
+if pass show "${PASS_PREFIX}$host" 2> /dev/null >&3; then
+ echo "FOUND ('${PASS_PREFIX}$host'). Connecting..."
+ exec sshpass -d3 ssh -o StrictHostKeyChecking=accept-new $@
+else
+ echo "not found. Trying pubkeys..."
+ ssh -o NumberOfPasswordPrompts=0 -o StrictHostKeyChecking=accept-new $@
+ ok=$?
+ if [ "$ok" -ne 0 ]; then
+ read -rp "Connection via pubkey failed, password? " passphrase
+ echo "$passphrase" >&3
+ echo "Connecting with passphrase..."
+ sshpass -d3 ssh -o StrictHostKeyChecking=accept-new $@
+ ok=$?
+ if [ "$ok" -eq 0 ]; then
+ echo "It worked! Storing password..."
+ echo "$passphrase" | pass insert -e "${PASS_PREFIX}$host"
+ else
+ echo "Unable to connect with password either; giving up."
+ fi
+ fi
+fi
diff --git a/ssf b/ssf
index 2366b29..8915c9a 100755
--- a/ssf
+++ b/ssf
@@ -3,9 +3,11 @@
# Author: Guillermo Ramos <gramos@gramos.me>
# SPDX-License-Identifier: BSD-3-Clause
#
-# Minimalistic SSH connector which uses FZF, the SSH config and the known_hosts file
-# to show a reasonable list of machines to connect to. Then it starts or attaches to
-# a remote tmux session named as the current user.
+# Minimalistic SSH connector which uses FZF and the SSH config to show a
+# reasonable list of machines to connect to. Then it starts or attaches to
+# a remote tmux session named as the current user. It also supports passwords
+# stored in `pass`, using the wrappers "passh" (provided in this repo" and
+# "sshpass".
#
################################################################################
@@ -13,68 +15,72 @@ use strict;
use warnings;
my @hosts;
-my %aliases;
-my $remote_user = $ENV{SSF_REMOTE_USER} || $ENV{USER};
+my $remote_session_name = $ENV{SSF_REMOTE_USER} || $ENV{USER};
-open(my $ssh_config, '<', "$ENV{HOME}/.ssh/config") or die "nope";
-while (my $line = <$ssh_config>) {
- if ($line =~ /^Host ([^#\n]+)(?: # (.*))?$/) {
- push @hosts, split(/ /, $1);
- if (defined $2) {
- $aliases{$_} = $1 foreach split / /, $2;
+foreach my $cfgfile (glob "$ENV{HOME}/.ssh/*config") {
+ open(my $ssh_config, '<', $cfgfile) or die "nope";
+ my @line_hosts;
+ while (my $line = <$ssh_config>) {
+ my ($key, $value);
+ if ($line =~ /^\s*([A-Z][a-zA-Z]+)\s+([^#\n]+)/) {
+ $key = $1;
+ $value = $2;
+ }
+ next unless defined $key;
+ if ($key eq 'Host') {
+ @line_hosts = map { { _pat => $_ } } (split /\s/, $value);
+ push @hosts, @line_hosts;
+ } elsif ($key eq 'Match') {
+ @line_hosts = ();
+ } else {
+ $_->{$key} = $value foreach (@line_hosts);
}
}
}
-my $egrep_regex = join "|", grep { $_ =~ /\*/ } @hosts;
-$egrep_regex =~ s/\./\\./g;
-$egrep_regex =~ s/\*/.*/g;
+my @hosts_no_wild = grep { not $_ =~ /\*/ } (map { $_->{_pat} } @hosts);
+my $newlined_hosts = join "\n", sort @hosts_no_wild;
-my $known_hosts = `
- grep -E '$egrep_regex' ~/.ssh/known_hosts |
- cut -f1 -d" " |
- sort -u
-`;
-my $hosts_no_wild = join "\n", grep { not $_ =~ /\*/ } @hosts;
-my $aliases = join "\n", keys %aliases;
-my $prompt = @ARGV ? "@ARGV " : "";
+my $fzf_cmd = 'fzf';
+if (exists $ENV{TMUX}) {
+ if (`which fzf-tmux`) {
+ $fzf_cmd = 'fzf-tmux';
+ }
+}
+
+my $prompt = @ARGV ? "$ARGV[0] " : "";
my $selection = `
- echo -n "${known_hosts}$aliases\n$hosts_no_wild" |
- fzf -1 --print-query -q "$prompt"
+ echo -n "$newlined_hosts" |
+ $fzf_cmd -1 --print-query -q "$prompt"
`;
my $retval = $? >> 8;
my @lines = split "\n", $selection;
my $hostname;
if ($retval == 0) {
+ # 0: normal exit; a host has been selected
$hostname = $lines[1];
} elsif ($retval == 1) {
+ # 1: no match; pick user input
$hostname = $lines[0];
} else {
+ # either 2 (error) or 130 (interrupted wth C-c or ESC)
exit $retval;
}
$hostname =~ s/^\s+|\s+$//g; # Trim whitespace
-my $host = $aliases{$hostname} || $hostname; # Resolve alias
# Save the final command to the shell history...?
-#`print -s "ssh $host"`;
+#`print -s "ssh $hostname"`;
+
+`which sshpass && which passh`;
+my @cmd = ($? eq 0 ? 'passh' : 'ssh', $hostname, '-t', "sh -c \"tmux new -As $remote_session_name\"");
-# Special behavior for tmux
if (exists $ENV{TMUX}) {
- my $window_id = `tmux list-windows -F '#{window_index}' -f '#{==:#{window_name},$hostname}'`;
- $window_id =~ s/^\s+|\s+$//g; # Trim whitespace
- if ($window_id ne '') {
- # The window exists; select it instead
- `tmux select-window -t $window_id`;
- } else {
- # The window does not exist; make the connection in the current one
- # and it to the machine we're connecting to
- `tmux rename-window $hostname`;
- system 'ssh', '-t', $host, "sh -c \"tmux new -As $remote_user\"";
- `tmux rename-window '!$hostname'`;
- }
+ `tmux rename-window $hostname`;
+ system 'passh', $hostname, '-t', "sh -c \"tmux new -As $remote_session_name\"";
+ `tmux rename-window '[$hostname]'`;
} else {
- exec 'ssh', '-t', $host, "sh -c \"tmux new -As $remote_user\"";
+ exec 'passh', $hostname, '-t', "sh -c \"tmux new -As $remote_session_name\"";
}