QuecManager non-beta
Its about time I did this!
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/check_status.cgi
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
STATUS_FILE="/tmp/quecprofiles_status.json"
|
||||
TRACK_FILE="/tmp/quecprofiles_active"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "status_check: $1"
|
||||
}
|
||||
|
||||
# Function to output default "idle" JSON
|
||||
output_idle_json() {
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "idle",
|
||||
"message": "No active profile operations",
|
||||
"profile": "unknown",
|
||||
"progress": 0,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check if status file exists
|
||||
if [ -f "$STATUS_FILE" ]; then
|
||||
# Check if file is not empty
|
||||
if [ -s "$STATUS_FILE" ]; then
|
||||
# Cat the entire file content (more reliable than grep)
|
||||
status_content=$(cat "$STATUS_FILE")
|
||||
|
||||
# Log content for debugging
|
||||
log_message "Status file content: $status_content" "debug"
|
||||
|
||||
# Check if it looks like valid JSON
|
||||
if echo "$status_content" | grep -q "status"; then
|
||||
# Output the status file content
|
||||
cat "$STATUS_FILE"
|
||||
|
||||
# Extract status for logging only
|
||||
status=$(echo "$status_content" | sed -n 's/.*"status":"\([^"]*\)".*/\1/p')
|
||||
log_message "Status from file: $status" "info"
|
||||
exit 0
|
||||
else
|
||||
log_message "Status file exists but not valid JSON" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "Status file exists but empty" "warn"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we get here, either no file exists or it's invalid/old
|
||||
# Check if track file exists (as a fallback)
|
||||
if [ -f "$TRACK_FILE" ]; then
|
||||
status_info=$(cat "$TRACK_FILE")
|
||||
status=$(echo "$status_info" | cut -d':' -f1)
|
||||
profile=$(echo "$status_info" | cut -d':' -f2)
|
||||
progress=$(echo "$status_info" | cut -d':' -f3)
|
||||
|
||||
# Make sure the message reflects the actual status
|
||||
if [ "$status" = "success" ]; then
|
||||
message="Profile successfully applied"
|
||||
elif [ "$status" = "applying" ]; then
|
||||
message="Profile operation in progress"
|
||||
elif [ "$status" = "error" ]; then
|
||||
message="Profile operation failed"
|
||||
elif [ "$status" = "rebooting" ]; then
|
||||
message="Device is rebooting to apply changes"
|
||||
else
|
||||
message="Profile operation status: $status"
|
||||
fi
|
||||
|
||||
# Output JSON based on track file
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"profile": "$profile",
|
||||
"progress": $progress,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
log_message "Retrieved status from track file: $status" "info"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If no valid files found, output idle state
|
||||
output_idle_json
|
||||
@@ -0,0 +1,157 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/list_profiles.sh
|
||||
|
||||
# Set content type to JSON and ensure blank line is output
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "list_profiles: $1"
|
||||
# Also log to our error file
|
||||
echo "[$(date)] $level: $1" >>/tmp/list_profiles_error.log
|
||||
}
|
||||
|
||||
# Function to output JSON error response
|
||||
output_error() {
|
||||
local message="$1"
|
||||
echo "{\"status\":\"error\",\"message\":\"$message\",\"profiles\":[]}"
|
||||
log_message "$message" "error"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to sanitize string for JSON
|
||||
sanitize_for_json() {
|
||||
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed 's/\t/\\t/g' | tr -d '\r\n'
|
||||
}
|
||||
|
||||
# Check if UCI command exists
|
||||
if ! which uci >/dev/null 2>&1; then
|
||||
output_error "UCI command not found"
|
||||
fi
|
||||
|
||||
# Function to extract profiles from UCI config
|
||||
get_profiles() {
|
||||
log_message "Fetching profiles from UCI config"
|
||||
|
||||
# Check if UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "No profiles config found" "warn"
|
||||
echo "{\"status\":\"success\",\"profiles\":[]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Start JSON output
|
||||
local json_output=""
|
||||
local first=1
|
||||
local count=0
|
||||
|
||||
# Get all profile indices - make sure this succeeds
|
||||
local indices=$(uci -q show quecprofiles | grep -o '@profile\[[0-9]*\]' | sort -u)
|
||||
|
||||
# Debug output
|
||||
echo "Found indices: $indices" >>/tmp/list_profiles_error.log
|
||||
|
||||
if [ -z "$indices" ]; then
|
||||
log_message "No profile indices found" "warn"
|
||||
echo "{\"status\":\"success\",\"profiles\":[]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Process each profile
|
||||
for idx in $indices; do
|
||||
log_message "Processing profile index: $idx"
|
||||
|
||||
# Try different UCI get approaches
|
||||
local name
|
||||
name=$(uci -q get "quecprofiles.$idx.name" 2>/dev/null)
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Failed to get name for $idx, trying alternative method" "warn"
|
||||
local section=${idx#@profile[}
|
||||
section=${section%]}
|
||||
name=$(uci -q get "quecprofiles.@profile[$section].name" 2>/dev/null)
|
||||
fi
|
||||
|
||||
# Get profile details
|
||||
local iccid=$(uci -q get "quecprofiles.$idx.iccid" 2>/dev/null)
|
||||
local imei=$(uci -q get "quecprofiles.$idx.imei" 2>/dev/null)
|
||||
local apn=$(uci -q get "quecprofiles.$idx.apn" 2>/dev/null)
|
||||
local pdp_type=$(uci -q get "quecprofiles.$idx.pdp_type" 2>/dev/null)
|
||||
local lte_bands=$(uci -q get "quecprofiles.$idx.lte_bands" 2>/dev/null)
|
||||
local sa_nr5g_bands=$(uci -q get "quecprofiles.$idx.sa_nr5g_bands" 2>/dev/null)
|
||||
local nsa_nr5g_bands=$(uci -q get "quecprofiles.$idx.nsa_nr5g_bands" 2>/dev/null)
|
||||
local network_type=$(uci -q get "quecprofiles.$idx.network_type" 2>/dev/null)
|
||||
local ttl=$(uci -q get "quecprofiles.$idx.ttl" 2>/dev/null)
|
||||
local paused=$(uci -q get "quecprofiles.$idx.paused" 2>/dev/null)
|
||||
|
||||
# Debug output
|
||||
log_message "Retrieved for $idx: name=$name, iccid=$iccid, apn=$apn, paused=$paused"
|
||||
|
||||
# Skip if missing required fields
|
||||
if [ -z "$name" ] || [ -z "$iccid" ] || [ -z "$apn" ]; then
|
||||
log_message "Skipping invalid profile: $idx (missing required fields)" "warn"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Sanitize all values to ensure valid JSON
|
||||
name=$(sanitize_for_json "$name")
|
||||
iccid=$(sanitize_for_json "$iccid")
|
||||
imei=$(sanitize_for_json "${imei:-""}")
|
||||
apn=$(sanitize_for_json "$apn")
|
||||
pdp_type=$(sanitize_for_json "${pdp_type:-"IPV4V6"}")
|
||||
lte_bands=$(sanitize_for_json "${lte_bands:-""}")
|
||||
sa_nr5g_bands=$(sanitize_for_json "${sa_nr5g_bands:-""}")
|
||||
nsa_nr5g_bands=$(sanitize_for_json "${nsa_nr5g_bands:-""}")
|
||||
network_type=$(sanitize_for_json "${network_type:-"LTE"}")
|
||||
ttl=$(sanitize_for_json "${ttl:-0}")
|
||||
paused=$(sanitize_for_json "${paused:-0}")
|
||||
|
||||
# Create profile JSON
|
||||
local profile_json="{"
|
||||
profile_json="${profile_json}\"name\":\"${name}\","
|
||||
profile_json="${profile_json}\"iccid\":\"${iccid}\","
|
||||
profile_json="${profile_json}\"imei\":\"${imei}\","
|
||||
profile_json="${profile_json}\"apn\":\"${apn}\","
|
||||
profile_json="${profile_json}\"pdp_type\":\"${pdp_type}\","
|
||||
profile_json="${profile_json}\"lte_bands\":\"${lte_bands}\","
|
||||
profile_json="${profile_json}\"sa_nr5g_bands\":\"${sa_nr5g_bands}\","
|
||||
profile_json="${profile_json}\"nsa_nr5g_bands\":\"${nsa_nr5g_bands}\","
|
||||
profile_json="${profile_json}\"network_type\":\"${network_type}\","
|
||||
profile_json="${profile_json}\"ttl\":\"${ttl}\","
|
||||
profile_json="${profile_json}\"paused\":\"${paused}\""
|
||||
profile_json="${profile_json}}"
|
||||
|
||||
# Add comma if not first
|
||||
if [ $first -eq 0 ]; then
|
||||
json_output="${json_output},"
|
||||
else
|
||||
first=0
|
||||
fi
|
||||
|
||||
# Add profile to output
|
||||
json_output="${json_output}${profile_json}"
|
||||
count=$((count+1))
|
||||
done
|
||||
|
||||
# Complete the JSON response
|
||||
local response="{\"status\":\"success\",\"profiles\":[${json_output}]}"
|
||||
|
||||
# Save the response for debugging
|
||||
echo "$response" > /tmp/list_profiles_response.json
|
||||
|
||||
echo "$response"
|
||||
log_message "Found and returned $count profiles"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Start fresh error log
|
||||
echo "=== List Profiles Run $(date) ===" > /tmp/list_profiles_error.log
|
||||
|
||||
# Main execution
|
||||
{
|
||||
get_profiles
|
||||
} || {
|
||||
# Error handler
|
||||
output_error "Failed to retrieve profiles"
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_create.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "create: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to validate ICCID (simple check)
|
||||
validate_iccid() {
|
||||
local iccid="$1"
|
||||
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
|
||||
return 1
|
||||
fi
|
||||
# Check that it's only digits
|
||||
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate IMEI (simple check)
|
||||
validate_imei() {
|
||||
local imei="$1"
|
||||
if [ -z "$imei" ]; then
|
||||
return 0 # IMEI is optional
|
||||
fi
|
||||
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate band list
|
||||
validate_bands() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
return 0 # Empty is valid
|
||||
fi
|
||||
# Check format (comma-separated numbers)
|
||||
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate network type
|
||||
validate_network_type() {
|
||||
local net_type="$1"
|
||||
case "$net_type" in
|
||||
"LTE" | "NR5G" | "LTE:NR5G")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to validate PDP type
|
||||
validate_pdp_type() {
|
||||
local pdp_type="$1"
|
||||
case "$pdp_type" in
|
||||
"IP" | "IPV6" | "IPV4V6")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Add function to validate TTL
|
||||
validate_ttl() {
|
||||
local ttl="$1"
|
||||
if [ -z "$ttl" ]; then
|
||||
return 0 # Empty is valid (will be treated as 0/disabled)
|
||||
fi
|
||||
# Check that TTL is a number between 0 and 255
|
||||
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if a profile with the same name or ICCID already exists
|
||||
check_duplicate_profile() {
|
||||
local name="$1"
|
||||
local iccid="$2"
|
||||
|
||||
# Check for duplicate name
|
||||
local existing_name=$(uci -q show quecprofiles | grep ".name='$name'" | head -n 1)
|
||||
if [ -n "$existing_name" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for duplicate ICCID
|
||||
local existing_iccid=$(uci -q show quecprofiles | grep ".iccid='$iccid'" | head -n 1)
|
||||
if [ -n "$existing_iccid" ]; then
|
||||
return 2
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to create new profile
|
||||
create_profile() {
|
||||
local name="$1"
|
||||
local iccid="$2"
|
||||
local imei="$3"
|
||||
local apn="$4"
|
||||
local pdp_type="$5"
|
||||
local lte_bands="$6"
|
||||
local sa_nr5g_bands="$7"
|
||||
local nsa_nr5g_bands="$8"
|
||||
local network_type="$9"
|
||||
local ttl="${10}"
|
||||
|
||||
# Generate a unique ID for the profile
|
||||
local profile_id="profile_$(date +%s)_$(head -c 4 /dev/urandom | hexdump -e '"%x"')"
|
||||
|
||||
# Add to UCI config
|
||||
uci -q batch <<EOF
|
||||
add quecprofiles profile
|
||||
set quecprofiles.@profile[-1].name='$name'
|
||||
set quecprofiles.@profile[-1].iccid='$iccid'
|
||||
set quecprofiles.@profile[-1].imei='$imei'
|
||||
set quecprofiles.@profile[-1].apn='$apn'
|
||||
set quecprofiles.@profile[-1].pdp_type='$pdp_type'
|
||||
set quecprofiles.@profile[-1].lte_bands='$lte_bands'
|
||||
set quecprofiles.@profile[-1].sa_nr5g_bands='$sa_nr5g_bands'
|
||||
set quecprofiles.@profile[-1].nsa_nr5g_bands='$nsa_nr5g_bands'
|
||||
set quecprofiles.@profile[-1].network_type='$network_type'
|
||||
set quecprofiles.@profile[-1].ttl='$ttl'
|
||||
set quecprofiles.@profile[-1].paused='0'
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully created profile '$name' for ICCID $iccid"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to create profile '$name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received create profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
# Create initial config file
|
||||
cat >/etc/config/quecprofiles <<EOF
|
||||
config quecprofiles 'settings'
|
||||
option check_interval '60'
|
||||
option enable_autoswitch '1'
|
||||
option apply_priority '20'
|
||||
EOF
|
||||
log_message "Created initial quecprofiles config file"
|
||||
fi
|
||||
|
||||
# Get POST data
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
|
||||
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
|
||||
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
|
||||
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
|
||||
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
|
||||
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
|
||||
|
||||
log_message "Parsed JSON data for profile: $name" "debug"
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
# This is less reliable but might work for simple cases
|
||||
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
|
||||
log_message "Basic parsing for profile: $name" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
else
|
||||
# URL parameters for GET requests (less secure, but supported for testing)
|
||||
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
|
||||
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
|
||||
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
|
||||
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
|
||||
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
|
||||
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode values
|
||||
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameters" "warn"
|
||||
fi
|
||||
|
||||
# Sanitize inputs
|
||||
name=$(sanitize "${name:-}")
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
imei=$(sanitize "${imei:-}")
|
||||
apn=$(sanitize "${apn:-}")
|
||||
pdp_type=$(sanitize "${pdp_type:-IP}")
|
||||
lte_bands=$(sanitize "${lte_bands:-}")
|
||||
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
|
||||
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
|
||||
network_type=$(sanitize "${network_type:-LTE}")
|
||||
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
|
||||
|
||||
# Output debug info
|
||||
log_message "Creating profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
|
||||
|
||||
# Validate required inputs
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Profile name is missing" "error"
|
||||
output_json "error" "Profile name is required"
|
||||
fi
|
||||
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required"
|
||||
fi
|
||||
|
||||
if [ -z "$apn" ]; then
|
||||
log_message "APN is missing" "error"
|
||||
output_json "error" "APN is required"
|
||||
fi
|
||||
|
||||
# Validate input formats
|
||||
if ! validate_iccid "$iccid"; then
|
||||
log_message "Invalid ICCID format: $iccid" "error"
|
||||
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
|
||||
fi
|
||||
|
||||
if ! validate_imei "$imei"; then
|
||||
log_message "Invalid IMEI format: $imei" "error"
|
||||
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
|
||||
fi
|
||||
|
||||
if ! validate_bands "$lte_bands"; then
|
||||
log_message "Invalid LTE bands format: $lte_bands" "error"
|
||||
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$sa_nr5g_bands"; then
|
||||
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$nsa_nr5g_bands"; then
|
||||
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
|
||||
fi
|
||||
|
||||
if ! validate_network_type "$network_type"; then
|
||||
log_message "Invalid network type: $network_type" "error"
|
||||
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
|
||||
fi
|
||||
|
||||
if ! validate_pdp_type "$pdp_type"; then
|
||||
log_message "Invalid PDP type: $pdp_type" "error"
|
||||
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
|
||||
fi
|
||||
|
||||
if ! validate_ttl "$ttl"; then
|
||||
log_message "Invalid TTL value: $ttl" "error"
|
||||
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
|
||||
fi
|
||||
|
||||
# Check for duplicates
|
||||
check_duplicate_profile "$name" "$iccid"
|
||||
dup_status=$?
|
||||
if [ $dup_status -eq 1 ]; then
|
||||
log_message "Duplicate profile name: $name" "error"
|
||||
output_json "error" "A profile with this name already exists"
|
||||
elif [ $dup_status -eq 2 ]; then
|
||||
log_message "Duplicate ICCID: $iccid" "error"
|
||||
output_json "error" "A profile with this ICCID already exists"
|
||||
fi
|
||||
|
||||
# Create the profile
|
||||
if create_profile "$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$sa_nr5g_bands" "$nsa_nr5g_bands" "$network_type" "$ttl"; then
|
||||
# Trigger immediate profile application
|
||||
touch "/tmp/quecprofiles_check"
|
||||
chmod 644 "/tmp/quecprofiles_check"
|
||||
log_message "Triggered immediate profile check after creation" "info"
|
||||
|
||||
# Create profile data JSON for return - WITHOUT outer curly braces
|
||||
profile_data="\"name\":\"$name\",\"iccid\":\"$iccid\",\"imei\":\"$imei\",\"apn\":\"$apn\",\"pdp_type\":\"$pdp_type\",\"lte_bands\":\"$lte_bands\",\"sa_nr5g_bands\":\"$sa_nr5g_bands\",\"nsa_nr5g_bands\":\"$nsa_nr5g_bands\",\"network_type\":\"$network_type\",\"ttl\":\"$ttl\""
|
||||
|
||||
# Wrap the data field in curly braces inside output_json
|
||||
output_json "success" "Profile created successfully" "{$profile_data}"
|
||||
else
|
||||
output_json "error" "Failed to create profile. Please check system logs."
|
||||
fi
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_delete.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "delete: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to find profile by ICCID
|
||||
find_profile_by_iccid() {
|
||||
local iccid="$1"
|
||||
# Get all profile indices
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
if [ "$current_iccid" = "$iccid" ]; then
|
||||
echo "$profile_index"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to delete a profile
|
||||
delete_profile() {
|
||||
local profile_index="$1"
|
||||
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Delete the profile from UCI config
|
||||
uci -q batch <<EOF
|
||||
delete quecprofiles.$profile_index
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully deleted profile '$profile_name'" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to delete profile '$profile_name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received delete profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "quecprofiles config does not exist" "error"
|
||||
output_json "error" "Configuration file not found"
|
||||
fi
|
||||
|
||||
# Get ICCID from request
|
||||
iccid=""
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
elif [ -n "$QUERY_STRING" ]; then
|
||||
# URL parameters for GET or DELETE requests
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode value
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameter: iccid=$iccid" "debug"
|
||||
fi
|
||||
|
||||
# Sanitize input
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
|
||||
# Validate ICCID
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required to identify the profile"
|
||||
fi
|
||||
|
||||
# Find profile to delete
|
||||
profile_index=$(find_profile_by_iccid "$iccid")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Profile with ICCID $iccid not found" "error"
|
||||
output_json "error" "Profile not found"
|
||||
fi
|
||||
|
||||
# Get profile info for response
|
||||
profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Delete the profile
|
||||
if delete_profile "$profile_index"; then
|
||||
log_message "Profile deleted successfully: $profile_name" "info"
|
||||
output_json "success" "Profile deleted successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\"}"
|
||||
else
|
||||
log_message "Failed to delete profile: $profile_name" "error"
|
||||
output_json "error" "Failed to delete profile. Please check system logs."
|
||||
fi
|
||||
@@ -0,0 +1,392 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_edit.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CHECK_TRIGGER="/tmp/quecprofiles_check"
|
||||
APPLIED_FLAG="/tmp/quecprofiles_applied"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "edit: $1"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] edit: $1" >>/tmp/quec_profile_edit.log
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
# Debug log to file only
|
||||
echo "Generating JSON response: status=$status, message=$message" >>/tmp/quec_profile_debug.log
|
||||
echo "Data payload: $data" >>/tmp/quec_profile_debug.log
|
||||
|
||||
# Use printf for consistent output without newlines or extra characters
|
||||
printf '{"status":"%s","message":"%s","data":%s}' "$status" "$message" "$data"
|
||||
|
||||
# Add debug marker at end of JSON
|
||||
echo "" >>/tmp/quec_profile_debug.log
|
||||
echo "JSON response generated at $(date)" >>/tmp/quec_profile_debug.log
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to validate ICCID (simple check)
|
||||
validate_iccid() {
|
||||
local iccid="$1"
|
||||
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
|
||||
return 1
|
||||
fi
|
||||
# Check that it's only digits
|
||||
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate IMEI (simple check)
|
||||
validate_imei() {
|
||||
local imei="$1"
|
||||
if [ -z "$imei" ]; then
|
||||
return 0 # IMEI is optional
|
||||
fi
|
||||
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate band list
|
||||
validate_bands() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
return 0 # Empty is valid
|
||||
fi
|
||||
# Check format (comma-separated numbers)
|
||||
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate network type
|
||||
validate_network_type() {
|
||||
local net_type="$1"
|
||||
case "$net_type" in
|
||||
"LTE" | "NR5G" | "LTE:NR5G")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to validate PDP type
|
||||
validate_pdp_type() {
|
||||
local pdp_type="$1"
|
||||
case "$pdp_type" in
|
||||
"IP" | "IPV6" | "IPV4V6")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_ttl() {
|
||||
local ttl="$1"
|
||||
if [ -z "$ttl" ]; then
|
||||
return 0 # Empty is valid (will be treated as 0/disabled)
|
||||
fi
|
||||
# Check that TTL is a number between 0 and 255
|
||||
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if a profile with given ICCID exists
|
||||
find_profile_by_iccid() {
|
||||
local iccid="$1"
|
||||
# Get all profile indices
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
if [ "$current_iccid" = "$iccid" ]; then
|
||||
echo "$profile_index"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to check for duplicate name (excluding current profile)
|
||||
check_duplicate_name() {
|
||||
local name="$1"
|
||||
local current_iccid="$2"
|
||||
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Skip the current profile we're editing
|
||||
if [ "$iccid" = "$current_iccid" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$profile_name" = "$name" ]; then
|
||||
return 0 # Found duplicate
|
||||
fi
|
||||
done
|
||||
|
||||
return 1 # No duplicate
|
||||
}
|
||||
|
||||
# Function to update an existing profile
|
||||
update_profile() {
|
||||
local profile_index="$1"
|
||||
local name="$2"
|
||||
local imei="$3"
|
||||
local apn="$4"
|
||||
local pdp_type="$5"
|
||||
local lte_bands="$6"
|
||||
local sa_nr5g_bands="$7"
|
||||
local nsa_nr5g_bands="$8"
|
||||
local network_type="$9"
|
||||
local ttl="${10}"
|
||||
|
||||
# Update the profile in UCI config
|
||||
uci -q batch <<EOF
|
||||
set quecprofiles.$profile_index.name='$name'
|
||||
set quecprofiles.$profile_index.imei='$imei'
|
||||
set quecprofiles.$profile_index.apn='$apn'
|
||||
set quecprofiles.$profile_index.pdp_type='$pdp_type'
|
||||
set quecprofiles.$profile_index.lte_bands='$lte_bands'
|
||||
set quecprofiles.$profile_index.sa_nr5g_bands='$sa_nr5g_bands'
|
||||
set quecprofiles.$profile_index.nsa_nr5g_bands='$nsa_nr5g_bands'
|
||||
set quecprofiles.$profile_index.network_type='$network_type'
|
||||
set quecprofiles.$profile_index.ttl='$ttl'
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully updated profile '$name'" "info"
|
||||
|
||||
# Remove the applied flag file to force reapplication on next check
|
||||
rm -f "$APPLIED_FLAG"
|
||||
|
||||
# Touch the check trigger file to force daemon to check ASAP
|
||||
touch "$CHECK_TRIGGER"
|
||||
|
||||
log_message "Triggered profile check for updated profile '$name'" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to update profile '$name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received edit profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "quecprofiles config does not exist" "error"
|
||||
output_json "error" "Configuration file not found"
|
||||
fi
|
||||
|
||||
# Get POST data
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
|
||||
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
|
||||
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
|
||||
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
|
||||
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
|
||||
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
|
||||
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
|
||||
|
||||
log_message "Parsed JSON data for profile: $name" "debug"
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
# This is less reliable but might work for simple cases
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
|
||||
log_message "Basic parsing for profile: $name" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
else
|
||||
# URL parameters for GET requests (less secure, but supported for testing)
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
|
||||
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
|
||||
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
|
||||
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
|
||||
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
|
||||
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
|
||||
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode values
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameters" "warn"
|
||||
fi
|
||||
|
||||
# Sanitize inputs
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
name=$(sanitize "${name:-}")
|
||||
imei=$(sanitize "${imei:-}")
|
||||
apn=$(sanitize "${apn:-}")
|
||||
pdp_type=$(sanitize "${pdp_type:-IP}")
|
||||
lte_bands=$(sanitize "${lte_bands:-}")
|
||||
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
|
||||
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
|
||||
network_type=$(sanitize "${network_type:-LTE}")
|
||||
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
|
||||
|
||||
# Output debug info
|
||||
log_message "Editing profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
|
||||
|
||||
# Validate required inputs
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required to identify the profile"
|
||||
fi
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Profile name is missing" "error"
|
||||
output_json "error" "Profile name is required"
|
||||
fi
|
||||
|
||||
if [ -z "$apn" ]; then
|
||||
log_message "APN is missing" "error"
|
||||
output_json "error" "APN is required"
|
||||
fi
|
||||
|
||||
# Validate input formats
|
||||
if ! validate_iccid "$iccid"; then
|
||||
log_message "Invalid ICCID format: $iccid" "error"
|
||||
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
|
||||
fi
|
||||
|
||||
if ! validate_imei "$imei"; then
|
||||
log_message "Invalid IMEI format: $imei" "error"
|
||||
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
|
||||
fi
|
||||
|
||||
if ! validate_bands "$lte_bands"; then
|
||||
log_message "Invalid LTE bands format: $lte_bands" "error"
|
||||
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$sa_nr5g_bands"; then
|
||||
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$nsa_nr5g_bands"; then
|
||||
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
|
||||
fi
|
||||
|
||||
if ! validate_network_type "$network_type"; then
|
||||
log_message "Invalid network type: $network_type" "error"
|
||||
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
|
||||
fi
|
||||
|
||||
if ! validate_pdp_type "$pdp_type"; then
|
||||
log_message "Invalid PDP type: $pdp_type" "error"
|
||||
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
|
||||
fi
|
||||
|
||||
if ! validate_ttl "$ttl"; then
|
||||
log_message "Invalid TTL value: $ttl" "error"
|
||||
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
|
||||
fi
|
||||
|
||||
# Find profile to edit
|
||||
profile_index=$(find_profile_by_iccid "$iccid")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Profile with ICCID $iccid not found" "error"
|
||||
output_json "error" "Profile not found"
|
||||
fi
|
||||
|
||||
# Check for duplicate name
|
||||
if check_duplicate_name "$name" "$iccid"; then
|
||||
log_message "Duplicate profile name: $name" "error"
|
||||
output_json "error" "A profile with this name already exists"
|
||||
fi
|
||||
|
||||
# Update profile
|
||||
if update_profile "$profile_index" "$name" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"; then
|
||||
# Trigger immediate profile application
|
||||
touch "/tmp/quecprofiles_check"
|
||||
chmod 644 "/tmp/quecprofiles_check"
|
||||
log_message "Triggered immediate profile check after update" "info"
|
||||
|
||||
# Create a clean JSON response with properly escaped quotes
|
||||
printf '{"status":"success","message":"Profile updated successfully","data":{"name":"%s","iccid":"%s","imei":"%s","apn":"%s","pdp_type":"%s","lte_bands":"%s","nr5g_bands":"%s","network_type":"%s"}}' \
|
||||
"$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"
|
||||
|
||||
log_message "Profile updated successfully: $name" "info"
|
||||
|
||||
# Note: The conditional trigger is replaced with the direct trigger above
|
||||
else
|
||||
printf '{"status":"error","message":"Failed to update profile. Please check system logs."}'
|
||||
log_message "Failed to update profile: $name" "error"
|
||||
fi
|
||||
@@ -0,0 +1,193 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/toggle_pause.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CHECK_TRIGGER="/tmp/quecprofiles_check"
|
||||
STATUS_FILE="/tmp/quecprofiles_status.json"
|
||||
TRACK_FILE="/tmp/quecprofiles_active"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "toggle_pause: $1"
|
||||
}
|
||||
|
||||
# Function to update status file directly - used when pausing a profile
|
||||
update_status_to_paused() {
|
||||
local profile_name="$1"
|
||||
|
||||
# Create JSON status for paused profile
|
||||
cat > "$STATUS_FILE" <<EOF
|
||||
{
|
||||
"status": "paused",
|
||||
"message": "Profile is paused. Resume the profile to apply settings.",
|
||||
"profile": "$profile_name",
|
||||
"progress": 0,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create simple track file for easy checking
|
||||
echo "paused:$profile_name:0" > "$TRACK_FILE"
|
||||
chmod 644 "$TRACK_FILE" "$STATUS_FILE"
|
||||
|
||||
log_message "Status updated: paused - Profile is paused ($profile_name)" "info"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to find profile by ICCID
|
||||
find_profile_by_iccid() {
|
||||
local iccid="$1"
|
||||
# Get all profile indices
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
if [ "$current_iccid" = "$iccid" ]; then
|
||||
echo "$profile_index"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to toggle pause state
|
||||
toggle_pause_state() {
|
||||
local profile_index="$1"
|
||||
local paused="$2" # 0 or 1
|
||||
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Update the profile in UCI config
|
||||
uci -q batch <<EOF
|
||||
set quecprofiles.$profile_index.paused='$paused'
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ "$paused" = "1" ]; then
|
||||
log_message "Successfully paused profile '$profile_name'" "info"
|
||||
# Immediately update status to paused without waiting for daemon
|
||||
update_status_to_paused "$profile_name"
|
||||
return 0
|
||||
else
|
||||
log_message "Successfully resumed profile '$profile_name'" "info"
|
||||
# Touch the check trigger file to force daemon to check ASAP
|
||||
touch "$CHECK_TRIGGER"
|
||||
chmod 644 "$CHECK_TRIGGER"
|
||||
log_message "Triggered profile check for resumed profile '$profile_name'" "info"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
log_message "Failed to update pause state for profile '$profile_name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received toggle pause request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "quecprofiles config does not exist" "error"
|
||||
output_json "error" "Configuration file not found"
|
||||
fi
|
||||
|
||||
# Get POST data
|
||||
iccid=""
|
||||
paused=""
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
paused=$(echo "$POST_DATA" | jsonfilter -e '@.paused' 2>/dev/null)
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
paused=$(echo "$POST_DATA" | grep -o '"paused":[0-1]' | head -1 | cut -d':' -f2)
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
elif [ -n "$QUERY_STRING" ]; then
|
||||
# URL parameters for GET requests (for testing)
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
paused=$(echo "$QUERY_STRING" | grep -o 'paused=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode values
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameters: iccid=$iccid, paused=$paused" "debug"
|
||||
fi
|
||||
|
||||
# Sanitize inputs
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
paused=$(sanitize "${paused:-}")
|
||||
|
||||
# Validate required inputs
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required to identify the profile"
|
||||
fi
|
||||
|
||||
# Validate pause state (must be 0 or 1)
|
||||
if [ "$paused" != "0" ] && [ "$paused" != "1" ]; then
|
||||
log_message "Invalid paused state: $paused" "error"
|
||||
output_json "error" "Paused state must be 0 (resumed) or 1 (paused)"
|
||||
fi
|
||||
|
||||
# Find profile to toggle
|
||||
profile_index=$(find_profile_by_iccid "$iccid")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Profile with ICCID $iccid not found" "error"
|
||||
output_json "error" "Profile not found"
|
||||
fi
|
||||
|
||||
# Get profile info for response
|
||||
profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Toggle pause state
|
||||
if toggle_pause_state "$profile_index" "$paused"; then
|
||||
if [ "$paused" = "1" ]; then
|
||||
log_message "Profile paused successfully: $profile_name" "info"
|
||||
output_json "success" "Profile paused successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\",\"paused\":true}"
|
||||
else
|
||||
log_message "Profile resumed successfully: $profile_name" "info"
|
||||
output_json "success" "Profile resumed successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\",\"paused\":false}"
|
||||
fi
|
||||
else
|
||||
log_message "Failed to update pause state for profile: $profile_name" "error"
|
||||
output_json "error" "Failed to update profile status. Please check system logs."
|
||||
fi
|
||||
Reference in New Issue
Block a user