forked from
lass.pds.lassul.us/superconfig
This repository has no description
2.2 kB
66 lines
1#!/usr/bin/env bash
2# Pick one of your live SSH agents (forwarded or local) and print an export line.
3# Usage: eval "$(ssh-agent-pick)"
4
5uid=$(id -u)
6rt=${XDG_RUNTIME_DIR:-/run/user/$uid}
7cands=()
8labels=()
9
10# local agents (configs/tpm2.nix, configs/phonetpm.nix, gpg-agent, gcr).
11# rbw's agent is left out: listing keys blocks on a vault unlock prompt.
12local_socks=(
13 "$rt/ssh-tpm-agent.sock"
14 "$rt/phonetpm/agent.sock"
15 "$rt/gnupg/S.gpg-agent.ssh"
16 "$rt/gcr/ssh"
17)
18
19# newest first: sshd creates a forwarded socket when the connection is established
20while IFS= read -r -d '' line; do
21 sock=${line#* }
22 [ -S "$sock" ] || continue
23 [ "$(stat -c %u "$sock")" = "$uid" ] || continue
24 rc=0
25 # timeout: an agent waiting on an unlock prompt must not hang the picker
26 keys=$(SSH_AUTH_SOCK=$sock timeout 3 ssh-add -l 2>/dev/null) || rc=$?
27 [ "$rc" -le 1 ] || continue # 2 = cannot connect (stale), 124 = timed out
28 if [ "$rc" -eq 1 ]; then
29 keys="(no identities)"
30 else
31 keys=$(printf '%s\n' "$keys" | awk '{ $1 = $2 = ""; $NF = ""; sub(/^ +/, ""); sub(/ +$/, ""); print }' | paste -sd, -)
32 fi
33 since=$(date -d "@${line%% *}" '+%F %T')
34 case $sock in
35 "$rt"/*) kind=local ;;
36 *) kind=forwarded ;;
37 esac
38 cands+=("$sock")
39 labels+=("$since $kind $keys $sock")
40done < <({
41 # errexit applies in here: a failing find must not skip the next one
42 find /tmp/ssh-* "$HOME/.ssh/agent" -maxdepth 1 -type s \( -name 'agent.*' -o -name '*.sshd.*' \) -printf '%T@ %p\0' || true
43 find "${local_socks[@]}" -maxdepth 0 -type s -printf '%T@ %p\0' || true
44} 2>/dev/null | sort -zrn)
45
46if [ ${#cands[@]} -eq 0 ]; then
47 echo "ssh-agent-pick: no live agent found" >&2
48 exit 1
49fi
50
51if [ ${#cands[@]} -eq 1 ]; then
52 choice=${cands[0]}
53elif [ -t 2 ]; then
54 sel=$(printf '%s\n' "${labels[@]}" | fzf --height=~10 --reverse --prompt='agent> ') || exit 1
55 choice=${sel##* }
56else
57 PS3='agent> '
58 select _ in "${labels[@]}"; do
59 [ -n "${REPLY:-}" ] && [ "$REPLY" -ge 1 ] 2>/dev/null && [ "$REPLY" -le ${#cands[@]} ] || continue
60 choice=${cands[REPLY - 1]}
61 break
62 done
63fi
64
65[ -n "${choice:-}" ] || exit 1
66printf "export SSH_AUTH_SOCK='%s'\n" "$choice"