#!/bin/sh MODNAME=newt SETTINGS=/opt/$MODNAME/etc/settings LOGFILE=/tmp/newt.log PIDFILE=/tmp/newt.pid # Escape special HTML characters htmlesc() { printf '%s' "$1" | sed \ -e 's/&/\&/g' \ -e 's/\</g' \ -e 's/>/\>/g' \ -e 's/"/\"/g' } # Decode URL-encoded form values (handles common chars in endpoints/ids/secrets) urldecode() { printf '%s' "$1" | sed \ -e 's/+/ /g' \ -e 's/%3[Aa]/:/g' -e 's/%3[aa]/:/g' \ -e 's/%2[Ff]/\//g' -e 's/%2[ff]/\//g' \ -e 's/%40/@/g' \ -e 's/%2[Ee]/./g' \ -e 's/%2[Dd]/-/g' \ -e 's/%5[Ff]/_/g' \ -e 's/%3[Dd]/=/g' \ -e 's/%3[Ff]/?/g' \ -e 's/%23/#/g' \ -e 's/%25/%/g' } # Extract a named field from URL-encoded POST data (awk splits on & without tr) get_field() { printf '%s' "$2" | awk -v f="${1}=" 'BEGIN{RS="&"} index($0,f)==1 {print substr($0,length(f)+1); exit}' } # Check whether newt process is alive is_running() { [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE" 2>/dev/null)" 2>/dev/null } ensure_settings_file() { [ -f "$SETTINGS" ] && return if [ -f "/opt/$MODNAME/etc/defaults" ]; then cp "/opt/$MODNAME/etc/defaults" "$SETTINGS" 2>/dev/null else printf 'MOD_PANGOLIN_SITE_ENABLED=0\n' > "$SETTINGS" fi } set_setting_raw() { key="$1" value="$2" ensure_settings_file awk -v k="$key" -v v="$value" ' BEGIN { done=0 } index($0, k "=") == 1 { print k "=" v; done=1; next } { print } END { if (!done) print k "=" v } ' "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS" } quote_sh_value() { printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' } # ── Read POST body ────────────────────────────────────────────────────────── POST_DATA="" if [ "$REQUEST_METHOD" = "POST" ] && [ -n "$CONTENT_LENGTH" ] && [ "$CONTENT_LENGTH" -gt 0 ] 2>/dev/null; then POST_DATA=$(dd bs="$CONTENT_LENGTH" count=1 2>/dev/null) fi # ── Load current settings ─────────────────────────────────────────────────── MOD_PANGOLIN_SITE_ENABLED=0 MOD_PANGOLIN_SITE_ENDPOINT="" MOD_PANGOLIN_SITE_ID="" MOD_PANGOLIN_SITE_SECRET="" [ -f "$SETTINGS" ] && . "$SETTINGS" # ── Handle actions ────────────────────────────────────────────────────────── if [ -n "$POST_DATA" ]; then ACTION=$(get_field "action" "$POST_DATA") case "$ACTION" in save) EP=$(urldecode "$(get_field "endpoint" "$POST_DATA")") ID=$(urldecode "$(get_field "id" "$POST_DATA")") SEC=$(urldecode "$(get_field "secret" "$POST_DATA")") set_setting_raw "MOD_PANGOLIN_SITE_ENDPOINT" "\"$(quote_sh_value "$EP")\"" set_setting_raw "MOD_PANGOLIN_SITE_ID" "\"$(quote_sh_value "$ID")\"" set_setting_raw "MOD_PANGOLIN_SITE_SECRET" "\"$(quote_sh_value "$SEC")\"" ;; start) set_setting_raw "MOD_PANGOLIN_SITE_ENABLED" "1" /opt/$MODNAME/etc/init start >/dev/null 2>&1 ;; stop) /opt/$MODNAME/etc/init stop >/dev/null 2>&1 set_setting_raw "MOD_PANGOLIN_SITE_ENABLED" "0" ;; restart) set_setting_raw "MOD_PANGOLIN_SITE_ENABLED" "1" /opt/$MODNAME/etc/init restart >/dev/null 2>&1 ;; clearlog) printf '' > "$LOGFILE" ;; esac fi # Reload settings after actions. MOD_PANGOLIN_SITE_ENABLED=0 MOD_PANGOLIN_SITE_ENDPOINT="" MOD_PANGOLIN_SITE_ID="" MOD_PANGOLIN_SITE_SECRET="" [ -f "$SETTINGS" ] && . "$SETTINGS" # ── Status ────────────────────────────────────────────────────────────────── if is_running; then STATUS_TEXT="Running" STATUS_CLASS="running" DISABLED="disabled" SETTINGS_HINT='