#!/bin/sh # captive portal auto-login script for TP-Link Omada (authType=0 only) # Copyright (c) 2022 Sebastian Muszynski # This is free software, licensed under the GNU General Public License v3 # set (s)hellcheck exceptions # shellcheck disable=1091,2181,3037,3043,3057 . "/lib/functions.sh" . "/usr/share/libubox/jshn.sh" urlencode() { local chr str="${1}" len="${#1}" pos=0 while [ "${pos}" -lt "${len}" ]; do chr="${str:pos:1}" case "${chr}" in [a-zA-Z0-9.~_-]) printf "%s" "${chr}" ;; " ") printf "%%20" ;; *) printf "%%%02X" "'${chr}" ;; esac pos=$((pos + 1)) done } urldecode() { echo -e "$(sed 's/+/ /g;s/%\(..\)/\\x\1/g;')" } request_parameter() { grep -oE "$1=[^&]+" | cut -d= -f2 } export LC_ALL=C export PATH="/usr/sbin:/usr/bin:/sbin:/bin" trm_captiveurl="$(uci_get travelmate global trm_captiveurl "http://detectportal.firefox.com")" trm_maxwait="$(uci_get travelmate global trm_maxwait "30")" trm_fetch="$(command -v curl) --connect-timeout $((trm_maxwait / 6)) --silent" raw_html="$(${trm_fetch} --show-error "${trm_captiveurl}")" if [ $? -ne 0 ]; then echo "The captive portal didn't respond" exit 1 fi if [ "$raw_html" = "success" ]; then echo "Internet access already available" exit 0 fi redirect_url=$(echo "$raw_html" | grep -oE 'location.href="[^\"]+"' | cut -d\" -f2) portal_baseurl=$(echo "$redirect_url" | cut -d/ -f1-4) client_mac=$(echo "$redirect_url" | request_parameter cid) ap_mac=$(echo "$redirect_url" | request_parameter ap) ssid=$(echo "$redirect_url" | request_parameter ssid | urldecode) radio_id=$(echo "$redirect_url" | request_parameter rid) url=$(echo "$redirect_url" | request_parameter u | urldecode) ${trm_fetch} "${portal_baseurl}/pubKey" | jsonfilter -e '@.result.key' > /tmp/trm-omada-pub.key if [ $? -ne 0 ]; then exit 2 fi json_init json_add_string "clientMac" "$client_mac" json_add_string "apMac" "$ap_mac" json_add_string "ssidName" "$ssid" json_add_int "radioId" "$radio_id" json_add_string "originUrl" "$url" json_close_object incomplete_auth_request="$(json_dump)" auth_type=$(${trm_fetch} "${portal_baseurl}/getPortalPageSetting" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -H 'X-Requested-With: XMLHttpRequest' \ --data-raw "$incomplete_auth_request" | jsonfilter -e '@.result.authType') if [ "$auth_type" -ne 0 ]; then echo "Unsupported auth type: $auth_type" exit 3 fi aes_key=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 16) aes_key_hex=$(printf "%s" "$aes_key" | hexdump -e '16/1 "%02x"') aes_vi=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 16) aes_vi_hex=$(printf "%s" "$aes_vi" | hexdump -e '16/1 "%02x"') rsa_encrypted_aes_secrets=$(printf "%s" "${aes_key}${aes_vi}" | openssl rsautl -encrypt -pubin -inkey /tmp/trm-omada-pub.key | base64 -w 0) rsa_encrypted_aes_secrets_urlencoded=$(urlencode "$rsa_encrypted_aes_secrets") json_load "$incomplete_auth_request" json_add_int "authType" "$auth_type" json_close_object auth_request="$(json_dump)" aes_encrypted_auth_request="$(echo "$auth_request" | openssl enc -aes-128-cbc -K "$aes_key_hex" -iv "$aes_vi_hex" -a -A)" auth_response=$(${trm_fetch} "${portal_baseurl}/auth?key=$rsa_encrypted_aes_secrets_urlencoded" \ -H 'Content-Type: text/plain' \ -H 'X-Requested-With: XMLHttpRequest' \ --data-raw "$aes_encrypted_auth_request" \ --insecure) if echo "$auth_response" | grep -q '{"errorCode":0}'; then exit 0 fi exit 255