#!/bin/sh # Auth Guardian RPCD Backend # OAuth2 authentication and voucher system . /lib/functions.sh . /usr/share/libubox/jshn.sh # Configuration paths CONFIG_FILE="/etc/config/auth_guardian" SESSIONS_FILE="/tmp/auth_guardian_sessions.json" LOGS_FILE="/tmp/auth_guardian_logs.json" # Initialize storage init_storage() { mkdir -p /tmp/auth_guardian [ ! -f "$SESSIONS_FILE" ] && echo '[]' > "$SESSIONS_FILE" [ ! -f "$LOGS_FILE" ] && echo '[]' > "$LOGS_FILE" touch "$CONFIG_FILE" } # Generate unique ID generate_id() { head -c 8 /dev/urandom | hexdump -e '"%016x"' } # Generate voucher code generate_voucher_code() { local part1=$(head -c 3 /dev/urandom | hexdump -e '"%06x"' | tr '[:lower:]' '[:upper:]') local part2=$(head -c 3 /dev/urandom | hexdump -e '"%06x"' | tr '[:lower:]' '[:upper:]') local part3=$(head -c 3 /dev/urandom | hexdump -e '"%06x"' | tr '[:lower:]' '[:upper:]') echo "${part1}-${part2}-${part3}" } # Add log entry add_log() { local event="$1" local details="$2" local mac="$3" init_storage local timestamp=$(date -Iseconds) local entry="{\"timestamp\":\"$timestamp\",\"event\":\"$event\",\"details\":\"$details\",\"mac\":\"$mac\"}" if [ -f "$LOGS_FILE" ]; then jq ". += [$entry] | .[-500:]" "$LOGS_FILE" > "${LOGS_FILE}.tmp" 2>/dev/null && mv "${LOGS_FILE}.tmp" "$LOGS_FILE" fi } # Get system status status() { init_storage json_init config_load auth_guardian local enabled auth_method config_get enabled global enabled "0" config_get auth_method global auth_method "splash" json_add_boolean "enabled" "$enabled" json_add_string "auth_method" "$auth_method" # Count active sessions local sessions=0 if [ -f "$SESSIONS_FILE" ]; then sessions=$(jq '[.[] | select(.active == true)] | length' "$SESSIONS_FILE" 2>/dev/null || echo 0) fi json_add_int "active_sessions" "$sessions" # Count OAuth providers local provider_count=0 config_foreach count_section oauth_provider && provider_count=$? json_add_int "oauth_providers" "$provider_count" # Count vouchers local voucher_count=0 local active_vouchers=0 config_foreach count_vouchers voucher json_add_int "total_vouchers" "$voucher_count" json_add_int "active_vouchers" "$active_vouchers" # Check nodogsplash local captive_portal=0 pgrep -x nodogsplash >/dev/null 2>&1 && captive_portal=1 json_add_boolean "captive_portal_active" "$captive_portal" json_dump } count_section() { return $(( $? + 1 )) } count_vouchers() { voucher_count=$((voucher_count + 1)) local used config_get used "$1" used "0" [ "$used" = "0" ] && active_vouchers=$((active_vouchers + 1)) } # List OAuth providers list_providers() { config_load auth_guardian json_init json_add_array "providers" _add_provider() { local name client_id client_secret redirect_uri enabled config_get name "$1" name "" config_get client_id "$1" client_id "" config_get client_secret "$1" client_secret "" config_get redirect_uri "$1" redirect_uri "" config_get enabled "$1" enabled "0" json_add_object "" json_add_string "id" "$1" json_add_string "name" "$name" json_add_string "client_id" "$client_id" json_add_string "client_secret" "${client_secret:0:10}..." # Masked json_add_string "redirect_uri" "$redirect_uri" json_add_boolean "enabled" "$enabled" json_close_object } config_foreach _add_provider oauth_provider json_close_array json_dump } # Set OAuth provider set_provider() { read -r input json_load "$input" local provider name client_id client_secret redirect_uri json_get_var provider provider json_get_var name name json_get_var client_id client_id json_get_var client_secret client_secret json_get_var redirect_uri redirect_uri if [ -z "$provider" ] || [ -z "$client_id" ]; then json_init json_add_boolean "success" 0 json_add_string "error" "Provider type and client_id required" json_dump return fi # Create or update provider local section_id="oauth_$(echo $provider | tr '[:upper:]' '[:lower:]')" uci -q delete "auth_guardian.${section_id}" 2>/dev/null uci set "auth_guardian.${section_id}=oauth_provider" uci set "auth_guardian.${section_id}.name=$name" uci set "auth_guardian.${section_id}.provider=$provider" uci set "auth_guardian.${section_id}.client_id=$client_id" uci set "auth_guardian.${section_id}.client_secret=$client_secret" uci set "auth_guardian.${section_id}.redirect_uri=$redirect_uri" uci set "auth_guardian.${section_id}.enabled=1" uci commit auth_guardian add_log "provider_configured" "OAuth provider $name configured" "" json_init json_add_boolean "success" 1 json_add_string "message" "OAuth provider configured" json_add_string "provider_id" "$section_id" json_dump } # Delete OAuth provider delete_provider() { read -r input json_load "$input" local provider_id json_get_var provider_id provider_id if [ -z "$provider_id" ]; then json_init json_add_boolean "success" 0 json_add_string "error" "Provider ID required" json_dump return fi uci -q delete "auth_guardian.${provider_id}" 2>/dev/null uci commit auth_guardian add_log "provider_deleted" "OAuth provider $provider_id deleted" "" json_init json_add_boolean "success" 1 json_add_string "message" "Provider deleted" json_dump } # List all vouchers list_vouchers() { config_load auth_guardian json_init json_add_array "vouchers" _add_voucher() { local code duration_hours data_limit_mb created used note config_get code "$1" code "" config_get duration_hours "$1" duration_hours "24" config_get data_limit_mb "$1" data_limit_mb "0" config_get created "$1" created "" config_get used "$1" used "0" config_get note "$1" note "" config_get used_by "$1" used_by "" config_get used_at "$1" used_at "" json_add_object "" json_add_string "id" "$1" json_add_string "code" "$code" json_add_int "duration_hours" "$duration_hours" json_add_int "data_limit_mb" "$data_limit_mb" json_add_string "created" "$created" json_add_boolean "used" "$used" json_add_string "note" "$note" json_add_string "used_by" "$used_by" json_add_string "used_at" "$used_at" json_close_object } config_foreach _add_voucher voucher json_close_array json_dump } # Create voucher create_voucher() { read -r input json_load "$input" local duration_hours data_limit_mb note json_get_var duration_hours duration_hours json_get_var data_limit_mb data_limit_mb json_get_var note note # Defaults duration_hours=${duration_hours:-24} data_limit_mb=${data_limit_mb:-0} note=${note:-""} # Generate voucher code local code=$(generate_voucher_code) local voucher_id="v_$(generate_id)" local timestamp=$(date -Iseconds) # Save to UCI uci set "auth_guardian.${voucher_id}=voucher" uci set "auth_guardian.${voucher_id}.code=$code" uci set "auth_guardian.${voucher_id}.duration_hours=$duration_hours" uci set "auth_guardian.${voucher_id}.data_limit_mb=$data_limit_mb" uci set "auth_guardian.${voucher_id}.created=$timestamp" uci set "auth_guardian.${voucher_id}.used=0" uci set "auth_guardian.${voucher_id}.note=$note" uci commit auth_guardian add_log "voucher_created" "Voucher $code created" "" json_init json_add_boolean "success" 1 json_add_string "message" "Voucher created" json_add_string "voucher_id" "$voucher_id" json_add_string "code" "$code" json_add_int "duration_hours" "$duration_hours" json_add_int "data_limit_mb" "$data_limit_mb" json_dump } # Delete voucher delete_voucher() { read -r input json_load "$input" local voucher_id json_get_var voucher_id voucher_id if [ -z "$voucher_id" ]; then json_init json_add_boolean "success" 0 json_add_string "error" "Voucher ID required" json_dump return fi config_load auth_guardian local code config_get code "$voucher_id" code "" uci -q delete "auth_guardian.${voucher_id}" 2>/dev/null uci commit auth_guardian add_log "voucher_deleted" "Voucher $code deleted" "" json_init json_add_boolean "success" 1 json_add_string "message" "Voucher deleted" json_dump } # Validate voucher code validate_voucher() { read -r input json_load "$input" local code mac json_get_var code code json_get_var mac mac if [ -z "$code" ]; then json_init json_add_boolean "valid" 0 json_add_string "error" "Voucher code required" json_dump return fi # Search for voucher config_load auth_guardian local found=0 local voucher_id="" local duration=24 local data_limit=0 local used=0 _check_voucher() { local v_code v_used config_get v_code "$1" code "" config_get v_used "$1" used "0" if [ "$v_code" = "$code" ]; then found=1 voucher_id="$1" config_get duration "$1" duration_hours "24" config_get data_limit "$1" data_limit_mb "0" used="$v_used" fi } config_foreach _check_voucher voucher if [ "$found" = "1" ] && [ "$used" = "0" ]; then # Mark as used local timestamp=$(date -Iseconds) uci set "auth_guardian.${voucher_id}.used=1" uci set "auth_guardian.${voucher_id}.used_by=$mac" uci set "auth_guardian.${voucher_id}.used_at=$timestamp" uci commit auth_guardian # Authorize MAC via nodogsplash if available if command -v ndsctl >/dev/null 2>&1 && [ -n "$mac" ]; then ndsctl auth "$mac" >/dev/null 2>&1 fi add_log "voucher_used" "Voucher $code validated" "$mac" json_init json_add_boolean "valid" 1 json_add_string "message" "Voucher valid and activated" json_add_int "duration_hours" "$duration" json_add_int "data_limit_mb" "$data_limit" json_dump else json_init json_add_boolean "valid" 0 json_add_string "error" "Invalid or already used voucher" json_dump fi } # List active sessions list_sessions() { init_storage json_init json_add_array "sessions" # Get sessions from nodogsplash if available if command -v ndsctl >/dev/null 2>&1; then ndsctl json 2>/dev/null | jq -c '.clients[]?' 2>/dev/null | while IFS= read -r client; do local mac=$(echo "$client" | jq -r '.mac // ""') local ip=$(echo "$client" | jq -r '.ip // ""') local uploaded=$(echo "$client" | jq -r '.uploaded // 0') local downloaded=$(echo "$client" | jq -r '.downloaded // 0') local duration=$(echo "$client" | jq -r '.duration // 0') json_add_object "" json_add_string "mac" "$mac" json_add_string "ip" "$ip" json_add_int "uploaded_bytes" "$uploaded" json_add_int "downloaded_bytes" "$downloaded" json_add_int "duration_seconds" "$duration" json_add_boolean "active" 1 json_add_string "auth_method" "voucher" json_close_object done fi # Also add from sessions file if [ -f "$SESSIONS_FILE" ]; then jq -c '.[]?' "$SESSIONS_FILE" 2>/dev/null | while IFS= read -r session; do echo "$session" done fi json_close_array json_dump } # Revoke session revoke_session() { read -r input json_load "$input" local mac json_get_var mac mac if [ -z "$mac" ]; then json_init json_add_boolean "success" 0 json_add_string "error" "MAC address required" json_dump return fi # Deauth via nodogsplash if command -v ndsctl >/dev/null 2>&1; then ndsctl deauth "$mac" >/dev/null 2>&1 fi # Remove from sessions file if [ -f "$SESSIONS_FILE" ]; then jq "map(select(.mac != \"$mac\"))" "$SESSIONS_FILE" > "${SESSIONS_FILE}.tmp" 2>/dev/null && mv "${SESSIONS_FILE}.tmp" "$SESSIONS_FILE" fi add_log "session_revoked" "Session revoked for $mac" "$mac" json_init json_add_boolean "success" 1 json_add_string "message" "Session revoked" json_dump } # Get authentication logs get_logs() { read -r input json_load "$input" local limit json_get_var limit limit limit=${limit:-100} init_storage json_init json_add_array "logs" if [ -f "$LOGS_FILE" ]; then jq -c ".[-${limit}:][]" "$LOGS_FILE" 2>/dev/null | while IFS= read -r entry; do echo "$entry" done fi json_close_array json_dump } # Main dispatcher case "$1" in list) cat << 'EOF' { "status": {}, "list_providers": {}, "set_provider": { "provider": "string", "name": "string", "client_id": "string", "client_secret": "string", "redirect_uri": "string" }, "delete_provider": { "provider_id": "string" }, "list_vouchers": {}, "create_voucher": { "duration_hours": 24, "data_limit_mb": 0, "note": "string" }, "delete_voucher": { "voucher_id": "string" }, "validate_voucher": { "code": "string", "mac": "string" }, "list_sessions": {}, "revoke_session": { "mac": "string" }, "get_logs": { "limit": 100 } } EOF ;; call) case "$2" in status) status ;; list_providers) list_providers ;; set_provider) set_provider ;; delete_provider) delete_provider ;; list_vouchers) list_vouchers ;; create_voucher) create_voucher ;; delete_voucher) delete_voucher ;; validate_voucher) validate_voucher ;; list_sessions) list_sessions ;; revoke_session) revoke_session ;; get_logs) get_logs ;; *) json_init json_add_int "error" -32601 json_add_string "message" "Method not found: $2" json_dump ;; esac ;; esac