#!/usr/bin/env bash # campus-login: detect a captive portal and open it in your browser, # reporting every step through the notification daemon. # # Usage: campus-login [-n|--no-wait] [-h|--help] # -n, --no-wait don't wait around to confirm you're online afterwards # # Env overrides: # PROBE_URL plain-HTTP URL that returns 204 when there is no portal # WAIT_TIMEOUT seconds to wait for connectivity after opening the portal set -u PROBE_URL=${PROBE_URL:-http://connectivitycheck.gstatic.com/generate_204} WAIT_TIMEOUT=${WAIT_TIMEOUT:-180} WAIT=1 case "${1:-}" in -n|--no-wait) WAIT=0 ;; -h|--help) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac # --- notifications ---------------------------------------------------------- # Every notification shares one "synchronous" tag so they replace each other # instead of stacking (works with dunst, mako, swaync). notify() { # notify <body> local urgency=$1 icon=$2 title=$3 body=$4 echo "$title: $body" command -v notify-send >/dev/null 2>&1 || return 0 notify-send -a campus-login -u "$urgency" -i "$icon" \ -h string:x-canonical-private-synchronous:campus-login \ -h string:x-dunst-stack-tag:campus-login \ "$title" "$body" } # --- probe ------------------------------------------------------------------ # Prints "<http_code> <redirect_url>". curl resolves relative redirects for us, # so no more grepping/sed-ing the Location header. probe() { curl -s -o /dev/null --max-time 5 \ -w '%{http_code} %{redirect_url}' "$PROBE_URL" 2>/dev/null } read -r CODE URL < <(probe) CODE=${CODE:-000} case "$CODE" in 000) notify critical network-error "No connection" \ "Couldn't reach the network. Are you connected to the Wi-Fi?" exit 2 ;; 204) notify low network-wireless "Already online" \ "No captive portal detected." exit 0 ;; esac if [[ -n "${URL:-}" ]]; then notify normal network-wireless-acquiring "Captive portal detected" "$URL" else # Some portals hijack the request and answer 200 without redirecting. # Opening a plain-HTTP page lets the portal intercept it in the browser. URL=$PROBE_URL notify normal network-wireless-acquiring "Captive portal likely" \ "Got HTTP $CODE with no redirect. Opening a test page to trigger it." fi # --- pick a browser --------------------------------------------------------- # $BROWSER is often unset when launched from a menu (aurora-run, rofi), so fall back. launch=() if [[ -n "${BROWSER:-}" ]]; then read -ra launch <<< "$BROWSER" fi if ! (( ${#launch[@]} )) || ! command -v "${launch[0]}" >/dev/null 2>&1; then launch=() for b in xdg-open firefox chromium google-chrome-stable brave; do if command -v "$b" >/dev/null 2>&1; then launch=("$b"); break; fi done fi if ! (( ${#launch[@]} )); then notify critical dialog-error "No browser found" \ "Set \$BROWSER or install one. Portal URL: $URL" exit 3 fi # Detach so the browser outlives this script (and the launcher). setsid -f "${launch[@]}" "$URL" >/dev/null 2>&1 notify normal web-browser "Opened portal" "${launch[0]} -> $URL" # --- wait for confirmation -------------------------------------------------- (( WAIT )) || exit 0 end=$((SECONDS + WAIT_TIMEOUT)) while (( SECONDS < end )); do sleep 3 read -r CODE _ < <(probe) if [[ "${CODE:-000}" == 204 ]]; then notify normal network-wireless "Connected" "You're online." exit 0 fi done notify normal network-wireless-offline "Still not online" \ "No connectivity after ${WAIT_TIMEOUT}s. The login may not have completed." exit 4