tailscale-toggle.sh hinzugefügt

This commit is contained in:
alf
2026-08-23 18:49:53 +00:00
commit 4cc204dd67

147
tailscale-toggle.sh Normal file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env bash
#
# ts-menu.sh — Interaktives Menü zum Sperren/Entsperren von Tailscale-Geräten
#
# Nutzt `gum` für die Menüführung und die Tailscale-API (authorized-Flag),
# um einzelne Geräte vom Tailnet zu trennen bzw. wieder zuzulassen.
#
# Voraussetzungen:
# - gum (https://github.com/charmbracelet/gum)
# - curl, jq
# - API-Access-Token: https://login.tailscale.com/admin/settings/keys
#
# Konfiguration in ~/.ts-toggle.conf:
# TAILSCALE_API_KEY="tskey-api-xxxxx"
# TAILSCALE_TAILNET="deine-org.ts.net"
#
# Verwendung:
# ./ts-menu.sh
set -euo pipefail
CONF_FILE="${HOME}/.ts-toggle.conf"
[[ -f "$CONF_FILE" ]] && source "$CONF_FILE"
API_KEY="${TAILSCALE_API_KEY:-}"
TAILNET="${TAILSCALE_TAILNET:-}"
API_BASE="https://api.tailscale.com/api/v2"
die() {
gum style --foreground 1 "Fehler: $*" >&2 2>/dev/null || echo "Fehler: $*" >&2
exit 1
}
command -v gum >/dev/null 2>&1 || { echo "Fehler: gum wird benötigt (https://github.com/charmbracelet/gum)."; exit 1; }
command -v curl >/dev/null 2>&1 || die "curl wird benötigt."
command -v jq >/dev/null 2>&1 || die "jq wird benötigt."
[[ -n "$API_KEY" ]] || die "TAILSCALE_API_KEY ist nicht gesetzt (siehe ~/.ts-toggle.conf)."
[[ -n "$TAILNET" ]] || die "TAILSCALE_TAILNET ist nicht gesetzt (siehe ~/.ts-toggle.conf)."
api_get() {
curl -sf -u "${API_KEY}:" "${API_BASE}/$1"
}
api_post() {
curl -sf -u "${API_KEY}:" -H "Content-Type: application/json" \
-X POST -d "$2" "${API_BASE}/$1"
}
fetch_devices() {
api_get "tailnet/${TAILNET}/devices"
}
# Zeigt eine Auswahlliste der Geräte und gibt die gewählte Device-ID aus
choose_device() {
local devices="$1"
local selection id
selection=$(echo "$devices" | jq -r '
.devices[] | [.id, .name, (if .authorized then "✅ aktiv" else "⛔ gesperrt" end)] | @tsv' \
| awk -F'\t' '{printf "%-35s %s\n", $2, $3, $1}' \
| gum choose --header "Gerät auswählen" --height 15) || return 1
[[ -z "$selection" ]] && return 1
local name
name=$(echo "$selection" | awk '{print $1}')
id=$(echo "$devices" | jq -r --arg n "$name" '.devices[] | select(.name==$n) | .id')
echo "$id"
}
action_toggle() {
local devices id name authorized new_value action_label
devices=$(gum spin --title "Lade Geräteliste..." --show-output -- bash -c "curl -sf -u '${API_KEY}:' '${API_BASE}/tailnet/${TAILNET}/devices'") \
|| { gum style --foreground 1 "Konnte Geräteliste nicht laden."; return; }
id=$(choose_device "$devices") || return
[[ -z "$id" ]] && return
name=$(echo "$devices" | jq -r --arg id "$id" '.devices[] | select(.id==$id) | .name')
authorized=$(echo "$devices" | jq -r --arg id "$id" '.devices[] | select(.id==$id) | .authorized')
if [[ "$authorized" == "true" ]]; then
new_value="false"
action_label="sperren"
else
new_value="true"
action_label="entsperren"
fi
if gum confirm "Gerät '$name' jetzt $action_label?"; then
gum spin --title "Setze Status..." -- \
curl -sf -u "${API_KEY}:" -H "Content-Type: application/json" \
-X POST -d "{\"authorized\": ${new_value}}" \
"${API_BASE}/device/${id}/authorized" >/dev/null
if [[ "$new_value" == "false" ]]; then
gum style --foreground 1 --bold "⛔ '$name' wurde gesperrt."
else
gum style --foreground 2 --bold "✅ '$name' wurde entsperrt."
fi
else
gum style --foreground 3 "Abgebrochen."
fi
}
action_list() {
local devices
devices=$(gum spin --title "Lade Geräteliste..." --show-output -- bash -c "curl -sf -u '${API_KEY}:' '${API_BASE}/tailnet/${TAILNET}/devices'") \
|| { gum style --foreground 1 "Konnte Geräteliste nicht laden."; return; }
echo "$devices" | jq -r '
["NAME","OS","STATUS"],
(.devices[] | [.name, .os, (if .authorized then "aktiv" else "GESPERRT" end)])
| @tsv' | gum table --separator=$'\t' --columns "Name,OS,Status"
}
main_menu() {
while true; do
clear
gum style --border rounded --padding "1 2" --border-foreground 6 \
"🔒 Tailscale Geräteverwaltung — Tailnet: ${TAILNET}"
choice=$(gum choose \
"Gerät sperren/entsperren" \
"Geräteliste anzeigen" \
"Beenden" \
--header "Was möchtest du tun?")
case "$choice" in
"Gerät sperren/entsperren")
action_toggle
gum input --placeholder "Enter drücken zum Fortfahren..." >/dev/null || true
;;
"Geräteliste anzeigen")
action_list
gum input --placeholder "Enter drücken zum Fortfahren..." >/dev/null || true
;;
"Beenden"|"")
echo "Bis dann 👋"
exit 0
;;
esac
done
}
main_menu