Compare commits

...

2 Commits

Author SHA1 Message Date
librelad
1e997f75d2 Merge claude/1 2026-06-12 22:33:55 +01:00
librelad
7c28007779 refactor(config): updater knobs -> configs/webui/webui_updater; fix config heal/reconcile gaps
Move the WebUI-updater settings out of general_terminal into their own
advanced webui-category file (webui_logs precedent): new
configs/webui/webui_updater holds CFG_UPDATER_SCAN_INTERVAL and the
migrated CFG_HOTFIX_AUTO, listed in webui/.category.

The move only reaches existing installs if the config convergence
machinery works, and three pieces of it silently didn't:

- checkConfigFilesMissingFiles walked a stale hardcoded category list
  ('general features network' — features doesn't exist; webui/backup/
  security never healed). Derive the categories from the template tree
  instead, and heal .category metadata too: copy it when absent and
  merge missing SUBCATEGORY_ORDER entries when present, so healed files
  actually appear in the WebUI Config editor. core_categories removed.
- Option reconciliation never touched ANY nested config file: configs_dir
  carries a trailing slash, so rel stripping missed ('configs//'), the
  template lookup failed, and reconcileConfigFile early-returned for
  every file. Strip the slash before matching.
- reconcileConfigFile's AUTO_DELETE=false branch read a never-populated
  live_line array, losing the dropped keys it promised to keep. Populate
  it alongside live_value.

Also exclude *.bak from config sourcing (reconciliation writes <file>.bak
next to live configs — now that it runs, sourcing backups would resurrect
deleted keys), and add 'libreportal config check' as a non-interactive
front door to the converge pass (was only reachable via install flows and
the interactive menu).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-06-12 22:33:23 +01:00
10 changed files with 86 additions and 31 deletions

View File

@ -2,8 +2,6 @@
# Terminal - System utilities and advanced settings **ADVANCED**
# ================================================================================
CFG_UPDATER_CHECK=60 # Update Check Interval - Hours between system update checks
CFG_HOTFIX_AUTO=security-breakage # Hotfix Auto-Apply - Which signed hotfix severities apply automatically on the update check [security-breakage|all|off]
CFG_UPDATER_SCAN_INTERVAL=30 # App Scan Interval - Minutes between automatic app update/CVE/improvement scans (0 disables)
CFG_SWAPFILE_SIZE=2G # Swap File Size - Size of swap file for memory management
CFG_GENERATED_PASS_LENGTH=14 # Password Length - Length for auto generated passwords
CFG_GENERATED_USER_LENGTH=8 # Username Length - Length for auto generated usernames

View File

@ -2,4 +2,4 @@ TITLE=WebUI
DESCRIPTION=Web interface settings and preferences
ICON=webui
ORDER=2
SUBCATEGORY_ORDER=webui_logins,webui_logs
SUBCATEGORY_ORDER=webui_logins,webui_logs,webui_updater

View File

@ -0,0 +1,5 @@
# ================================================================================
# WebUI Updater - Automatic app update, CVE & improvement scanning **ADVANCED**
# ================================================================================
CFG_UPDATER_SCAN_INTERVAL=30 # App Scan Interval - Minutes between automatic app update/CVE/improvement scans. 0 disables.
CFG_HOTFIX_AUTO=security-breakage # Hotfix Auto-Apply - Which signed hotfix severities apply automatically on the update check [security-breakage|all|off]

View File

@ -14,6 +14,16 @@ cliHandleConfigCommands()
configUpdateBatch "$encoded_pairs"
;;
"check")
# Converge live configs on the install templates: copy any missing
# files / categories (and surface them to the WebUI Config editor
# via .category), then reconcile the options inside each file —
# add new keys, drop removed ones, refresh comments, keep the
# user's values. Read-and-converge; safe to run any time.
checkConfigFilesMissingFiles
checkConfigFilesMissingVariables true
;;
"")
cliShowConfigHelp
;;

View File

@ -5,6 +5,9 @@ cliShowConfigHelp()
echo ""
echo "Available Config Commands:"
echo ""
echo " libreportal config check - Converge live configs on the install templates:"
echo " copy missing files, then reconcile options in each"
echo " (add new keys, drop removed ones, keep your values)"
echo " libreportal config update '<encoded>' - Apply a batch of CFG_KEY=VALUE pairs"
echo " <encoded> is pipe-separated; literal '|' in"
echo " values must be URL-encoded as %7C."

View File

@ -11,19 +11,24 @@ checkConfigFilesMissingFiles()
local missing_files_count=0
local found_files_count=0
# Check for core config categories in the new structure
for category in "${core_categories[@]}"; do
local install_category_dir="$install_configs_dir/$category"
local target_category_dir="$configs_dir/$category"
# Walk every category the install templates define (configs/<category>/),
# derived from the template tree itself — so a new category, or one a
# hardcoded list would miss (webui/backup/security were), heals onto
# existing installs automatically.
local install_category_dir category target_category_dir
for install_category_dir in "$install_configs_dir"*/; do
[ -d "$install_category_dir" ] || continue
category="$(basename "$install_category_dir")"
target_category_dir="${configs_dir%/}/$category"
if [ -d "$install_category_dir" ]; then
# Create target category directory if it doesn't exist
if [ ! -d "$target_category_dir" ]; then
runInstallOp mkdir -p "$target_category_dir"
fi
# Check each file in the install category directory
for install_file in "$install_category_dir"/*; do
local install_file
for install_file in "$install_category_dir"*; do
if [ -f "$install_file" ] && [[ ! "$install_file" =~ \.category$ ]]; then
local filename=$(basename "$install_file")
local target_file="$target_category_dir/$filename"
@ -36,6 +41,36 @@ checkConfigFilesMissingFiles()
((found_files_count++))
fi
done
# Heal the category's .category metadata too: copy it when absent (a
# brand-new category is invisible to the WebUI Config editor without
# it), and when present merge in any template SUBCATEGORY_ORDER entries
# it lacks — the editor only renders files listed there, so a healed
# config file would otherwise ship hidden. User-kept order and any
# extra local entries are preserved; new entries append.
local tmpl_cat="${install_category_dir}.category"
local live_cat="$target_category_dir/.category"
if [ -f "$tmpl_cat" ]; then
if [ ! -f "$live_cat" ]; then
runInstallOp cp "$tmpl_cat" "$live_cat"
else
local tmpl_order live_order merged entry _entries
tmpl_order="$(grep -m1 '^SUBCATEGORY_ORDER=' "$tmpl_cat" 2>/dev/null | cut -d= -f2-)"
live_order="$(runInstallOp grep -m1 '^SUBCATEGORY_ORDER=' "$live_cat" 2>/dev/null | cut -d= -f2-)"
merged="$live_order"
IFS=',' read -ra _entries <<< "$tmpl_order"
for entry in "${_entries[@]}"; do
[ -n "$entry" ] || continue
[[ ",$merged," == *",$entry,"* ]] || merged="${merged:+$merged,}$entry"
done
if [ -n "$merged" ] && [ "$merged" != "$live_order" ]; then
if runInstallOp grep -q '^SUBCATEGORY_ORDER=' "$live_cat" 2>/dev/null; then
runInstallOp sed -i "s/^SUBCATEGORY_ORDER=.*/SUBCATEGORY_ORDER=$merged/" "$live_cat"
else
printf 'SUBCATEGORY_ORDER=%s\n' "$merged" | runInstallOp tee -a "$live_cat" >/dev/null
fi
fi
fi
fi
done

View File

@ -8,7 +8,11 @@ checkLibrePortalConfigFilesMissingVariables()
while IFS= read -r live; do
[[ -f "$live" ]] || continue
fn=$(basename "$live")
rel="${live#"$configs_dir"/}"
# configs_dir carries a trailing slash (paths.sh) — strip it before
# appending one, or the prefix never matches ("configs//"), rel stays
# the absolute path, the template lookup misses, and every nested
# config file silently skips reconciliation.
rel="${live#"${configs_dir%/}"/}"
remote="$install_configs_dir$fn"
[[ -f "$remote" ]] || remote="$install_configs_dir$rel"
reconcileConfigFile "$live" "$remote"

View File

@ -41,13 +41,14 @@ reconcileConfigFile()
[[ -f "$live" ]] || return 0
runInstallOp test -s "$template" 2>/dev/null || return 0
declare -A live_value emitted
declare -A live_value live_line emitted
local line key
while IFS= read -r line; do
if [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]]; then
key="${BASH_REMATCH[1]}"
_reconcileSplitValueComment "$line"
live_value["$key"]="$_reconcile_value"
live_line["$key"]="$line"
fi
done < <(runInstallOp cat "$live")

View File

@ -26,7 +26,7 @@ sourceScanFiles()
# echo "$load_type NEW FILE $file"
fi
fi
done < <(find "$folder_dir" -maxdepth 2 -type f ! -name "*.category" ! -name "config_*" ! -name ".*" -print0)
done < <(find "$folder_dir" -maxdepth 2 -type f ! -name "*.category" ! -name "config_*" ! -name ".*" ! -name "*.bak" -print0)
# Per-location backup configs live nested at depth 3
# (configs/backup/locations/<idx>/location.config) — source them via

View File

@ -54,7 +54,6 @@ run_file=run.txt
# Configs
update_done=false
config_file_wireguard=config_wireguard
core_categories=("general" "features" "network")
# Menu
menu_number=0