Files
ubuntu-based-kiosk/install.sh
T
Claude 6c68897935 Migrate Authelia addon; fix real config-clobbering bug in save_config; bump to v2.6.0
Second Addon migrated: menus/addon_authelia.sh (encrypted SSO
credentials, AES-256-CBC with a key derived from /etc/machine-id via
scrypt - same algorithm main.js decrypts with - plus the full
Dockerized server-side setup instructions, now viewable again later
without reconfiguring).

Investigating how to wire its three config.json fields (autheliaURL/
autheliaUsername/autheliaEncryptedPassword) into lib/config.sh surfaced
a real, currently-shipping bug that has nothing to do with Authelia
specifically: save_config() did a full `jq -n` rebuild of config.json
from a fixed list of known fields - identical to what the legacy
script's own save_config still does. The legacy configure_authelia()
writes its three fields via a careful `. + {...}` merge that preserves
everything else already in the file, but neither save_config knew those
fields existed - so the next time a user visited Sites, Touch Controls,
Navigation, or Password Protection (all of which call save_config),
their Authelia credentials were silently deleted. This bug already
existed in the shipped single-file installer; it was ported faithfully
into lib/config.sh's first version because no test happened to set an
untracked field before calling save_config.

Fixed in lib/config.sh: save_config now merges its known fields onto
whatever's already in config.json (jq `. + {...}`) instead of rebuilding
the file from nothing, with a `jq empty` validity check falling back to
`{}` if the existing file is missing or corrupt. Any field this tool
doesn't track - Authelia's three today, anything else a future addon
adds tomorrow - now survives automatically. autheliaURL/
autheliaUsername/autheliaEncryptedPassword are also tracked fields in
their own right now (load_existing_config/save_config), consistent with
every other config.json field this tool manages, giving Authelia both a
direct fix and the general safety net.

The equivalent bug still exists, unfixed, in ubuntu-based-kiosk.sh's own
save_config - noted in both that script's changelog and the Readme's
"Modular Management" section as an open question: whether to backport
just that one fix into the legacy script now, independent of the wider
migration, given it's a real credential-loss bug affecting the
currently-shipping installer today.

Verified:
- New dedicated test (test_save_merge.sh) proving the save_config fix
  itself: seeded config.json with a simulated untracked field via the
  same `. + {...}` merge Authelia's own code uses, called save_config
  from an unrelated context (Sites deleting a tab), and confirmed the
  untracked field survived while the tab deletion still correctly took
  effect (not undone by the merge) - plus corrupt-JSON and
  missing-file edge cases both handled without crashing.
- New scratch-config test for addon_authelia.sh using REAL encryption
  (this sandbox has both Node and /etc/machine-id): configured with a
  real password, then decrypted the stored ciphertext using main.js's
  exact algorithm (independently reproduced in the test) and confirmed
  it recovers the original password exactly - true interoperability,
  not just "some ciphertext was produced." Also covered cancel paths,
  clearing the configuration, the encryption-unavailable failure path,
  and confirmed Authelia's config survives an unrelated Sites save.
- Full regression: re-ran all 9 prior scratch/stub test suites after
  both the lib/config.sh changes - all still clean.
- End-to-end: ran the real install.sh as a genuine non-root, non-
  "kiosk" user with a seeded minimal config.json, through Addons ->
  Authelia -> Configure with a real URL/username/password -> confirmed
  the resulting config.json on disk, and independently decrypted the
  stored password for real using main.js's algorithm to confirm it
  matches exactly. Clean exit code 0 throughout.
2026-08-18 21:56:21 +00:00

148 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# install.sh - Modular management entry point for Ubuntu Based Kiosk.
#
# This is NOT yet the full system installer - that is still the big
# single-file script (ubuntu-based-kiosk.sh) documented in Readme.md, and
# first-time provisioning of a new kiosk still goes through it. That file
# still also contains its own (unmigrated, unmodified) copies of every
# menu below - both copies coexist deliberately until enough of Core
# Settings/Addons/Advanced has moved over to retire the old ones in one
# pass. This entry point is the modular replacement, one menus/*.sh file
# at a time, so a change to (say) the Sites menu can't accidentally break
# WiFi setup or the uninstaller three thousand lines away.
#
# Migrated so far, grouped the same way the legacy menu groups them:
# Core Settings: Sites & Page Timing, Display & Interaction, Timezone,
# Hidden Site PIN, Password Protection & Lockout, WiFi,
# Power/Display/Quiet Hours.
# Addons: CUPS Printing (menus/addon_cups.sh), Authelia Auto-Login
# (menus/addon_authelia.sh).
# Advanced: Diagnostics (menus/diagnostics.sh - system status/logs/
# audio/network).
#
# Usage (once the kiosk has already been installed):
# git clone <repo>
# cd ubuntu-based-kiosk
# ./install.sh
################################################################################
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/menu.sh
source "$SCRIPT_DIR/lib/menu.sh"
# shellcheck source=lib/config.sh
source "$SCRIPT_DIR/lib/config.sh"
# shellcheck source=menus/sites.sh
source "$SCRIPT_DIR/menus/sites.sh"
# shellcheck source=menus/display.sh
source "$SCRIPT_DIR/menus/display.sh"
# shellcheck source=menus/timezone.sh
source "$SCRIPT_DIR/menus/timezone.sh"
# shellcheck source=menus/hidden_pin.sh
source "$SCRIPT_DIR/menus/hidden_pin.sh"
# shellcheck source=menus/lockout.sh
source "$SCRIPT_DIR/menus/lockout.sh"
# shellcheck source=menus/wifi.sh
source "$SCRIPT_DIR/menus/wifi.sh"
# shellcheck source=menus/power_schedule.sh
source "$SCRIPT_DIR/menus/power_schedule.sh"
# shellcheck source=menus/diagnostics.sh
source "$SCRIPT_DIR/menus/diagnostics.sh"
# shellcheck source=menus/addon_cups.sh
source "$SCRIPT_DIR/menus/addon_cups.sh"
# shellcheck source=menus/addon_authelia.sh
source "$SCRIPT_DIR/menus/addon_authelia.sh"
################################################################################
# Preflight
################################################################################
if [[ "$(whoami)" == "kiosk" ]]; then
log_error "Cannot run as user 'kiosk'"
exit 1
fi
if [[ $EUID -eq 0 ]]; then
log_error "Run as a regular user with sudo privileges, not as root"
exit 1
fi
if ! command -v jq &>/dev/null; then
log_error "jq is required but not installed. Run: sudo apt-get install -y jq"
exit 1
fi
if ! is_kiosk_installed; then
echo
log_error "No installed kiosk found at ${KIOSK_DIR}."
echo
echo "This tool manages an already-installed kiosk. To provision a new"
echo "one for the first time, use the full installer instead - see"
echo "Readme.md ('Quick Install') for the current download command."
echo
exit 1
fi
################################################################################
# Top-level menu - grouped the same way the legacy menu groups them
# (Core Settings / Addons / Advanced), so the structure stays familiar
# and the flat list doesn't grow unwieldy as more menus migrate in.
################################################################################
core_settings_menu_builder() {
MENU_LABELS=(
"Sites & Page Timing"
"Display & Interaction"
"Timezone"
"Hidden Site PIN"
"Password Protection & Lockout"
"WiFi"
"Power/Display/Quiet Hours"
)
MENU_HANDLERS=(
sites_menu
display_menu
timezone_menu
hidden_pin_menu
lockout_menu
wifi_menu
power_schedule_menu
)
}
core_settings_menu() {
run_menu "CORE SETTINGS" core_settings_menu_builder
}
addons_menu_builder() {
MENU_LABELS=("CUPS Printing" "Authelia Auto-Login")
MENU_HANDLERS=(addon_cups_menu addon_authelia_menu)
}
addons_menu() {
run_menu "ADDONS" addons_menu_builder
}
advanced_menu_builder() {
MENU_LABELS=("Diagnostics")
MENU_HANDLERS=(diagnostics_menu)
}
advanced_menu() {
run_menu "ADVANCED" advanced_menu_builder
}
main_menu_builder() {
MENU_LABELS=("Core Settings" "Addons" "Advanced")
MENU_HANDLERS=(core_settings_menu addons_menu advanced_menu)
}
main_menu_status() {
echo "Managing kiosk at: ${KIOSK_DIR}"
}
run_menu "UBUNTU BASED KIOSK - MANAGEMENT" main_menu_builder main_menu_status "Exit"