Copy QuecManager beta to non-beta
QM BETA --> regular/non-beta
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set Content-Type for CGI script
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
TOKEN="${HTTP_AUTHORIZATION}"
|
||||
|
||||
# Read POST data
|
||||
read -r POST_DATA
|
||||
|
||||
# Debug log for generated hash
|
||||
DEBUG_LOG="/tmp/password_change.log"
|
||||
AUTH_FILE="/tmp/auth_success"
|
||||
|
||||
# Get Token from Authorization Header on Request
|
||||
if [ ! -f $AUTH_FILE ]; then
|
||||
echo "{\"error\":\"Unauthenticated Request\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$TOKEN" ] || "${TOKEN}" = "" || [ $(grep "${TOKEN}" "${AUTH_FILE}" | wc -l) -eq 0 ]; then
|
||||
echo "{\"response\": { \"status\": \"error\", \"raw_output\": \"Not Authorized\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Not Authorized\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if token is within 2 hours
|
||||
TOKEN_LINE=$(grep "${TOKEN}" "${AUTH_FILE}")
|
||||
TOKEN_DATE=$(echo "$TOKEN_LINE" | awk '{print $1}' | sed 's/T/ /')
|
||||
TOKEN_TIME=$(date -d "$TOKEN_DATE" +%s 2>/dev/null)
|
||||
NOW_TIME=$(date +%s)
|
||||
MAX_AGE=$((2 * 3600)) # 2 hours in seconds
|
||||
|
||||
if [ -z "$TOKEN_TIME" ] || [ $((NOW_TIME - TOKEN_TIME)) -gt $MAX_AGE ]; then
|
||||
echo "{ \"response\": { \"status\": \"error\", \"raw_output\": \"Token expired. Reauthenticate to get new token.\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Token expired\"}"
|
||||
# Cleanup/Remove token from file
|
||||
sed -i -e "s/.*${TOKEN}.*//g" /tmp/auth_success 2>/dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Extract the passwords from POST data (URL encoded)
|
||||
USER="root"
|
||||
OLD_PASSWORD=$(echo "$POST_DATA" | grep -o 'oldPassword=[^&]*' | cut -d= -f2-)
|
||||
NEW_PASSWORD=$(echo "$POST_DATA" | grep -o 'newPassword=[^&]*' | cut -d= -f2-)
|
||||
|
||||
# URL-decode the passwords (replace + with space and decode %XX)
|
||||
urldecode() {
|
||||
local encoded="${1//+/ }"
|
||||
printf '%b' "${encoded//%/\\x}"
|
||||
}
|
||||
|
||||
OLD_PASSWORD=$(urldecode "$OLD_PASSWORD")
|
||||
NEW_PASSWORD=$(urldecode "$NEW_PASSWORD")
|
||||
|
||||
# Basic validation to reject & and $ characters
|
||||
if echo "$OLD_PASSWORD$NEW_PASSWORD" | grep -q '[&$]'; then
|
||||
echo '{"state":"failed","message":"Password contains forbidden characters (& or $)"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the hashed password from /etc/shadow for the specified user
|
||||
USER_SHADOW_ENTRY=$(grep "^$USER:" /etc/shadow)
|
||||
|
||||
if [ -z "$USER_SHADOW_ENTRY" ]; then
|
||||
echo '{"state":"failed","message":"User not found"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the password hash (second field, colon-separated)
|
||||
USER_HASH=$(echo "$USER_SHADOW_ENTRY" | cut -d: -f2)
|
||||
|
||||
# Extract the salt (MD5 uses the $1$ prefix followed by the salt)
|
||||
SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
|
||||
|
||||
# Generate hash from old password using the same salt
|
||||
OLD_GENERATED_HASH=$(printf '%s' "$OLD_PASSWORD" | openssl passwd -1 -salt "$SALT" -stdin)
|
||||
|
||||
# Verify old password
|
||||
if [ "$OLD_GENERATED_HASH" != "$USER_HASH" ]; then
|
||||
echo '{"state":"failed","message":"Current password is incorrect"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a temporary file for the new password
|
||||
PASS_FILE=$(mktemp)
|
||||
chmod 600 "$PASS_FILE"
|
||||
|
||||
# Write the new password twice (for confirmation)
|
||||
printf '%s\n%s\n' "$NEW_PASSWORD" "$NEW_PASSWORD" > "$PASS_FILE"
|
||||
|
||||
# Change password using passwd command
|
||||
ERROR_OUTPUT=$(passwd "$USER" < "$PASS_FILE" 2>&1)
|
||||
RESULT=$?
|
||||
|
||||
# Log the operation
|
||||
echo "Password change attempt. Result: $RESULT. Time: $(date)" >> "$DEBUG_LOG"
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo "Error output: $ERROR_OUTPUT" >> "$DEBUG_LOG"
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm -f "$PASS_FILE"
|
||||
|
||||
# Return result
|
||||
if [ $RESULT -eq 0 ]; then
|
||||
echo '{"state":"success","message":"Password changed successfully"}'
|
||||
else
|
||||
echo '{"state":"failed","message":"Failed to change password"}'
|
||||
fi
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Send CGI headers first
|
||||
echo "Content-Type: application/json"
|
||||
echo "Cache-Control: no-cache"
|
||||
echo
|
||||
|
||||
# Simple script to force a reboot of the system
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
# Function to force reboot
|
||||
force_reboot() {
|
||||
if command -v reboot >/dev/null 2>&1; then
|
||||
reboot
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
if force_reboot; then
|
||||
output_json "success" "System is rebooting"
|
||||
else
|
||||
output_json "error" "Reboot command not found or failed"
|
||||
fi
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,375 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Smart Measurement Units Configuration Script
|
||||
# Manages distance unit preferences (km/mi) with automatic timezone-based defaults
|
||||
# Author: dr-dolomite
|
||||
# Date: 2025-08-04
|
||||
|
||||
# Set content type and CORS headers
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CONFIG_DIR="/etc/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/measurement_units.conf"
|
||||
LOG_FILE="/tmp/measurement_units.log"
|
||||
|
||||
# Logging function
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error response function
|
||||
send_error() {
|
||||
local error_code="$1"
|
||||
local error_message="$2"
|
||||
log_message "ERROR: $error_message"
|
||||
echo "{\"status\":\"error\",\"code\":\"$error_code\",\"message\":\"$error_message\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success response function
|
||||
send_success() {
|
||||
local message="$1"
|
||||
local data="$2"
|
||||
log_message "SUCCESS: $message"
|
||||
if [ -n "$data" ]; then
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\",\"data\":$data}"
|
||||
else
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure configuration directory exists
|
||||
ensure_config_directory() {
|
||||
if [ ! -d "$CONFIG_DIR" ]; then
|
||||
log_message "Creating directory: $CONFIG_DIR"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
if [ $? -ne 0 ]; then
|
||||
# Try to use a fallback location in /tmp
|
||||
CONFIG_DIR="/tmp/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/measurement_units.conf"
|
||||
log_message "Fallback to alternative location: $CONFIG_DIR"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
if [ $? -ne 0 ]; then
|
||||
send_error "DIRECTORY_ERROR" "Failed to create configuration directory"
|
||||
fi
|
||||
fi
|
||||
chmod 755 "$CONFIG_DIR"
|
||||
log_message "Created configuration directory: $CONFIG_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if the country uses imperial or metric system based on timezone
|
||||
get_default_unit() {
|
||||
# Get timezone from OpenWrt system - use uci as primary method
|
||||
local timezone=""
|
||||
|
||||
# Primary method: Use uci command (standard OpenWrt way)
|
||||
if command -v uci >/dev/null 2>&1; then
|
||||
timezone=$(uci -q get system.@system[0].zonename)
|
||||
if [ -z "$timezone" ]; then
|
||||
timezone=$(uci -q get system.@system[0].timezone)
|
||||
fi
|
||||
log_message "Detected timezone using uci command: $timezone"
|
||||
fi
|
||||
|
||||
# Fallback method: Parse OpenWrt config file directly
|
||||
if [ -z "$timezone" ] && [ -f "/etc/config/system" ]; then
|
||||
timezone=$(grep -o "option zonename '[^']*'" /etc/config/system | sed "s/option zonename '//;s/'//")
|
||||
|
||||
if [ -z "$timezone" ]; then
|
||||
timezone=$(grep -o "option timezone '[^']*'" /etc/config/system | sed "s/option timezone '//;s/'//")
|
||||
fi
|
||||
log_message "Detected timezone from OpenWrt config file: $timezone"
|
||||
fi
|
||||
|
||||
# Additional fallback methods
|
||||
if [ -z "$timezone" ]; then
|
||||
# Try TZ environment variable
|
||||
if [ -n "$TZ" ]; then
|
||||
timezone="$TZ"
|
||||
log_message "Detected timezone from TZ environment variable: $timezone"
|
||||
# Try /etc/TZ file
|
||||
elif [ -f "/etc/TZ" ]; then
|
||||
timezone=$(cat /etc/TZ)
|
||||
log_message "Detected timezone from /etc/TZ file: $timezone"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If still no timezone, use a default
|
||||
if [ -z "$timezone" ]; then
|
||||
timezone="Unknown"
|
||||
log_message "Warning: Could not detect timezone, using default (km)"
|
||||
fi
|
||||
|
||||
# Countries and territories that primarily use imperial system (miles)
|
||||
# Based on current usage as of 2025:
|
||||
# - United States (including territories)
|
||||
# - Liberia
|
||||
# - Myanmar/Burma (mixed usage, but officially imperial for distances)
|
||||
# - UK uses miles for road distances (though metric for most other measurements)
|
||||
# - Some British territories and dependencies
|
||||
case "$timezone" in
|
||||
# United States and territories - comprehensive timezone coverage
|
||||
*America/New_York*|*America/Chicago*|*America/Denver*|*America/Los_Angeles*|*America/Phoenix*|*America/Anchorage*|*America/Honolulu*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US major cities)"
|
||||
;;
|
||||
# All Americas timezones that are US-based
|
||||
*America/Adak*|*America/Juneau*|*America/Metlakatla*|*America/Nome*|*America/Sitka*|*America/Yakutat*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US Alaska)"
|
||||
;;
|
||||
# US territories in Pacific
|
||||
*Pacific/Honolulu*|*Pacific/Johnston*|*Pacific/Midway*|*Pacific/Wake*|*HST*|*Pacific/Samoa*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US Pacific territories)"
|
||||
;;
|
||||
# US territories in other regions
|
||||
*America/Puerto_Rico*|*America/Virgin*|*Atlantic/Bermuda*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US territories)"
|
||||
;;
|
||||
# General US timezone patterns
|
||||
*America/*EDT*|*America/*EST*|*America/*CDT*|*America/*CST*|*America/*MDT*|*America/*MST*|*America/*PDT*|*America/*PST*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US timezone abbreviations)"
|
||||
;;
|
||||
# Simple timezone abbreviations commonly used in US systems
|
||||
*EST*|*CST*|*MST*|*PST*|*EDT*|*CDT*|*MDT*|*PDT*|*AKST*|*AKDT*|*HST*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (US timezone codes)"
|
||||
;;
|
||||
# United Kingdom - uses miles for road distances
|
||||
*Europe/London*|*GMT*|*BST*|*Europe/Belfast*|*Europe/Edinburgh*|*Europe/Cardiff*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (UK)"
|
||||
;;
|
||||
# British territories and dependencies that use miles
|
||||
*Atlantic/Stanley*|*Indian/Chagos*|*Europe/Gibraltar*|*Atlantic/South_Georgia*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (British territories)"
|
||||
;;
|
||||
# Liberia
|
||||
*Africa/Monrovia*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (Liberia)"
|
||||
;;
|
||||
# Myanmar/Burma (mixed usage but officially uses imperial for some measurements)
|
||||
*Asia/Yangon*|*Asia/Rangoon*)
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (Myanmar)"
|
||||
;;
|
||||
# OpenWrt config format with spaces (common in some router configurations)
|
||||
"America/New York"|"America/Los Angeles"|"America/Chicago"|"America/Denver"|"America/Phoenix"|"America/Anchorage"|"Europe/London")
|
||||
echo "mi"
|
||||
log_message "Default unit based on timezone ($timezone): miles (space-separated format)"
|
||||
;;
|
||||
# Default to metric for all other countries/territories
|
||||
*)
|
||||
echo "km"
|
||||
log_message "Default unit based on timezone ($timezone): kilometers (metric country)"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get current measurement unit
|
||||
get_measurement_unit() {
|
||||
# If config file exists, read from it
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
unit=$(grep "^DISTANCE_UNIT=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||
if [ -n "$unit" ]; then
|
||||
echo "$unit"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# If no config or empty config, determine default based on timezone
|
||||
get_default_unit
|
||||
}
|
||||
|
||||
# Save measurement unit to config file
|
||||
save_measurement_unit() {
|
||||
local unit="$1"
|
||||
ensure_config_directory
|
||||
|
||||
# Create or update config file
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Update existing file
|
||||
sed -i "s/^DISTANCE_UNIT=.*$/DISTANCE_UNIT=$unit/" "$CONFIG_FILE"
|
||||
if [ $? -ne 0 ]; then
|
||||
# If sed fails (e.g., no match), append the setting
|
||||
echo "DISTANCE_UNIT=$unit" >> "$CONFIG_FILE"
|
||||
fi
|
||||
else
|
||||
# Create new file
|
||||
echo "DISTANCE_UNIT=$unit" > "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
chmod 644 "$CONFIG_FILE"
|
||||
log_message "Saved distance unit: $unit"
|
||||
}
|
||||
|
||||
# Delete measurement unit configuration
|
||||
delete_measurement_unit() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Remove the DISTANCE_UNIT line
|
||||
sed -i '/^DISTANCE_UNIT=/d' "$CONFIG_FILE"
|
||||
log_message "Deleted distance unit configuration"
|
||||
|
||||
# If file is empty after deletion, remove it
|
||||
if [ ! -s "$CONFIG_FILE" ]; then
|
||||
rm -f "$CONFIG_FILE"
|
||||
log_message "Removed empty config file"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle GET request - Retrieve measurement unit preference
|
||||
handle_get() {
|
||||
log_message "GET request received"
|
||||
|
||||
# Check if this is a debug request
|
||||
if echo "$QUERY_STRING" | grep -q "debug=1"; then
|
||||
# Return diagnostic information
|
||||
local timezone_info=""
|
||||
|
||||
if command -v uci >/dev/null 2>&1; then
|
||||
timezone_info="$timezone_info\"uci_system_zonename\": \"$(uci -q get system.@system[0].zonename || echo 'Not found')\","
|
||||
timezone_info="$timezone_info\"uci_system_timezone\": \"$(uci -q get system.@system[0].timezone || echo 'Not found')\","
|
||||
else
|
||||
timezone_info="$timezone_info\"uci\": \"Command not found\","
|
||||
fi
|
||||
|
||||
if [ -f "/etc/config/system" ]; then
|
||||
timezone_info="$timezone_info\"openwrt_config\": \"$(cat /etc/config/system | grep -E 'zonename|timezone' | tr '\n' ' ' | sed 's/"/\\"/g')\","
|
||||
else
|
||||
timezone_info="$timezone_info\"openwrt_config\": \"Not found\","
|
||||
fi
|
||||
|
||||
if [ -n "$TZ" ]; then
|
||||
timezone_info="$timezone_info\"TZ_env\": \"$TZ\","
|
||||
else
|
||||
timezone_info="$timezone_info\"TZ_env\": \"Not set\","
|
||||
fi
|
||||
|
||||
if [ -f "/etc/TZ" ]; then
|
||||
timezone_info="$timezone_info\"etc_TZ\": \"$(cat /etc/TZ)\","
|
||||
else
|
||||
timezone_info="$timezone_info\"etc_TZ\": \"Not found\","
|
||||
fi
|
||||
|
||||
# Get default unit
|
||||
local default_unit=$(get_default_unit)
|
||||
|
||||
# Remove trailing comma
|
||||
timezone_info=$(echo "$timezone_info" | sed 's/,$//')
|
||||
|
||||
send_success "Debug information" "{$timezone_info, \"default_unit\": \"$default_unit\"}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get current unit (from config or default)
|
||||
local unit=$(get_measurement_unit)
|
||||
|
||||
# Check if it's from config or default
|
||||
local is_default=true
|
||||
if [ -f "$CONFIG_FILE" ] && grep -q "^DISTANCE_UNIT=" "$CONFIG_FILE"; then
|
||||
is_default=false
|
||||
fi
|
||||
|
||||
send_success "Measurement unit retrieved" "{\"unit\":\"$unit\",\"isDefault\":$is_default}"
|
||||
}
|
||||
|
||||
# Handle POST request - Update measurement unit preference
|
||||
handle_post() {
|
||||
log_message "POST request received"
|
||||
|
||||
# Read POST data
|
||||
local content_length=${CONTENT_LENGTH:-0}
|
||||
if [ "$content_length" -gt 0 ]; then
|
||||
local post_data=$(dd bs=$content_length count=1 2>/dev/null)
|
||||
log_message "Received POST data: $post_data"
|
||||
|
||||
# Multiple approaches to parse JSON, for robustness across various OpenWrt versions
|
||||
# Approach 1: Simple regex extraction
|
||||
local unit=$(echo "$post_data" | sed -n 's/.*"unit"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
|
||||
# Approach 2: grep + cut extraction
|
||||
if [ -z "$unit" ]; then
|
||||
unit=$(echo "$post_data" | grep -o '"unit":"[^"]*"' | cut -d'"' -f4)
|
||||
fi
|
||||
|
||||
# Approach 3: Very basic extraction - look for km or mi in the payload
|
||||
if [ -z "$unit" ]; then
|
||||
if echo "$post_data" | grep -q '"km"'; then
|
||||
unit="km"
|
||||
elif echo "$post_data" | grep -q '"mi"'; then
|
||||
unit="mi"
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "Received unit: $unit"
|
||||
|
||||
# Validate unit
|
||||
if [ "$unit" = "km" ] || [ "$unit" = "mi" ]; then
|
||||
save_measurement_unit "$unit"
|
||||
send_success "Measurement unit updated successfully" "{\"unit\":\"$unit\"}"
|
||||
else
|
||||
send_error "INVALID_UNIT" "Invalid unit provided. Must be 'km' or 'mi'."
|
||||
fi
|
||||
else
|
||||
send_error "NO_DATA" "No data provided"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle DELETE request - Reset to default (delete configuration)
|
||||
handle_delete() {
|
||||
log_message "DELETE request received"
|
||||
|
||||
if delete_measurement_unit; then
|
||||
# Get the default unit that will be used
|
||||
local default_unit=$(get_default_unit)
|
||||
send_success "Measurement unit reset to default" "{\"unit\":\"$default_unit\",\"isDefault\":true}"
|
||||
else
|
||||
send_error "NOT_FOUND" "Measurement unit configuration not found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle OPTIONS request for CORS preflight
|
||||
handle_options() {
|
||||
log_message "OPTIONS request received"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo "Access-Control-Max-Age: 86400"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_message "Measurement units script called with method: ${REQUEST_METHOD:-GET}"
|
||||
|
||||
# Handle different HTTP methods
|
||||
case "${REQUEST_METHOD:-GET}" in
|
||||
GET)
|
||||
handle_get
|
||||
;;
|
||||
POST)
|
||||
handle_post
|
||||
;;
|
||||
DELETE)
|
||||
handle_delete
|
||||
;;
|
||||
OPTIONS)
|
||||
handle_options
|
||||
;;
|
||||
*)
|
||||
send_error "METHOD_NOT_ALLOWED" "HTTP method ${REQUEST_METHOD} not supported"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,301 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Memory Settings Configuration Script
|
||||
# Manages memory service (enable/disable) and daemon settings with dynamic service management
|
||||
|
||||
# Handle OPTIONS request first
|
||||
if [ "${REQUEST_METHOD:-GET}" = "OPTIONS" ]; then
|
||||
echo "Content-Type: text/plain"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo "Access-Control-Max-Age: 86400"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Set content type and CORS headers
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo ""
|
||||
|
||||
# Configuration paths
|
||||
CONFIG_DIR="/etc/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/memory_settings.conf"
|
||||
FALLBACK_CONFIG_DIR="/tmp/quecmanager/settings"
|
||||
FALLBACK_CONFIG_FILE="$FALLBACK_CONFIG_DIR/memory_settings.conf"
|
||||
LOG_FILE="/tmp/memory_settings.log"
|
||||
SERVICES_INIT="/etc/init.d/quecmanager_services"
|
||||
|
||||
# Logging function
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error response function
|
||||
send_error() {
|
||||
local error_code="$1"
|
||||
local error_message="$2"
|
||||
log_message "ERROR: $error_message"
|
||||
echo "{\"status\":\"error\",\"code\":\"$error_code\",\"message\":\"$error_message\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success response function
|
||||
send_success() {
|
||||
local message="$1"
|
||||
local data="$2"
|
||||
log_message "SUCCESS: $message"
|
||||
if [ -n "$data" ]; then
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\",\"data\":$data}"
|
||||
else
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get current configuration
|
||||
get_config() {
|
||||
# Defaults
|
||||
ENABLED="false"
|
||||
INTERVAL="1"
|
||||
|
||||
# Try primary config first, then fallback
|
||||
local config_to_read=""
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
config_to_read="$CONFIG_FILE"
|
||||
elif [ -f "$FALLBACK_CONFIG_FILE" ]; then
|
||||
config_to_read="$FALLBACK_CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if [ -n "$config_to_read" ]; then
|
||||
local enabled_val=$(grep "^MEMORY_ENABLED=" "$config_to_read" 2>/dev/null | tail -n1 | cut -d'=' -f2)
|
||||
local interval_val=$(grep "^MEMORY_INTERVAL=" "$config_to_read" 2>/dev/null | tail -n1 | cut -d'=' -f2)
|
||||
|
||||
case "$enabled_val" in
|
||||
true|1|on|yes|enabled) ENABLED="true" ;;
|
||||
*) ENABLED="false" ;;
|
||||
esac
|
||||
|
||||
if echo "$interval_val" | grep -qE '^[0-9]+$' && [ "$interval_val" -ge 1 ] && [ "$interval_val" -le 10 ]; then
|
||||
INTERVAL="$interval_val"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Save configuration
|
||||
save_config() {
|
||||
local enabled="$1"
|
||||
local interval="$2"
|
||||
|
||||
# Try primary location first
|
||||
if mkdir -p "$CONFIG_DIR" 2>/dev/null && [ -w "$CONFIG_DIR" ]; then
|
||||
{
|
||||
echo "MEMORY_ENABLED=$enabled"
|
||||
echo "MEMORY_INTERVAL=$interval"
|
||||
} > "$CONFIG_FILE" && chmod 644 "$CONFIG_FILE" 2>/dev/null
|
||||
log_message "Saved config to primary location: enabled=$enabled, interval=$interval"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback to tmp
|
||||
mkdir -p "$FALLBACK_CONFIG_DIR" 2>/dev/null
|
||||
{
|
||||
echo "MEMORY_ENABLED=$enabled"
|
||||
echo "MEMORY_INTERVAL=$interval"
|
||||
} > "$FALLBACK_CONFIG_FILE" && chmod 644 "$FALLBACK_CONFIG_FILE" 2>/dev/null
|
||||
log_message "Saved config to fallback location: enabled=$enabled, interval=$interval"
|
||||
}
|
||||
|
||||
# Add memory daemon to services init script
|
||||
add_memory_daemon_to_services() {
|
||||
if [ ! -f "$SERVICES_INIT" ]; then
|
||||
log_message "Services init file not found: $SERVICES_INIT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if memory daemon is already present
|
||||
if grep -q "memory_daemon.sh" "$SERVICES_INIT" 2>/dev/null; then
|
||||
log_message "Memory daemon already present in services"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create a temporary file with the memory daemon block
|
||||
local temp_file="/tmp/services_temp_$$"
|
||||
|
||||
# Find the line before "echo \"All QuecManager services Started\"" and insert memory daemon
|
||||
awk '
|
||||
/echo "All QuecManager services Started"/ {
|
||||
print " # Start memory daemon"
|
||||
print " echo \"Starting Memory Daemon...\""
|
||||
print " procd_open_instance"
|
||||
print " procd_set_param command /www/cgi-bin/services/memory_daemon.sh"
|
||||
print " procd_set_param respawn"
|
||||
print " procd_set_param stdout 1"
|
||||
print " procd_set_param stderr 1"
|
||||
print " procd_close_instance"
|
||||
print " echo \"Memory Daemon started\""
|
||||
print ""
|
||||
}
|
||||
{ print }
|
||||
' "$SERVICES_INIT" > "$temp_file"
|
||||
|
||||
if [ -s "$temp_file" ]; then
|
||||
mv "$temp_file" "$SERVICES_INIT"
|
||||
chmod +x "$SERVICES_INIT"
|
||||
log_message "Added memory daemon to services init script"
|
||||
return 0
|
||||
else
|
||||
rm -f "$temp_file"
|
||||
log_message "Failed to add memory daemon to services"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove memory daemon from services init script
|
||||
remove_memory_daemon_from_services() {
|
||||
if [ ! -f "$SERVICES_INIT" ]; then
|
||||
log_message "Services init file not found: $SERVICES_INIT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if memory daemon is present
|
||||
if ! grep -q "memory_daemon.sh" "$SERVICES_INIT" 2>/dev/null; then
|
||||
log_message "Memory daemon not present in services"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove the memory daemon block (from "# Start memory daemon" to the empty line after)
|
||||
local temp_file="/tmp/services_temp_$$"
|
||||
|
||||
awk '
|
||||
/# Start memory daemon/ { skip=1; next }
|
||||
skip && /^$/ { skip=0; next }
|
||||
!skip { print }
|
||||
' "$SERVICES_INIT" > "$temp_file"
|
||||
|
||||
if [ -s "$temp_file" ]; then
|
||||
mv "$temp_file" "$SERVICES_INIT"
|
||||
chmod +x "$SERVICES_INIT"
|
||||
log_message "Removed memory daemon from services init script"
|
||||
return 0
|
||||
else
|
||||
rm -f "$temp_file"
|
||||
log_message "Failed to remove memory daemon from services"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Restart QuecManager services
|
||||
restart_services() {
|
||||
log_message "Restarting QuecManager services..."
|
||||
|
||||
# Stop services
|
||||
if [ -x "$SERVICES_INIT" ]; then
|
||||
"$SERVICES_INIT" stop >/dev/null 2>&1
|
||||
sleep 2
|
||||
"$SERVICES_INIT" start >/dev/null 2>&1
|
||||
log_message "Services restarted successfully"
|
||||
return 0
|
||||
else
|
||||
log_message "Cannot restart services - init script not found or not executable"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if memory daemon is running
|
||||
is_memory_daemon_running() {
|
||||
pgrep -f "memory_daemon.sh" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Handle POST request - Update memory setting
|
||||
handle_post() {
|
||||
log_message "POST request received"
|
||||
|
||||
local content_length=${CONTENT_LENGTH:-0}
|
||||
if [ "$content_length" -eq 0 ]; then
|
||||
send_error "NO_DATA" "No data provided"
|
||||
fi
|
||||
|
||||
# Read POST data
|
||||
local post_data=$(dd bs=$content_length count=1 2>/dev/null)
|
||||
log_message "Received POST data: $post_data"
|
||||
|
||||
# Parse enabled and interval from JSON
|
||||
local enabled=$(echo "$post_data" | sed -n 's/.*"enabled"[[:space:]]*:[[:space:]]*\([^,}]*\).*/\1/p' | tr -d ' "')
|
||||
local interval=$(echo "$post_data" | sed -n 's/.*"interval"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p')
|
||||
|
||||
# Set defaults if not provided
|
||||
[ -z "$enabled" ] && enabled="false"
|
||||
[ -z "$interval" ] && interval="1"
|
||||
|
||||
# Validate input
|
||||
case "$enabled" in
|
||||
true|false) ;;
|
||||
*) send_error "INVALID_SETTING" "Invalid enabled value. Must be true or false." ;;
|
||||
esac
|
||||
|
||||
if ! echo "$interval" | grep -qE '^[0-9]+$' || [ "$interval" -lt 1 ] || [ "$interval" -gt 10 ]; then
|
||||
send_error "INVALID_INTERVAL" "Interval must be a number between 1 and 10 seconds."
|
||||
fi
|
||||
|
||||
# Get current config to compare
|
||||
get_config
|
||||
local prev_enabled="$ENABLED"
|
||||
local prev_interval="$INTERVAL"
|
||||
|
||||
# Save new configuration
|
||||
save_config "$enabled" "$interval"
|
||||
|
||||
# Handle service changes
|
||||
if [ "$enabled" = "true" ]; then
|
||||
# Enable memory daemon
|
||||
add_memory_daemon_to_services
|
||||
if [ "$prev_enabled" != "true" ] || [ "$prev_interval" != "$interval" ]; then
|
||||
restart_services
|
||||
fi
|
||||
else
|
||||
# Disable memory daemon
|
||||
remove_memory_daemon_from_services
|
||||
restart_services
|
||||
fi
|
||||
|
||||
# Return current status
|
||||
sleep 1 # Give services time to start/stop
|
||||
local running="false"
|
||||
if is_memory_daemon_running; then
|
||||
running="true"
|
||||
fi
|
||||
|
||||
send_success "Memory setting updated successfully" "{\"enabled\":$enabled,\"interval\":$interval,\"running\":$running}"
|
||||
}
|
||||
|
||||
# Handle DELETE request - Reset to default
|
||||
handle_delete() {
|
||||
log_message "DELETE request received"
|
||||
|
||||
# Remove memory daemon from services and restart
|
||||
remove_memory_daemon_from_services
|
||||
restart_services
|
||||
|
||||
# Remove config files
|
||||
rm -f "$CONFIG_FILE" "$FALLBACK_CONFIG_FILE" 2>/dev/null
|
||||
|
||||
send_success "Memory setting reset to default (disabled)" "{\"enabled\":false,\"interval\":1,\"running\":false,\"isDefault\":true}"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_message "Memory settings script called with method: ${REQUEST_METHOD:-GET}"
|
||||
|
||||
case "${REQUEST_METHOD:-GET}" in
|
||||
POST)
|
||||
handle_post
|
||||
;;
|
||||
DELETE)
|
||||
handle_delete
|
||||
;;
|
||||
*)
|
||||
send_error "METHOD_NOT_ALLOWED" "HTTP method ${REQUEST_METHOD} not supported."
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,330 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Ping Settings Configuration Script
|
||||
# Manages ping service (enable/disable) and daemon settings
|
||||
# Author: dr-dolomite
|
||||
# Date: 2025-08-04
|
||||
|
||||
# Handle OPTIONS request first (before any headers)
|
||||
if [ "${REQUEST_METHOD:-GET}" = "OPTIONS" ]; then
|
||||
echo "Content-Type: text/plain"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo "Access-Control-Max-Age: 86400"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Set content type and CORS headers for other requests
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CONFIG_DIR="/etc/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/ping_settings.conf"
|
||||
FALLBACK_CONFIG_DIR="/tmp/quecmanager/settings"
|
||||
FALLBACK_CONFIG_FILE="$FALLBACK_CONFIG_DIR/ping_settings.conf"
|
||||
LOG_FILE="/tmp/ping_settings.log"
|
||||
PID_FILE="/tmp/quecmanager/ping_daemon.pid"
|
||||
# Prefer the new services location, fall back to the legacy path for compatibility
|
||||
DAEMON_RELATIVE_PATHS="/cgi-bin/services/ping_daemon.sh"
|
||||
|
||||
# Logging function
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error response function
|
||||
send_error() {
|
||||
local error_code="$1"
|
||||
local error_message="$2"
|
||||
log_message "ERROR: $error_message"
|
||||
echo "{\"status\":\"error\",\"code\":\"$error_code\",\"message\":\"$error_message\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success response function
|
||||
send_success() {
|
||||
local message="$1"
|
||||
local data="$2"
|
||||
log_message "SUCCESS: $message"
|
||||
if [ -n "$data" ]; then
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\",\"data\":$data}"
|
||||
else
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Resolve config file for reading: prefer primary, then fallback
|
||||
resolve_config_for_read() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
return 0
|
||||
elif [ -f "$FALLBACK_CONFIG_FILE" ]; then
|
||||
CONFIG_FILE="$FALLBACK_CONFIG_FILE"
|
||||
CONFIG_DIR="$FALLBACK_CONFIG_DIR"
|
||||
return 0
|
||||
fi
|
||||
# Default to primary path if none exist
|
||||
return 0
|
||||
}
|
||||
|
||||
# Determine daemon path (absolute) based on typical web root layouts
|
||||
resolve_daemon_path() {
|
||||
# Common locations where CGI/WWW is mounted
|
||||
for rel in $DAEMON_RELATIVE_PATHS; do
|
||||
for base in \
|
||||
/www \
|
||||
/; do
|
||||
if [ -x "$base$rel" ]; then
|
||||
echo "$base$rel"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
# Also try as-is if busybox httpd cwd matches web root
|
||||
if [ -x "$rel" ]; then
|
||||
echo "$rel"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
# Nothing found; return first candidate as a best-effort path
|
||||
set -- $DAEMON_RELATIVE_PATHS
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
daemon_running() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||
if [ -n "${pid:-}" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
start_daemon() {
|
||||
# Ensure /tmp/quecmanager exists for PID
|
||||
[ -d "/tmp/quecmanager" ] || mkdir -p "/tmp/quecmanager"
|
||||
|
||||
if daemon_running; then
|
||||
log_message "Daemon already running"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local daemon_path
|
||||
daemon_path="$(resolve_daemon_path)"
|
||||
if [ ! -x "$daemon_path" ]; then
|
||||
# Try to make it executable if present
|
||||
if [ -f "$daemon_path" ]; then
|
||||
chmod +x "$daemon_path" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -x "$daemon_path" ]; then
|
||||
nohup "$daemon_path" >/dev/null 2>&1 &
|
||||
log_message "Started ping daemon: $daemon_path (pid $!)"
|
||||
return 0
|
||||
else
|
||||
log_message "Daemon script not found or not executable: $daemon_path"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
stop_daemon() {
|
||||
if daemon_running; then
|
||||
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||
if [ -n "${pid:-}" ]; then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
sleep 0.2
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
rm -f "$PID_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Get current ping setting
|
||||
get_config_values() {
|
||||
# defaults
|
||||
ENABLED="true"
|
||||
HOST="8.8.8.8"
|
||||
INTERVAL="5"
|
||||
|
||||
resolve_config_for_read
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
val=$(grep -E "^PING_ENABLED=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2)
|
||||
if [ -n "${val:-}" ]; then
|
||||
case "$val" in
|
||||
true|1|on|yes|enabled) ENABLED="true" ;;
|
||||
*) ENABLED="false" ;;
|
||||
esac
|
||||
fi
|
||||
val=$(grep -E "^PING_HOST=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2)
|
||||
[ -n "${val:-}" ] && HOST="$val"
|
||||
val=$(grep -E "^PING_INTERVAL=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2)
|
||||
if echo "${val:-}" | grep -qE '^[0-9]+$'; then
|
||||
INTERVAL="$val"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Save ping setting to config file
|
||||
save_config() {
|
||||
local enabled="$1"
|
||||
local host="$2"
|
||||
local interval="$3"
|
||||
|
||||
# Try primary directory first
|
||||
if mkdir -p "$CONFIG_DIR" 2>/dev/null; then
|
||||
local tmp="$CONFIG_FILE.tmp.$$"
|
||||
echo "PING_ENABLED=$enabled" > "$tmp" || rm -f "$tmp" || return 1
|
||||
echo "PING_HOST=$host" >> "$tmp" || rm -f "$tmp" || return 1
|
||||
echo "PING_INTERVAL=$interval" >> "$tmp" || rm -f "$tmp" || return 1
|
||||
if mv -f "$tmp" "$CONFIG_FILE" 2>/dev/null; then
|
||||
chmod 644 "$CONFIG_FILE" 2>/dev/null || true
|
||||
log_message "Saved ping config (primary): enabled=$enabled host=$host interval=$interval"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to /tmp
|
||||
mkdir -p "$FALLBACK_CONFIG_DIR" 2>/dev/null || true
|
||||
local tmp2="$FALLBACK_CONFIG_FILE.tmp.$$"
|
||||
echo "PING_ENABLED=$enabled" > "$tmp2" || rm -f "$tmp2" || return 1
|
||||
echo "PING_HOST=$host" >> "$tmp2" || rm -f "$tmp2" || return 1
|
||||
echo "PING_INTERVAL=$interval" >> "$tmp2" || rm -f "$tmp2" || return 1
|
||||
mv -f "$tmp2" "$FALLBACK_CONFIG_FILE" 2>/dev/null || return 1
|
||||
chmod 644 "$FALLBACK_CONFIG_FILE" 2>/dev/null || true
|
||||
# Point CONFIG_FILE to fallback for subsequent reads in this request
|
||||
CONFIG_FILE="$FALLBACK_CONFIG_FILE"; CONFIG_DIR="$FALLBACK_CONFIG_DIR"
|
||||
log_message "Saved ping config (fallback): enabled=$enabled host=$host interval=$interval"
|
||||
}
|
||||
|
||||
# Delete ping configuration (reset to default)
|
||||
delete_ping_setting() {
|
||||
local removed=1
|
||||
for f in "$CONFIG_FILE" "$FALLBACK_CONFIG_FILE"; do
|
||||
if [ -f "$f" ]; then
|
||||
sed -i '/^PING_ENABLED=/d' "$f" 2>/dev/null || true
|
||||
sed -i '/^PING_HOST=/d' "$f" 2>/dev/null || true
|
||||
sed -i '/^PING_INTERVAL=/d' "$f" 2>/dev/null || true
|
||||
log_message "Deleted ping configuration entries in $f"
|
||||
[ -s "$f" ] || { rm -f "$f" 2>/dev/null || true; log_message "Removed empty config file $f"; }
|
||||
removed=0
|
||||
fi
|
||||
done
|
||||
return $removed
|
||||
}
|
||||
|
||||
# Handle GET request - Retrieve ping setting
|
||||
handle_get() {
|
||||
log_message "GET request received"
|
||||
get_config_values
|
||||
local running=false
|
||||
if daemon_running; then running=true; fi
|
||||
local is_default=true
|
||||
if [ -f "$CONFIG_FILE" ] && grep -q "^PING_ENABLED=" "$CONFIG_FILE"; then
|
||||
is_default=false
|
||||
fi
|
||||
send_success "Ping configuration retrieved" "{\"enabled\":$ENABLED,\"host\":\"$HOST\",\"interval\":$INTERVAL,\"running\":$running,\"isDefault\":$is_default}"
|
||||
}
|
||||
|
||||
# Handle POST request - Update ping setting
|
||||
handle_post() {
|
||||
log_message "POST request received"
|
||||
|
||||
# Read POST data
|
||||
local content_length=${CONTENT_LENGTH:-0}
|
||||
if [ "$content_length" -gt 0 ]; then
|
||||
local post_data=$(dd bs=$content_length count=1 2>/dev/null)
|
||||
log_message "Received POST data: $post_data"
|
||||
|
||||
# Parse fields
|
||||
local enabled host interval
|
||||
enabled=$(echo "$post_data" | sed -n 's/.*"enabled"[[:space:]]*:[[:space:]]*\([^,}]*\).*/\1/p' | tr -d ' ' | sed 's/"//g')
|
||||
host=$(echo "$post_data" | sed -n 's/.*"host"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
interval=$(echo "$post_data" | sed -n 's/.*"interval"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p')
|
||||
|
||||
# Defaults when missing
|
||||
[ -z "$enabled" ] && enabled="true"
|
||||
[ -z "$host" ] && host="8.8.8.8"
|
||||
[ -z "$interval" ] && interval="5"
|
||||
|
||||
# Validate
|
||||
case "$enabled" in
|
||||
true|false) : ;;
|
||||
*) send_error "INVALID_SETTING" "Invalid enabled value. Must be true or false." ;;
|
||||
esac
|
||||
if ! echo "$interval" | grep -qE '^[0-9]+$'; then
|
||||
send_error "INVALID_INTERVAL" "Interval must be a number (seconds)."
|
||||
fi
|
||||
if [ "$interval" -lt 1 ] || [ "$interval" -gt 3600 ]; then
|
||||
send_error "INVALID_INTERVAL" "Interval must be between 1 and 3600 seconds."
|
||||
fi
|
||||
|
||||
# Capture previous values to decide on restart
|
||||
get_config_values
|
||||
local prev_enabled="$ENABLED"
|
||||
local prev_host="$HOST"
|
||||
local prev_interval="$INTERVAL"
|
||||
|
||||
save_config "$enabled" "$host" "$interval" || send_error "WRITE_FAILED" "Failed to save configuration"
|
||||
|
||||
if [ "$enabled" = "true" ]; then
|
||||
if daemon_running; then
|
||||
# Restart only if effective parameters changed
|
||||
if [ "$prev_host" != "$host" ] || [ "$prev_interval" != "$interval" ] || [ "$prev_enabled" != "$enabled" ]; then
|
||||
log_message "Config change detected (host/interval/enabled). Restarting daemon."
|
||||
stop_daemon
|
||||
start_daemon || log_message "Failed to restart daemon"
|
||||
else
|
||||
log_message "No change requiring restart; daemon remains running"
|
||||
fi
|
||||
else
|
||||
start_daemon || log_message "Failed to start daemon"
|
||||
fi
|
||||
else
|
||||
stop_daemon
|
||||
fi
|
||||
|
||||
get_config_values
|
||||
local running=false
|
||||
if daemon_running; then running=true; fi
|
||||
send_success "Ping setting updated successfully" "{\"enabled\":$ENABLED,\"host\":\"$HOST\",\"interval\":$INTERVAL,\"running\":$running}"
|
||||
else
|
||||
send_error "NO_DATA" "No data provided"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle DELETE request - Reset to default (delete configuration)
|
||||
handle_delete() {
|
||||
log_message "DELETE request received"
|
||||
stop_daemon
|
||||
if delete_ping_setting; then
|
||||
# Default is enabled
|
||||
send_success "Ping setting reset to default" "{\"enabled\":true,\"isDefault\":true,\"running\":false}"
|
||||
else
|
||||
send_error "NOT_FOUND" "Ping setting configuration not found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_message "Ping settings script called with method: ${REQUEST_METHOD:-GET}"
|
||||
|
||||
# Handle different HTTP methods
|
||||
case "${REQUEST_METHOD:-GET}" in
|
||||
GET)
|
||||
handle_get
|
||||
;;
|
||||
POST)
|
||||
handle_post
|
||||
;;
|
||||
DELETE)
|
||||
handle_delete
|
||||
;;
|
||||
*)
|
||||
send_error "METHOD_NOT_ALLOWED" "HTTP method ${REQUEST_METHOD} not supported"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,193 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Ultra-Simple Profile Picture Management Script
|
||||
# Handles direct file uploads without base64 encoding
|
||||
# Author: dr-dolomite
|
||||
# Date: 2025-08-04
|
||||
|
||||
# Set content type and CORS headers
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type, Authorization"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
PROFILE_DIR="/www/assets/profile"
|
||||
PROFILE_IMAGE="$PROFILE_DIR/profile.jpg"
|
||||
TEMP_DIR="/tmp"
|
||||
LOG_FILE="/tmp/profile_picture.log"
|
||||
|
||||
# Logging function
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error response function
|
||||
send_error() {
|
||||
local error_code="$1"
|
||||
local error_message="$2"
|
||||
log_message "ERROR: $error_message"
|
||||
echo "{\"status\":\"error\",\"code\":\"$error_code\",\"message\":\"$error_message\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success response function
|
||||
send_success() {
|
||||
local message="$1"
|
||||
local data="$2"
|
||||
log_message "SUCCESS: $message"
|
||||
if [ -n "$data" ]; then
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\",\"data\":$data}"
|
||||
else
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get file size
|
||||
get_file_size() {
|
||||
local file="$1"
|
||||
if [ -f "$file" ]; then
|
||||
stat -c%s "$file" 2>/dev/null || wc -c < "$file"
|
||||
else
|
||||
echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Create profile directory if it doesn't exist
|
||||
ensure_profile_directory() {
|
||||
if [ ! -d "$PROFILE_DIR" ]; then
|
||||
mkdir -p "$PROFILE_DIR"
|
||||
if [ $? -ne 0 ]; then
|
||||
send_error "DIRECTORY_ERROR" "Failed to create profile directory"
|
||||
fi
|
||||
chmod 755 "$PROFILE_DIR"
|
||||
log_message "Created profile directory: $PROFILE_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle GET request - Fetch profile picture
|
||||
handle_get() {
|
||||
log_message "GET request received"
|
||||
|
||||
if [ -f "$PROFILE_IMAGE" ]; then
|
||||
# Get file information
|
||||
local file_size=$(get_file_size "$PROFILE_IMAGE")
|
||||
local file_modified=$(stat -c %Y "$PROFILE_IMAGE" 2>/dev/null || echo "0")
|
||||
|
||||
# Return file information and base64 encoded image
|
||||
local base64_image=""
|
||||
if command -v base64 >/dev/null 2>&1; then
|
||||
base64_image=$(base64 -w 0 "$PROFILE_IMAGE" 2>/dev/null)
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
base64_image=$(openssl base64 -in "$PROFILE_IMAGE" | tr -d '\n' 2>/dev/null)
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
base64_image=$(python3 -c "
|
||||
import base64
|
||||
try:
|
||||
with open('$PROFILE_IMAGE', 'rb') as f:
|
||||
data = f.read()
|
||||
encoded = base64.b64encode(data).decode('ascii')
|
||||
print(encoded)
|
||||
except Exception as e:
|
||||
pass
|
||||
" 2>/dev/null)
|
||||
elif command -v busybox >/dev/null 2>&1; then
|
||||
base64_image=$(busybox base64 "$PROFILE_IMAGE" | tr -d '\n' 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -n "$base64_image" ]; then
|
||||
local file_type=$(file -b --mime-type "$PROFILE_IMAGE" 2>/dev/null || echo "image/jpeg")
|
||||
send_success "Profile picture found" "{\"exists\":true,\"size\":$file_size,\"modified\":$file_modified,\"type\":\"$file_type\",\"data\":\"data:$file_type;base64,$base64_image\"}"
|
||||
else
|
||||
send_success "Profile picture found but could not encode" "{\"exists\":true,\"size\":$file_size,\"modified\":$file_modified,\"data\":null}"
|
||||
fi
|
||||
else
|
||||
log_message "No profile picture found"
|
||||
echo "{\"status\":\"error\",\"code\":\"NO_IMAGE_FOUND\",\"message\":\"No profile picture found\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle POST request - Direct file upload (no base64)
|
||||
handle_post() {
|
||||
log_message "POST request received"
|
||||
ensure_profile_directory
|
||||
|
||||
# Create temporary file with unique name
|
||||
local temp_file="$TEMP_DIR/profile_upload_$$"
|
||||
|
||||
log_message "Content-Type: ${CONTENT_TYPE:-unknown}"
|
||||
log_message "Content-Length: ${CONTENT_LENGTH:-unknown}"
|
||||
|
||||
# Read the raw uploaded file data directly to temp file
|
||||
cat > "$temp_file"
|
||||
|
||||
# Check if file was created and has content
|
||||
if [ ! -f "$temp_file" ]; then
|
||||
send_error "UPLOAD_ERROR" "Failed to receive uploaded file"
|
||||
fi
|
||||
|
||||
local temp_size=$(get_file_size "$temp_file")
|
||||
log_message "Received file size: $temp_size bytes"
|
||||
|
||||
if [ "$temp_size" -eq 0 ]; then
|
||||
rm -f "$temp_file"
|
||||
send_error "UPLOAD_ERROR" "Received empty file"
|
||||
fi
|
||||
|
||||
# Simply move the uploaded file to profile location (rename operation)
|
||||
if mv "$temp_file" "$PROFILE_IMAGE"; then
|
||||
chmod 644 "$PROFILE_IMAGE"
|
||||
local file_size=$(get_file_size "$PROFILE_IMAGE")
|
||||
log_message "Profile picture saved successfully, size: $file_size bytes"
|
||||
send_success "Profile picture uploaded successfully" "{\"size\":$file_size,\"path\":\"$PROFILE_IMAGE\"}"
|
||||
else
|
||||
rm -f "$temp_file"
|
||||
send_error "SAVE_ERROR" "Failed to save profile picture"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle DELETE request - Remove profile picture
|
||||
handle_delete() {
|
||||
log_message "DELETE request received"
|
||||
|
||||
if [ -f "$PROFILE_IMAGE" ]; then
|
||||
if rm "$PROFILE_IMAGE"; then
|
||||
send_success "Profile picture deleted successfully"
|
||||
else
|
||||
send_error "DELETE_ERROR" "Failed to delete profile picture"
|
||||
fi
|
||||
else
|
||||
send_error "NO_IMAGE_FOUND" "No profile picture found to delete"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle OPTIONS request for CORS preflight
|
||||
handle_options() {
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type, Authorization"
|
||||
echo "Access-Control-Max-Age: 86400"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_message "Profile picture script called with method: ${REQUEST_METHOD:-GET}"
|
||||
|
||||
# Handle different HTTP methods
|
||||
case "${REQUEST_METHOD:-GET}" in
|
||||
GET)
|
||||
handle_get
|
||||
;;
|
||||
POST)
|
||||
handle_post
|
||||
;;
|
||||
DELETE)
|
||||
handle_delete
|
||||
;;
|
||||
OPTIONS)
|
||||
handle_options
|
||||
;;
|
||||
*)
|
||||
send_error "METHOD_NOT_ALLOWED" "HTTP method ${REQUEST_METHOD} not supported"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user