Backport save_config merge fix into legacy ubuntu-based-kiosk.sh; bump to v2.7.0

Per user decision: backport just the config-clobbering fix from v2.6.0
(lib/config.sh) into the legacy single-file installer's own
save_config(), independent of migrating the rest of that menu into
./install.sh.

The bug: save_config() rebuilt config.json from a fixed list of known
fields via `jq -n`, silently deleting anything it didn't know about -
specifically autheliaURL/autheliaUsername/autheliaEncryptedPassword,
written by configure_authelia()'s own careful `. + {...}` merge.
Configuring Authelia and then visiting Sites, Touch Controls,
Navigation, or Password Protection (all of which call save_config)
silently deleted the Authelia credentials. Real, currently-shipping
credential-loss bug, unrelated to whether the rest of that menu is ever
migrated - didn't need to wait for a full pass.

Fixed the same way as lib/config.sh: merge the known fields onto
whatever's already in config.json (`. + {...}`) instead of rebuilding
from nothing, with a `jq empty` validity check falling back to `{}` if
the existing file is missing or corrupt. This is a standalone fix to
one function only - nothing else about Sites/Touch/Navigation/Authelia
changed, and none of that is migrated by this commit.

Verified before touching the shipping copy: extracted the exact
save_config() function (now lines 3682-3805) into an isolated test
harness with stubbed dependencies (kiosk_user_exists, is_service_active,
log_success/warning), seeded a stub config.json with Authelia-style
fields via the same `. + {...}` merge configure_authelia() uses, called
save_config() a second time simulating a visit to an unrelated menu,
and confirmed the Authelia fields survive while an actual settings
change (duration 60 -> 90) still correctly takes effect. Also verified
the corrupt-JSON and missing-file edge cases don't crash the function.
Full syntax check on the whole 12,000+ line script, and the entire
modular test suite (11 scratch/stub suites), both still clean.
This commit is contained in:
Claude
2026-08-19 01:21:43 +00:00
parent 6c68897935
commit cdd6f5adcf
2 changed files with 59 additions and 14 deletions
+46 -4
View File
@@ -1,8 +1,35 @@
#!/bin/bash
################################################################################
### Ubuntu Based Kiosk v2.6.0 ###
### Ubuntu Based Kiosk v2.7.0 ###
################################################################################
#
# RELEASE v2.7.0 - Backported Fix: save_config() No Longer Deletes
# Authelia Credentials (or Any Other Untracked Field)
# - This script's own save_config() had the exact bug described under
# v2.6.0 below: it rebuilt config.json from a fixed list of known
# fields via `jq -n`, which silently deleted anything it didn't know
# about - specifically autheliaURL/autheliaUsername/
# autheliaEncryptedPassword, written by configure_authelia()'s own
# careful `. + {...}` merge. Configure Authelia, then visit Core
# Settings → Sites/Touch Controls/Navigation/Password Protection (all
# of which call save_config), and the Authelia credentials were
# silently gone - a real credential-loss bug that was shipping in this
# script independent of the modular migration.
# - Fixed the same way as lib/config.sh's save_config: merge the known
# fields onto whatever's already in config.json (`. + {...}`) instead
# of rebuilding it from nothing, with a `jq empty` validity check
# falling back to `{}` if the existing file is missing or corrupt.
# Verified in isolation (the exact function extracted and exercised
# against a stub config.json seeded with Authelia-style fields,
# confirming they survive a second save_config call while an actual
# settings change still takes effect, plus the corrupt/missing-file
# edge cases) before touching the shipping copy.
# - This is a standalone backport of one specific fix, not a wider
# migration of the Sites/Touch/Navigation/Authelia menus into this
# script - those still work exactly as before, just without the
# credential-loss bug. The modular ./install.sh path (lib/config.sh)
# got the equivalent fix in v2.6.0.
#
# RELEASE v2.6.0 - Authelia Migrated; Real Config-Clobbering Bug Fixed
# - New in ./install.sh: Authelia Auto-Login (menus/addon_authelia.sh) -
# encrypted SSO credentials (AES-256-CBC, key derived from this
@@ -261,7 +288,7 @@ set -euo pipefail
### SECTION 1: CONSTANTS & GLOBALS
################################################################################
SCRIPT_VERSION="2.6.0"
SCRIPT_VERSION="2.7.0"
# Resolve the real path to this script file.
# When piped (curl|bash or wget|bash), BASH_SOURCE[0] is a pipe descriptor,
@@ -3712,7 +3739,22 @@ save_config() {
local boot_password_json="false"
[[ "$REQUIRE_PASSWORD_ON_BOOT" == "true" ]] && boot_password_json="true"
jq -n \
# Merge onto whatever's already in config.json rather than rebuilding
# it from nothing (fixed in v2.7.0). The old `jq -n` rebuild silently
# deleted any field this function doesn't explicitly know about -
# notably autheliaURL/autheliaUsername/autheliaEncryptedPassword,
# written by configure_authelia()'s own careful `. + {...}` merge.
# Configuring Authelia and then visiting Sites, Touch Controls,
# Navigation, or Password Protection (all of which call this
# function) silently deleted the Authelia credentials. See the
# RELEASE v2.7.0 note above.
local existing="{}"
if sudo -u "$KIOSK_USER" test -f "$CONFIG_PATH" 2>/dev/null; then
existing=$(sudo -u "$KIOSK_USER" cat "$CONFIG_PATH" 2>/dev/null)
echo "$existing" | jq empty 2>/dev/null || existing="{}"
fi
echo "$existing" | jq \
--arg unit "s" \
--argjson autoswitch "$auto_json" \
--argjson enableTouch true \
@@ -3731,7 +3773,7 @@ save_config() {
--arg lockoutActiveStart "${LOCKOUT_ACTIVE_START:-}" \
--arg lockoutActiveEnd "${LOCKOUT_ACTIVE_END:-}" \
--argjson requirePasswordOnBoot "$boot_password_json" \
'{unit:$unit,autoswitch:$autoswitch,enableTouch:$enableTouch,dualSwipe:$dualSwipe,swipeMode:$swipeMode,allowNavigation:$allowNavigation,homeTabIndex:$homeTabIndex,inactivityTimeout:$inactivityTimeout,enablePauseButton:$enablePauseButton,enableKeyboardButton:$enableKeyboardButton,enableNavButton:$enableNavButton,enablePasswordProtection:$enablePasswordProtection,lockoutPassword:$lockoutPassword,lockoutTimeout:$lockoutTimeout,lockoutAtTime:$lockoutAtTime,lockoutActiveStart:$lockoutActiveStart,lockoutActiveEnd:$lockoutActiveEnd,requirePasswordOnBoot:$requirePasswordOnBoot,tabs:[]}' > "$tmp"
'. + {unit:$unit,autoswitch:$autoswitch,enableTouch:$enableTouch,dualSwipe:$dualSwipe,swipeMode:$swipeMode,allowNavigation:$allowNavigation,homeTabIndex:$homeTabIndex,inactivityTimeout:$inactivityTimeout,enablePauseButton:$enablePauseButton,enableKeyboardButton:$enableKeyboardButton,enableNavButton:$enableNavButton,enablePasswordProtection:$enablePasswordProtection,lockoutPassword:$lockoutPassword,lockoutTimeout:$lockoutTimeout,lockoutAtTime:$lockoutAtTime,lockoutActiveStart:$lockoutActiveStart,lockoutActiveEnd:$lockoutActiveEnd,requirePasswordOnBoot:$requirePasswordOnBoot,tabs:[]}' > "$tmp"
if [[ ${#URLS[@]} -gt 0 ]]; then
for idx in "${!URLS[@]}"; do