Something went wrong. Try again.
Scaffolds custom tools for a devenv environment
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106#!/usr/bin/env bash# ssh-open: open an authenticated SSH master connection per host, for later# `ssh HOST ...`, scp, rsync and git to reuse without a new key touch.## Each host needs a ControlPath in ~/.ssh/config (ControlMaster auto,# ControlPath ~/.ssh/cm-%C); without one nothing could reuse the master, so# the host is refused. A host's ProxyJump host is opened first, so each# host costs one touch and the jumped host rides on the jump's master.## Without a terminal (an agent, a script), the touch prompt goes to a desktop# notification (ssh-touch-notify) unless SSH_ASKPASS is already set.set -euo pipefail
usage() { cat <<'EOF'usage: ssh-open [-t TTL] HOST...
Open a master connection to each HOST (skipping those already open), thenshow their status. Touch the security key when asked.
-t TTL keep each master this long after its last use (ssh ControlPersist: 10m, 1h, yes = until ssh-close); default: the host's ssh configEOF}
ttl=""while getopts "t:h" opt; do case $opt in t) ttl=$OPTARG ;; h) usage; exit 0 ;; *) usage >&2; exit 2 ;; esacdoneshift $((OPTIND - 1))[ $# -gt 0 ] || { usage >&2; exit 2; }
state="${XDG_RUNTIME_DIR:-$HOME/.cache}/devkit-ssh/hosts"mkdir -p "$(dirname "$state")"touch "$state"
# No terminal for ssh to prompt on: show the touch request on the desktop.if [ ! -t 0 ] && [ ! -t 2 ] && [ -z "${SSH_ASKPASS:-}" ]; then SSH_ASKPASS="$(command -v ssh-touch-notify || true)" if [ -n "$SSH_ASKPASS" ]; then export SSH_ASKPASS SSH_ASKPASS_REQUIRE=force else unset SSH_ASKPASS fifi
ssh_opt() { ssh -G "$1" 2>/dev/null | awk -v k="$2" '$1 == k { print $2; exit }'; }
record() { grep -qxF "$1" "$state" || printf '%s\n' "$1" >>"$state"; }
declare -A seen=()opened=()failed=0
open_host() { local host=$1 jump j jumps [ -z "${seen[$host]:-}" ] || return 0 seen[$host]=1
local cpath cpath="$(ssh_opt "$host" controlpath)" if [ -z "$cpath" ] || [ "$cpath" = none ]; then echo "ssh-open: $host: no ControlPath in ssh config, nothing could reuse a master; add:" >&2 echo " ControlMaster auto" >&2 echo " ControlPath ~/.ssh/cm-%C" >&2 failed=1 return 0 fi
# Open bare-name jump hosts first (user@host:port forms are left to ssh). jump="$(ssh_opt "$host" proxyjump)" if [ -n "$jump" ] && [ "$jump" != none ]; then IFS=, read -ra jumps <<<"$jump" for j in "${jumps[@]}"; do case $j in *[@:/]*) ;; *) open_host "$j" ;; esac done fi
if ssh -O check "$host" 2>/dev/null; then record "$host" opened+=("$host") return 0 fi
echo "ssh-open: opening $host (touch your security key when it blinks)" >&2 local args=(-fNT -o ControlMaster=auto) [ -z "$ttl" ] || args+=(-o "ControlPersist=$ttl") # shellcheck disable=SC2029 # $host is the destination, not a remote command if DEVKIT_SSH_HOST=$host ssh "${args[@]}" "$host"; then record "$host" opened+=("$host") else echo "ssh-open: $host: could not connect" >&2 failed=1 fi}
for host in "$@"; do open_host "$host"; done
[ ${#opened[@]} -eq 0 ] || ssh-status "${opened[@]}" || failed=1exit "$failed"