#!/bin/bash # Apply a batch of `CFG_KEY=VALUE` pairs joined by `|` (literal `|` in values # encoded as `%7C`). Re-runs apps.json regen + startScan after. configUpdateBatch() { local encoded_pairs="$1" if [[ -z "$encoded_pairs" ]]; then isNotice "configUpdateBatch called with no changes — skipping update." fi isHeader "Applying configuration changes" local applied=0 local failed=0 local catalog_changed=false IFS='|' read -ra pairs <<< "$encoded_pairs" for pair in "${pairs[@]}"; do [[ -z "$pair" ]] && continue if [[ "$pair" =~ ^(CFG_[A-Z0-9_]+)=(.*)$ ]]; then local key="${BASH_REMATCH[1]}" local value="${BASH_REMATCH[2]//%7C/|}" # A value the WebUI collected as a secret arrives here as a # REFERENCE, never the secret itself. Redeem it at the last moment # before the write. # # This is the whole point of the channel: the pair string reaching # this function came in as part of a task's command, and tasks are # recorded in frontend/data/tasks/*.json — 0644, inside a # world-readable directory — as well as being visible in `ps` while # they run. A backup repository password sent that way is the key to # every backup the user has, readable by any local account. # # Done here rather than per caller because this is the single point # every config write from the WebUI passes through, so every # password field benefits at once. if declare -f webuiSecretIsRef >/dev/null 2>&1 && webuiSecretIsRef "$value"; then local _secret if ! _secret=$(webuiSecretConsume "${value#secret:}"); then isError "Could not read the submitted value for $key — leaving it unchanged." ((failed++)) continue fi value="$_secret" fi [[ "$key" == CFG_CATALOG_* ]] && catalog_changed=true if updateConfigOption "$key" "$value"; then ((applied++)) else ((failed++)) fi else isNotice "Skipping malformed pair: $pair" ((failed++)) fi done isSuccessful "Applied $applied config change(s); $failed skipped/failed." echo "" echo "---- Regenerating apps.json from updated config..." echo "" if declare -f webuiGenerateLibrePortalConfig >/dev/null 2>&1; then webuiGenerateLibrePortalConfig >/dev/null 2>&1 || true isSuccessful "apps.json regenerated." fi echo "" echo "---- Running system scan to apply new configuration..." echo "" if declare -f startScan >/dev/null 2>&1; then startScan isSuccessful "System scan completed." fi # Catalog sources are the source of truth for the App Center browse data; # rebuild the generated registry_catalog.json when a CFG_CATALOG_* changed. if [[ "$catalog_changed" == true ]] && declare -f catalogRefresh >/dev/null 2>&1; then echo "" echo "---- Refreshing catalog sources..." echo "" catalogRefresh fi echo "" isSuccessful "Configuration update complete." }