aboutsummaryrefslogtreecommitdiff
path: root/ssf
blob: dcd73229b365e893231d72cf055d083dcf60d11f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env perl
#
# Author: Guillermo Ramos <gramos@gramos.me>
# SPDX-License-Identifier: BSD-3-Clause
#
# 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".
#
################################################################################

use strict;
use warnings;

my @hosts;

my $remote_session_name = $ENV{SSF_REMOTE_USER} || $ENV{USER};

foreach my $cfgfile (glob("$ENV{HOME}/.ssh/config.d/*"), "$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') {
            if ($value =~ /"/) {
                @line_hosts = ({ _pat => $value });
            } else {
                @line_hosts = map { { _pat => $_ } } (split /\s/, $value);
            }
            push @hosts, @line_hosts;
        } elsif ($key eq 'Match') {
            @line_hosts = ();
        } else {
            $_->{$key} = $value foreach (@line_hosts);
        }
    }
}

my @hosts_no_wild = grep { not $_ =~ /\*/ } (map { $_->{_pat} } @hosts);
my %tmp = map { $_, 1 } @hosts_no_wild;
my @hosts_no_rep = keys %tmp;
my $newlined_hosts = join "\n", sort @hosts_no_rep;

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 "$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

# Save the final command to the shell history...?
#`print -s "ssh $hostname"`;

`which sshpass && which passh`;
my @cmd = ($? eq 0 ? 'passh' : 'ssh', $hostname, '-t', "sh -c \"tmux new -As $remote_session_name\"");

if (exists $ENV{TMUX}) {
    `tmux rename-window $hostname`;
    system 'passh', $hostname, '-t', "sh -c \"tmux new -As $remote_session_name\"";
    `tmux rename-window '[$hostname]'`;
} else {
    exec 'passh', $hostname;
}