127 lines
3.3 KiB
Bash
127 lines
3.3 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# Helper: pick a relay (country [city] [hostname]) via fuzzel + jq
|
||
|
|
pick_relay() {
|
||
|
|
local api="$API_RESPONSE"
|
||
|
|
local country_list country_sel country_code
|
||
|
|
local city_list city_sel city_code loc_key
|
||
|
|
local host_list host_sel
|
||
|
|
|
||
|
|
# Build "Country Name (cc)" array
|
||
|
|
mapfile -t country_list < <(
|
||
|
|
jq -r '
|
||
|
|
.locations
|
||
|
|
| to_entries[]
|
||
|
|
| "\(.value.country) (\(.key|split("-")[0]))"
|
||
|
|
' <<<"$api" | sort -u
|
||
|
|
)
|
||
|
|
country_sel=$(printf '%s\n' "${country_list[@]}" |
|
||
|
|
fuzzel --dmenu --prompt="Select country:")
|
||
|
|
[[ -z "$country_sel" ]] && return 1
|
||
|
|
country_code=$(grep -oP '(?<=\()[^)]+(?=\))' <<<"$country_sel")
|
||
|
|
|
||
|
|
# Build "City Name (ccc)" array for that country
|
||
|
|
mapfile -t city_list < <(
|
||
|
|
jq -r --arg cc "$country_code" '
|
||
|
|
.locations
|
||
|
|
| to_entries[]
|
||
|
|
| select(.key|startswith("\($cc)-"))
|
||
|
|
| "\(.value.city) (\(.key|split("-")[1]))"
|
||
|
|
' <<<"$api" | sort -u
|
||
|
|
)
|
||
|
|
if ((${#city_list[@]})); then
|
||
|
|
city_sel=$(printf '%s\n' "${city_list[@]}" |
|
||
|
|
fuzzel --dmenu --prompt="Select city in $country_sel:")
|
||
|
|
[[ -z "$city_sel" ]] && return 1
|
||
|
|
city_code=$(grep -oP '(?<=\()[^)]+(?=\))' <<<"$city_sel")
|
||
|
|
loc_key="$country_code-$city_code"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Optional hostname picker
|
||
|
|
mapfile -t host_list < <(
|
||
|
|
jq -r --arg loc "${loc_key:-}" '
|
||
|
|
( .openvpn.relays[]
|
||
|
|
, .wireguard.relays[]
|
||
|
|
, .bridge.relays[] )
|
||
|
|
| select(.location == $loc)
|
||
|
|
| .hostname
|
||
|
|
' <<<"$api" | sort -u
|
||
|
|
)
|
||
|
|
if ((${#host_list[@]})); then
|
||
|
|
host_sel=$(printf '%s\n' "${host_list[@]}" |
|
||
|
|
fuzzel --dmenu --prompt="Select hostname (optional):")
|
||
|
|
# if they pick a hostname, we switch to pure-hostname mode
|
||
|
|
[[ -n "$host_sel" ]] && {
|
||
|
|
RELAY_CMD_ARGS=("$host_sel")
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Assemble country [city]
|
||
|
|
RELAY_CMD_ARGS=("$country_code")
|
||
|
|
[[ -n "${city_code-}" ]] && RELAY_CMD_ARGS+=("$city_code")
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
|
||
|
|
# Ensure mullvad CLI exists
|
||
|
|
if ! command -v mullvad >/dev/null 2>&1; then
|
||
|
|
echo "Mullvad CLI not found" | fuzzel --dmenu
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Fetch status and API once
|
||
|
|
STATUS_RAW=$(mullvad status 2>/dev/null || echo "Disconnected")
|
||
|
|
API_RESPONSE=$(curl -s "https://api.mullvad.net/app/v1/relays")
|
||
|
|
|
||
|
|
# Determine state and current relay (if any)
|
||
|
|
if [[ $STATUS_RAW == Connecting* ]]; then
|
||
|
|
STATE=Connecting
|
||
|
|
elif grep -q "^Connected" <<<"$STATUS_RAW"; then
|
||
|
|
STATE=Connected
|
||
|
|
else
|
||
|
|
STATE=Disconnected
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Try to parse the current relay hostname for Connected/Connecting
|
||
|
|
if [[ $STATE != Disconnected ]]; then
|
||
|
|
CURRENT_RELAY=$(grep -E 'Relay:' <<<"$STATUS_RAW" |
|
||
|
|
sed -E 's/.*Relay:[[:space:]]*//')
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Main menu
|
||
|
|
case $STATE in
|
||
|
|
Connected | Connecting)
|
||
|
|
# Offer Disconnect or Change Location
|
||
|
|
CHOICE=$(printf "Disconnect\nChange Location" |
|
||
|
|
fuzzel --dmenu --prompt="$STATE ${CURRENT_RELAY:-}")
|
||
|
|
case "$CHOICE" in
|
||
|
|
Disconnect)
|
||
|
|
mullvad disconnect
|
||
|
|
;;
|
||
|
|
"Change Location")
|
||
|
|
if pick_relay; then
|
||
|
|
mullvad relay set location "${RELAY_CMD_ARGS[@]}"
|
||
|
|
fi
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
;;
|
||
|
|
Disconnected)
|
||
|
|
# Offer Connect or Connect to Location
|
||
|
|
CHOICE=$(printf "Connect\nConnect to Location" |
|
||
|
|
fuzzel --dmenu --prompt="Disconnected")
|
||
|
|
case "$CHOICE" in
|
||
|
|
Connect)
|
||
|
|
mullvad connect
|
||
|
|
;;
|
||
|
|
"Connect to Location")
|
||
|
|
if pick_relay; then
|
||
|
|
mullvad relay set location "${RELAY_CMD_ARGS[@]}"
|
||
|
|
mullvad connect
|
||
|
|
fi
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|