Add Fleet Profile MVP for replicating settings across kiosks; bump to v2.13.0
New menus/fleet_profile.sh (Advanced), for the "set up one kiosk, then stand up a dozen more like it" use case. Not a port of the legacy Export/Import Settings - a narrower, deliberately-scoped feature: - Export: writes config.json's portable fields (sites, display/touch/ navigation, lockout, password protection) plus a list of addons present at export time to a JSON profile file. - Apply: merges those fields onto a target kiosk's config.json (same merge-not-replace pattern as save_config, so the target's own fields survive untouched) and prints a checklist of which listed addons are/ aren't installed on the target. Deliberately excludes machine-bound credentials rather than silently mishandling them: Authelia's encrypted password is keyed off /etc/machine-id and decrypts to garbage elsewhere; a WireGuard private key is a device identity, reusing one across machines is a peer conflict; most Asterisk PBXes reject duplicate registrations to the same extension. Apply prints all three as an explicit "needs a human" checklist. Non-interactive addon installation (for a fully scriptable fleet rollout) is a deliberate follow-up, not part of this MVP. Full command-level stubbed test suite covering export (site/setting content, Authelia stripped, addon detection) and apply (merge correctness, target's own Authelia preserved, bad path/invalid JSON handled cleanly). Full 20-suite regression + real end-to-end menu navigation via install.sh all pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VfsFSoRqfbRG7XAg5RoE7e
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Ubuntu Based Kiosk
|
# Ubuntu Based Kiosk
|
||||||
|
|
||||||
**Current Version:** 2.12.0 (check script header for latest version)
|
**Current Version:** 2.13.0 (check script header for latest version)
|
||||||
**Built with Claude Sonnet 4.6 AI assistance**
|
**Built with Claude Sonnet 4.6 AI assistance**
|
||||||
**License:** GPL v3 - Keep derivatives open source
|
**License:** GPL v3 - Keep derivatives open source
|
||||||
**Repository:** https://github.com/outis1one/ubuntu-based-kiosk/
|
**Repository:** https://github.com/outis1one/ubuntu-based-kiosk/
|
||||||
@@ -1255,6 +1255,11 @@ terminal menu and the web UI, so they can't drift apart).
|
|||||||
Settings): the last of the "destructive trio." Composed from every
|
Settings): the last of the "destructive trio." Composed from every
|
||||||
addon's own `*_do_uninstall` helper instead of re-implementing
|
addon's own `*_do_uninstall` helper instead of re-implementing
|
||||||
removal a second time — see "Recent Updates (v2.12.0)" below.
|
removal a second time — see "Recent Updates (v2.12.0)" below.
|
||||||
|
- `menus/fleet_profile.sh` — **Fleet Profile** (Advanced): export/apply
|
||||||
|
the portable parts of `config.json` across several kiosks that should
|
||||||
|
share the same settings. New, not a legacy port — deliberately never
|
||||||
|
copies machine-bound credentials (Authelia, WireGuard, Asterisk
|
||||||
|
Intercom); see "Recent Updates (v2.13.0)" below.
|
||||||
- `install.sh` — entry point for the modular tool, now grouped **Core
|
- `install.sh` — entry point for the modular tool, now grouped **Core
|
||||||
Settings / Addons / Advanced** like the legacy menu. Run it against an
|
Settings / Addons / Advanced** like the legacy menu. Run it against an
|
||||||
*already-installed* kiosk:
|
*already-installed* kiosk:
|
||||||
@@ -1269,11 +1274,14 @@ most of the old installer. `ubuntu-based-kiosk.sh` is still ~12,000
|
|||||||
lines and still contains its own unremoved, unmodified copies of every
|
lines and still contains its own unremoved, unmodified copies of every
|
||||||
menu above, including the legacy three-option (Client/Server/Full)
|
menu above, including the legacy three-option (Client/Server/Full)
|
||||||
Easy Asterisk Intercom — the modular version only replaces the Client
|
Easy Asterisk Intercom — the modular version only replaces the Client
|
||||||
option, by design (plus Upgrade, Full Reinstall, Export/Import
|
option, by design (plus Upgrade, Full Reinstall, and Fix Squeezelite
|
||||||
Settings, and Fix Squeezelite Audio — none of that has moved yet;
|
Audio — none of that has moved yet; Complete Uninstall *is* now
|
||||||
Complete Uninstall *is* now migrated, but Upgrade and Full Reinstall
|
migrated, but Upgrade and Full Reinstall are staying put — both are
|
||||||
are staying put — both are coupled to this file's own heredoc self-
|
coupled to this file's own heredoc self-extraction of main.js/
|
||||||
extraction of main.js/preload.js/etc, which has no modular equivalent).
|
preload.js/etc, which has no modular equivalent). The legacy Export/
|
||||||
|
Import Settings is also staying as-is; Fleet Profile is a new,
|
||||||
|
narrower feature alongside it, not a replacement for it — see "Recent
|
||||||
|
Updates (v2.13.0)" below for why they're not the same thing.
|
||||||
Both copies coexist deliberately: the old ones stay until enough of
|
Both copies coexist deliberately: the old ones stay until enough of
|
||||||
Core Settings/Addons/Advanced is migrated to retire them in one pass,
|
Core Settings/Addons/Advanced is migrated to retire them in one pass,
|
||||||
rather than leaving the legacy menu half-wired. Migration continues one
|
rather than leaving the legacy menu half-wired. Migration continues one
|
||||||
@@ -1305,9 +1313,14 @@ full migration pass.
|
|||||||
|
|
||||||
## Project Status & Future Plans
|
## Project Status & Future Plans
|
||||||
|
|
||||||
**Current Version:** 2.12.0
|
**Current Version:** 2.13.0
|
||||||
|
|
||||||
**Recent Updates (v2.12.0):**
|
**Recent Updates (v2.13.0):**
|
||||||
|
- **New: Fleet Profile** (Advanced → Fleet Profile) — not a port of the legacy Export/Import Settings, a narrower MVP for the "set up one kiosk, then stamp out a dozen more like it" use case. Exports the portable parts of `config.json` (sites, display/touch/navigation, lockout, password protection) to a JSON file; applies that file to any other already-installed kiosk.
|
||||||
|
- **Deliberately does not copy machine-bound credentials**, because copying them would be actively wrong: Authelia's encrypted password is keyed off `/etc/machine-id` and decrypts to garbage on another machine; a WireGuard private key is a device identity, and reusing one across machines is a peer conflict, not a saving; most Asterisk PBXes reject two simultaneous registrations to the same extension. Applying a profile prints these as an explicit "needs a human" checklist instead of silently skipping or cloning them.
|
||||||
|
- Records which addons were present at export time and reports which are/aren't present on the target — doesn't install anything itself. Non-interactive addon installation (so applying a profile needs zero prompts — scriptable over SSH to a whole fleet) is a deliberate follow-up, not bundled into this MVP.
|
||||||
|
|
||||||
|
**Previous (v2.12.0):**
|
||||||
- **Complete Uninstall migrated** — the last of the "destructive trio." Rather than re-implementing every addon's teardown a second time (the legacy shape — CUPS/VNC/WireGuard/Tailscale/Netbird/LMS/Squeezelite removal all inlined again, independently of each addon's own uninstall action), `menus/complete_uninstall.sh` composes the `*_do_uninstall` helpers each addon already has. Every addon menu with an uninstall action was split into a confirm-and-call wrapper (unchanged from the user's perspective) plus a silent removal helper that both the wrapper and Complete Uninstall call — no duplicated logic anywhere, and if an addon's removal logic changes later, Complete Uninstall picks it up automatically.
|
- **Complete Uninstall migrated** — the last of the "destructive trio." Rather than re-implementing every addon's teardown a second time (the legacy shape — CUPS/VNC/WireGuard/Tailscale/Netbird/LMS/Squeezelite removal all inlined again, independently of each addon's own uninstall action), `menus/complete_uninstall.sh` composes the `*_do_uninstall` helpers each addon already has. Every addon menu with an uninstall action was split into a confirm-and-call wrapper (unchanged from the user's perspective) plus a silent removal helper that both the wrapper and Complete Uninstall call — no duplicated logic anywhere, and if an addon's removal logic changes later, Complete Uninstall picks it up automatically.
|
||||||
- **Important bug found and fixed while composing these:** several `*_do_uninstall` helpers (CUPS's `apt autoremove`/`apt clean`, VNC/WireGuard/Tailscale/Netbird's `apt remove`) had a bare, unguarded `apt` call. Previously this only risked aborting that one menu action if the package was already gone. Composed together as sequential calls inside Complete Uninstall, the same failure would have silently truncated the *entire* uninstall partway through — e.g. the kiosk user might never get removed because an already-uninstalled VPN client's `apt remove` failed first. Guarded all of them with `|| true`.
|
- **Important bug found and fixed while composing these:** several `*_do_uninstall` helpers (CUPS's `apt autoremove`/`apt clean`, VNC/WireGuard/Tailscale/Netbird's `apt remove`) had a bare, unguarded `apt` call. Previously this only risked aborting that one menu action if the package was already gone. Composed together as sequential calls inside Complete Uninstall, the same failure would have silently truncated the *entire* uninstall partway through — e.g. the kiosk user might never get removed because an already-uninstalled VPN client's `apt remove` failed first. Guarded all of them with `|| true`.
|
||||||
- Non-addon teardown (kiosk user/files, Node.js, LightDM/Openbox, remaining systemd units/scripts, polkit rules, re-enabling virtual consoles, final package cleanup) stays inline in `menus/complete_uninstall.sh`, since no single addon owns those paths — same as the legacy script.
|
- Non-addon teardown (kiosk user/files, Node.js, LightDM/Openbox, remaining systemd units/scripts, polkit rules, re-enabling virtual consoles, final package cleanup) stays inline in `menus/complete_uninstall.sh`, since no single addon owns those paths — same as the legacy script.
|
||||||
|
|||||||
+9
-3
@@ -30,7 +30,10 @@
|
|||||||
# manual update, fix blank screen), Factory Reset
|
# manual update, fix blank screen), Factory Reset
|
||||||
# (menus/advanced_factory_reset.sh), Virtual Consoles
|
# (menus/advanced_factory_reset.sh), Virtual Consoles
|
||||||
# (menus/advanced_virtual_consoles.sh), Emergency Hotspot
|
# (menus/advanced_virtual_consoles.sh), Emergency Hotspot
|
||||||
# (menus/advanced_emergency_hotspot.sh).
|
# (menus/advanced_emergency_hotspot.sh), Fleet Profile
|
||||||
|
# (menus/fleet_profile.sh - export/apply portable settings across
|
||||||
|
# several kiosks; deliberately excludes machine-bound credentials
|
||||||
|
# like Authelia/WireGuard/Asterisk Intercom - see the file header).
|
||||||
#
|
#
|
||||||
# Usage (once the kiosk has already been installed):
|
# Usage (once the kiosk has already been installed):
|
||||||
# git clone <repo>
|
# git clone <repo>
|
||||||
@@ -84,6 +87,9 @@ source "$SCRIPT_DIR/menus/advanced_emergency_hotspot.sh"
|
|||||||
# Sourced last: composes the *_do_uninstall/*_do_remove_all/*_do_disable
|
# Sourced last: composes the *_do_uninstall/*_do_remove_all/*_do_disable
|
||||||
# helpers defined in every file above it.
|
# helpers defined in every file above it.
|
||||||
source "$SCRIPT_DIR/menus/complete_uninstall.sh"
|
source "$SCRIPT_DIR/menus/complete_uninstall.sh"
|
||||||
|
# shellcheck source=menus/fleet_profile.sh
|
||||||
|
# Also composes detection helpers (*_is_installed) from every addon above.
|
||||||
|
source "$SCRIPT_DIR/menus/fleet_profile.sh"
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Preflight
|
# Preflight
|
||||||
@@ -158,8 +164,8 @@ addons_menu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
advanced_menu_builder() {
|
advanced_menu_builder() {
|
||||||
MENU_LABELS=("Diagnostics" "Electron Maintenance" "Factory Reset" "Virtual Consoles" "Emergency Hotspot")
|
MENU_LABELS=("Diagnostics" "Electron Maintenance" "Factory Reset" "Virtual Consoles" "Emergency Hotspot" "Fleet Profile")
|
||||||
MENU_HANDLERS=(diagnostics_menu advanced_electron_menu advanced_factory_reset_menu advanced_virtual_consoles_menu advanced_emergency_hotspot_menu)
|
MENU_HANDLERS=(diagnostics_menu advanced_electron_menu advanced_factory_reset_menu advanced_virtual_consoles_menu advanced_emergency_hotspot_menu fleet_profile_menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
advanced_menu() {
|
advanced_menu() {
|
||||||
|
|||||||
@@ -0,0 +1,258 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
################################################################################
|
||||||
|
# menus/fleet_profile.sh - "Fleet Profile" (Advanced): export the portable
|
||||||
|
# parts of this kiosk's configuration to a JSON file, and apply that file
|
||||||
|
# to other already-installed kiosks - for standing up several kiosks that
|
||||||
|
# should share the same sites/settings.
|
||||||
|
#
|
||||||
|
# This is deliberately an MVP, not the legacy Export/Import Settings
|
||||||
|
# redesigned 1:1. It moves only what's actually safe to copy between
|
||||||
|
# machines automatically:
|
||||||
|
# - config.json's portable fields (sites, display/touch, navigation,
|
||||||
|
# lockout, password protection) - plain data, no machine binding.
|
||||||
|
# - Which addons were present at export time, as an informational
|
||||||
|
# checklist on apply - NOT automated installation. That's a
|
||||||
|
# deliberately separate, bigger follow-up (each addon would need a
|
||||||
|
# non-interactive install variant, mirroring the *_do_uninstall
|
||||||
|
# helpers Complete Uninstall already composes).
|
||||||
|
#
|
||||||
|
# Explicitly NOT exported, because copying them would be actively wrong,
|
||||||
|
# not just incomplete:
|
||||||
|
# - Authelia credentials: encrypted with a key derived from this
|
||||||
|
# machine's /etc/machine-id (addon_authelia.sh) - decrypts to
|
||||||
|
# garbage on any other machine.
|
||||||
|
# - WireGuard/VPN identity: a private key is that device's identity;
|
||||||
|
# reusing one across machines is a peer conflict, not a saving.
|
||||||
|
# - Asterisk Intercom's SIP extension: most PBXes reject two
|
||||||
|
# simultaneous registrations to the same extension.
|
||||||
|
# Apply prints all three as an explicit "needs a human" checklist rather
|
||||||
|
# than silently skipping them.
|
||||||
|
#
|
||||||
|
# Depends on: lib/menu.sh, lib/config.sh, and every menus/addon_*.sh
|
||||||
|
# being sourced first (for the *_is_installed detection helpers).
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
fleet_profile_status() {
|
||||||
|
echo "Exports/applies sites, display, navigation, and lockout settings"
|
||||||
|
echo "between already-installed kiosks. Addon credentials that are"
|
||||||
|
echo "bound to one machine (Authelia, WireGuard, Asterisk Intercom)"
|
||||||
|
echo "are never copied - see the checklist after applying a profile."
|
||||||
|
}
|
||||||
|
|
||||||
|
fleet_profile_menu_builder() {
|
||||||
|
MENU_LABELS=("Export fleet profile" "Apply fleet profile")
|
||||||
|
MENU_HANDLERS=(action_export_fleet_profile action_apply_fleet_profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
fleet_profile_menu() {
|
||||||
|
run_menu "FLEET PROFILE" fleet_profile_menu_builder fleet_profile_status
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Helpers
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# JSON array of addon identifiers currently present on this machine.
|
||||||
|
fleet_detect_addons() {
|
||||||
|
local addons=()
|
||||||
|
|
||||||
|
cups_is_installed 2>/dev/null && addons+=("cups")
|
||||||
|
lms_is_installed 2>/dev/null && addons+=("lms")
|
||||||
|
squeezelite_is_installed 2>/dev/null && addons+=("squeezelite")
|
||||||
|
is_service_active x11vnc 2>/dev/null && addons+=("vnc")
|
||||||
|
command -v wg &>/dev/null && addons+=("wireguard")
|
||||||
|
command -v tailscale &>/dev/null && addons+=("tailscale")
|
||||||
|
command -v netbird &>/dev/null && addons+=("netbird")
|
||||||
|
baresip_is_installed 2>/dev/null && addons+=("asterisk_intercom")
|
||||||
|
|
||||||
|
if sudo -u "$KIOSK_USER" test -f "$CONFIG_PATH" 2>/dev/null; then
|
||||||
|
local authelia_url
|
||||||
|
authelia_url=$(sudo -u "$KIOSK_USER" jq -r '.autheliaURL // ""' "$CONFIG_PATH" 2>/dev/null || true)
|
||||||
|
[[ -n "$authelia_url" ]] && addons+=("authelia")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${#addons[@]}" -eq 0 ]]; then
|
||||||
|
echo "[]"
|
||||||
|
else
|
||||||
|
printf '%s\n' "${addons[@]}" | jq -R . | jq -s . || echo "[]"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Actions
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
action_export_fleet_profile() {
|
||||||
|
echo
|
||||||
|
if ! sudo -u "$KIOSK_USER" test -f "$CONFIG_PATH" 2>/dev/null; then
|
||||||
|
log_error "config.json not found at $CONFIG_PATH - configure sites/settings first"
|
||||||
|
pause
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local out_path
|
||||||
|
out_path=$(ask_text "Export profile to" "$HOME/kiosk-fleet-profile.json")
|
||||||
|
|
||||||
|
local raw_config
|
||||||
|
raw_config=$(sudo -u "$KIOSK_USER" cat "$CONFIG_PATH" 2>/dev/null)
|
||||||
|
if ! echo "$raw_config" | jq empty 2>/dev/null; then
|
||||||
|
log_error "config.json is not valid JSON - cannot export"
|
||||||
|
pause
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local settings
|
||||||
|
settings=$(echo "$raw_config" | jq 'del(.autheliaURL, .autheliaUsername, .autheliaEncryptedPassword)')
|
||||||
|
|
||||||
|
local addons_present
|
||||||
|
addons_present=$(fleet_detect_addons)
|
||||||
|
|
||||||
|
jq -n \
|
||||||
|
--argjson settings "$settings" \
|
||||||
|
--argjson addons "$addons_present" \
|
||||||
|
--arg script_version "${SCRIPT_VERSION:-unknown}" \
|
||||||
|
'{profile_version: 1, script_version: $script_version, settings: $settings, addons_present: $addons}' \
|
||||||
|
> "$out_path"
|
||||||
|
|
||||||
|
log_success "Fleet profile exported to $out_path"
|
||||||
|
echo
|
||||||
|
echo "Included: sites, display/touch/navigation settings, lockout,"
|
||||||
|
echo "password protection (SHA-256 hash only)."
|
||||||
|
echo
|
||||||
|
echo "NOT included (needs fresh setup on each new device):"
|
||||||
|
echo " - Authelia credentials (encrypted per-machine, won't decrypt elsewhere)"
|
||||||
|
echo " - WireGuard/VPN keys (each device needs its own identity)"
|
||||||
|
echo " - Asterisk Intercom extension (most PBXes reject duplicate registrations)"
|
||||||
|
|
||||||
|
pause
|
||||||
|
}
|
||||||
|
|
||||||
|
action_apply_fleet_profile() {
|
||||||
|
echo
|
||||||
|
local in_path
|
||||||
|
in_path=$(ask_text "Profile file to apply" "")
|
||||||
|
if [[ -z "$in_path" ]]; then
|
||||||
|
echo "Cancelled"
|
||||||
|
pause
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$in_path" ]]; then
|
||||||
|
log_error "File not found: $in_path"
|
||||||
|
pause
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! jq empty "$in_path" 2>/dev/null; then
|
||||||
|
log_error "Not valid JSON: $in_path"
|
||||||
|
pause
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local settings addons_present
|
||||||
|
settings=$(jq -c '.settings // {}' "$in_path" || echo '{}')
|
||||||
|
addons_present=$(jq -r '.addons_present[]? // empty' "$in_path" || true)
|
||||||
|
|
||||||
|
echo "Profile summary:"
|
||||||
|
echo " Sites: $(echo "$settings" | jq '.tabs | length // 0')"
|
||||||
|
echo " Addons expected: $(echo "$addons_present" | tr '\n' ' ')"
|
||||||
|
echo
|
||||||
|
ask_yes_no "Apply this profile? This overwrites current sites/display/lockout settings." "n" || { echo "Cancelled"; pause; return; }
|
||||||
|
|
||||||
|
sudo mkdir -p "$KIOSK_DIR"
|
||||||
|
sudo chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_DIR"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Merge, not replace - same reasoning as save_config: this machine's
|
||||||
|
# own Authelia fields (never in the exported settings blob) must
|
||||||
|
# survive an apply untouched. Guarded: $settings came from an
|
||||||
|
# external file - a corrupted/hand-edited profile whose "settings"
|
||||||
|
# key isn't a JSON object must not be allowed to crash the session.
|
||||||
|
local merged
|
||||||
|
if ! merged=$(echo "$existing" | jq --argjson s "$settings" '. + $s' 2>/dev/null); then
|
||||||
|
log_error "Profile's settings are not a valid JSON object - nothing was changed"
|
||||||
|
pause
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmp
|
||||||
|
tmp=$(mktemp)
|
||||||
|
echo "$merged" > "$tmp"
|
||||||
|
sudo -u "$KIOSK_USER" bash -c "cat > '$CONFIG_PATH'" < "$tmp"
|
||||||
|
sudo -u "$KIOSK_USER" chmod 644 "$CONFIG_PATH"
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
log_success "Settings applied"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Addon checklist (from the exported profile):"
|
||||||
|
local missing_any=false
|
||||||
|
if [[ -z "$addons_present" ]]; then
|
||||||
|
echo " (profile recorded no addons)"
|
||||||
|
fi
|
||||||
|
while IFS= read -r addon; do
|
||||||
|
[[ -z "$addon" ]] && continue
|
||||||
|
case "$addon" in
|
||||||
|
cups)
|
||||||
|
if cups_is_installed; then
|
||||||
|
echo " [x] CUPS Printing - already installed"
|
||||||
|
else
|
||||||
|
echo " [ ] CUPS Printing - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
lms)
|
||||||
|
if lms_is_installed; then
|
||||||
|
echo " [x] LMS Server - already installed"
|
||||||
|
else
|
||||||
|
echo " [ ] LMS Server - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
squeezelite)
|
||||||
|
if squeezelite_is_installed; then
|
||||||
|
echo " [x] Squeezelite Player - already installed"
|
||||||
|
else
|
||||||
|
echo " [ ] Squeezelite Player - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
vnc)
|
||||||
|
if is_service_active x11vnc; then
|
||||||
|
echo " [x] VNC - already installed"
|
||||||
|
else
|
||||||
|
echo " [ ] VNC - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
wireguard)
|
||||||
|
echo " [!] WireGuard - needs a NEW keypair/peer on this device, never clone the key" ;;
|
||||||
|
tailscale)
|
||||||
|
if command -v tailscale &>/dev/null; then
|
||||||
|
echo " [x] Tailscale - installed (connect with a reusable auth key if not yet connected)"
|
||||||
|
else
|
||||||
|
echo " [ ] Tailscale - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
netbird)
|
||||||
|
if command -v netbird &>/dev/null; then
|
||||||
|
echo " [x] Netbird - installed (connect with a reusable setup key if not yet connected)"
|
||||||
|
else
|
||||||
|
echo " [ ] Netbird - not installed, install via Addons"
|
||||||
|
missing_any=true
|
||||||
|
fi ;;
|
||||||
|
asterisk_intercom)
|
||||||
|
echo " [!] Asterisk Intercom - needs its own SIP extension on this device" ;;
|
||||||
|
authelia)
|
||||||
|
echo " [!] Authelia - needs a fresh login on this device" ;;
|
||||||
|
*)
|
||||||
|
echo " [?] $addon - unrecognized entry in profile" ;;
|
||||||
|
esac
|
||||||
|
done <<< "$addons_present"
|
||||||
|
|
||||||
|
if $missing_any; then
|
||||||
|
echo
|
||||||
|
echo "Install anything marked \"not installed\" above via the Addons menu."
|
||||||
|
fi
|
||||||
|
|
||||||
|
pause
|
||||||
|
}
|
||||||
+26
-2
@@ -1,8 +1,32 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
################################################################################
|
################################################################################
|
||||||
### Ubuntu Based Kiosk v2.12.0 ###
|
### Ubuntu Based Kiosk v2.13.0 ###
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
|
# RELEASE v2.13.0 - Fleet Profile: New MVP for Standing Up Several
|
||||||
|
# Kiosks with the Same Settings
|
||||||
|
# - New in ./install.sh's Advanced menu: Fleet Profile
|
||||||
|
# (menus/fleet_profile.sh). Not a port of the legacy Export/Import
|
||||||
|
# Settings - a narrower, deliberately-scoped feature for the "set up
|
||||||
|
# one kiosk, then stamp out a dozen more like it" use case: export the
|
||||||
|
# portable parts of config.json (sites, display/touch/navigation,
|
||||||
|
# lockout, password protection) to a JSON file, apply that file to any
|
||||||
|
# other already-installed kiosk.
|
||||||
|
# - Explicitly does NOT copy machine-bound credentials, because copying
|
||||||
|
# them would be actively wrong, not just incomplete: Authelia's
|
||||||
|
# encrypted password is keyed off /etc/machine-id and decrypts to
|
||||||
|
# garbage elsewhere; a WireGuard private key is a device identity and
|
||||||
|
# reusing one across machines is a peer conflict; most Asterisk PBXes
|
||||||
|
# reject two simultaneous registrations to the same extension. Apply
|
||||||
|
# prints these as an explicit "needs a human" checklist instead of
|
||||||
|
# silently skipping them or (worse) cloning them.
|
||||||
|
# - Does not install missing addons - only records which addons were
|
||||||
|
# present at export time and reports which of those are/aren't
|
||||||
|
# present on the machine being applied to. Non-interactive addon
|
||||||
|
# installation (so applying a profile needs zero prompts, scriptable
|
||||||
|
# over SSH to a whole fleet) is deliberately left as a follow-up, not
|
||||||
|
# bundled into this MVP.
|
||||||
|
#
|
||||||
# RELEASE v2.12.0 - Complete Uninstall Migrated (Last of the
|
# RELEASE v2.12.0 - Complete Uninstall Migrated (Last of the
|
||||||
# "Destructive Trio"); Composed, Not Re-Implemented
|
# "Destructive Trio"); Composed, Not Re-Implemented
|
||||||
# - New in ./install.sh's Core Settings menu: Complete Uninstall
|
# - New in ./install.sh's Core Settings menu: Complete Uninstall
|
||||||
@@ -450,7 +474,7 @@ set -euo pipefail
|
|||||||
### SECTION 1: CONSTANTS & GLOBALS
|
### SECTION 1: CONSTANTS & GLOBALS
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
SCRIPT_VERSION="2.12.0"
|
SCRIPT_VERSION="2.13.0"
|
||||||
|
|
||||||
# Resolve the real path to this script file.
|
# Resolve the real path to this script file.
|
||||||
# When piped (curl|bash or wget|bash), BASH_SOURCE[0] is a pipe descriptor,
|
# When piped (curl|bash or wget|bash), BASH_SOURCE[0] is a pipe descriptor,
|
||||||
|
|||||||
Reference in New Issue
Block a user