From b61b58ce2c1371d6f904f108fa7feed3abfbe5c7 Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Wed, 8 Apr 2026 13:18:14 +0900 Subject: * MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated-commit-by: dots Signed-off-by: Robert Günzler --- bin/vpnm | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 bin/vpnm (limited to 'bin/vpnm') diff --git a/bin/vpnm b/bin/vpnm new file mode 100755 index 0000000..f09b41a --- /dev/null +++ b/bin/vpnm @@ -0,0 +1,124 @@ +#!/bin/bash +set -eu + +# shellcheck disable=2034 +description="vpn manager" + +FUZL_PROMPT=vpnm +FUZL_ICON=󰦝 +. libfuzl.sh + +main() { + local conn + + conn=$(get_current_connection) + [ -n "$conn" ] && fuzl_action_add "down" "󰦝" "Connected to $conn" + fuzl_action_add "networks" "󰾰" "Available networks" + fuzl_action_add "profile" "󱗼" "Switch profile" + + fuzl_action_menu || return +} + +# +# helpers +# + +get_emoji_flag() { + code= + # TODO: calc flag + # U\1F1E6 A + # U\200D zero-w joiner + case "$*" in + au-*) code=$'🦘' ;; + be-*) code=$'🇧🇪' ;; + br-*) code=$'🇧🇷' ;; + ca-*) code=$'🇨🇦' ;; + de-*) code=$'🇩🇪' ;; + fr-*) code=$'🇫🇷' ;; + gb-*) code=$'🇬🇧' ;; + jp-*) code=$'🇯🇵' ;; + no-*) code=$'🇳🇴' ;; + se-*) code=$'🇸🇪' ;; + us-*) code=$'🇺🇸' ;; + *tail2d6ce*) code=$'󰠜' ;; + *) code=$'🌐' ;; + esac + echo -n $code +} + +get_vpn_connections() { + ( + tailscale exit-node list | + awk '/.tail2d6ce.ts.net/{print $2, $1}' + tailscale exit-node list | + awk -F '[ ]{2,}' '/.mullvad.ts.net/{print $2, $1, ($3 "/" $4)}' | + sort -u + ) | while read -r conn ip location; do + printf '%s\t' "$ip" + printf '%s\t' "$(get_emoji_flag "$conn")" + if grep -q 'mullvad.ts.net' <<<"$conn"; then + printf '%s\t' "$location" + else + printf '%s\t' "$conn" + fi + printf '\n' + done +} + +get_current_connection() { + tailscale exit-node list | + grep -e selected | + grep -v -e Any | ( + awk '/.tail2d6ce.ts.net/{print $2, $1}' + awk -F '[ ]{2,}' '/.mullvad.ts.net/{print $2, $1, ($3 "/" $4)}' + ) | while read -r conn ip location; do + printf '%s' "$(get_emoji_flag "$conn")" + printf ' ' + if grep -q 'mullvad.ts.net' <<<"$conn"; then + printf '%s' "$location" + else + printf '%s' "$conn" + fi + done +} + +vpnup() { + fuzl_try -- tailscale set --exit-node=${1:?} + fuzl_try -- pkill -RTMIN+2 -x waybar +} + +vpndown() { + fuzl_try -- tailscale set --exit-node= + fuzl_try -- pkill -RTMIN+2 -x waybar +} + +# +# actions +# + +vpnm_down() { + fuzl_try -- vpndown +} + +vpnm_networks() { + ip=$(get_vpn_connections | + fuzl_menu $FUZL_MENU_FILTER --with-nth='{2} {3}' --accept-nth=1) + + [ -n "$ip" ] || main + fuzl_try -- vpnup "$ip" + +} + +vpnm_profile() { + profile=$(tailscale switch --list 2>/dev/null | + tail -n+2 | + awk '{printf "%s\t%s\n", $3, $2}' | + fuzl_menu $FUZL_MENU_FILTER --accept-nth=1) + + [ -n "$profile" ] || main + fuzl_try -- tailscale switch "$profile" + sleep 2 + fuzl_try -- pkill -SIGRTMIN+2 waybar +} + +main -- cgit 1.4.1