Compare commits

...
14 Commits
Author SHA1 Message Date
Outis ccf73d41bd Merge pull request #110 from outis1one/claude/offline-install-readme-kfpr5u
Claude/offline install readme kfpr5u
2026-08-02 19:46:41 -04:00
Claude 10c4c22f44 Route audio to HDMI automatically when an external display is connected
Previously nothing switched PipeWire's default sink, so audio always stayed on the laptop/built-in speakers regardless of HDMI mirroring. Adds /usr/local/bin/kiosk-audio-route.sh, which finds a sink whose name contains 'hdmi' and makes it the default (moving any already-playing streams onto it) whenever an external display is connected, falling back to the non-HDMI sink when it isn't. Called from autostart once PipeWire is confirmed ready, and from kiosk-hotplug.sh alongside the existing display mirroring on every plug/unplug event. Documents the behavior and manual fallback in the README.
2026-08-02 22:54:23 +00:00
Claude 6f6d34512e Mirror external display at the kiosk's exact resolution, not its own native mode
Previously mirroring used 'xrandr --auto', which picks the external output's own native resolution (e.g. a TV's 1920x1080) rather than matching the kiosk/laptop panel's resolution. Extracts the shared mirroring logic (previously duplicated between autostart and the hotplug handler) into /usr/local/bin/kiosk-mirror-display.sh, which now checks whether the external output natively lists the primary's resolution and uses it directly, or generates a matching mode with cvt and forces it via --newmode/--addmode when it doesn't. Documents the behavior and a manual fallback for displays that reject non-native CVT timings in the README.
2026-08-02 22:51:08 +00:00
Claude f01781de41 Add live HDMI/display hotplug handling via udev + systemd
Adds a udev rule (DRM 'change' events) that triggers a new kiosk-hotplug.service, which re-runs the same xrandr mirroring logic as the Openbox autostart script. External displays plugged in after boot now get mirrored without requiring a login or lightdm restart. Named kiosk-hotplug (not kiosk-display-*) to avoid collision with the existing kiosk-display-* wildcard cleanup in remove_all_schedules(). Also removes the udev rule during Complete Uninstall and documents the behavior in the README.
2026-08-02 22:37:39 +00:00
Claude 68a7345f5b Mirror external HDMI/monitor output onto primary display automatically
Openbox autostart now detects any connected output beyond the primary and mirrors the kiosk content onto it via xrandr, instead of leaving detected-but-unused external displays dark. Also documents the behavior, its limitation (applies at session start, not live hotplug), and adds an HDMI troubleshooting section to the README.
2026-08-02 22:34:19 +00:00
Claude b5d37fa646 Install net-tools and ncdu; curl/git already covered
apt install already includes curl and git; adds net-tools and ncdu to the same idempotent apt install so they're present on fresh installs without duplicating already-installed packages.
2026-08-02 22:15:15 +00:00
Outis de9c97aa06 Merge pull request #109 from outis1one/claude/offline-install-readme-kfpr5u
Add offline/air-gapped download instructions to README
2026-08-02 18:11:50 -04:00
Claude ca00674e4c Add offline/air-gapped download instructions to README
Clarifies that the installer script can be downloaded on another machine and transferred via USB, while noting the kiosk machine still needs internet access during install for apt/npm packages.
2026-08-02 22:06:48 +00:00
Outis 0c809d7e53 Merge pull request #108 from outis1one/claude/brave-tesla-hwf1m8
Claude/brave tesla hwf1m8
2026-06-16 14:17:35 -04:00
Claude 29b5783052 Fix LightDM autologin on fresh server installs (nopasswdlogin group + missing config)
Two bugs caused the login screen to appear on new Ubuntu 24.04 server hardware:

1. Ubuntu 24.04's PAM config checks 'user ingroup nopasswdlogin', not 'autologin'.
   Add kiosk user to nopasswdlogin group (and autologin for older versions).

2. The upgrade path never wrote /etc/lightdm/lightdm.conf.d/10-kiosk.conf,
   so on new hardware running through upgrade the file simply didn't exist.

Refactor: extract configure_lightdm_autologin() shared helper called from
both fresh install (step 19/27) and upgrade, so both paths are consistent.
Also use [Seat:*] instead of [SeatDefaults] for forward compatibility.

https://claude.ai/code/session_01VQ13Fwq4MXxwThLfCXBeGr
2026-06-16 18:15:05 +00:00
Outis de197f77d3 Merge pull request #107 from outis1one/claude/brave-tesla-hwf1m8
Fix all file existence checks to run as kiosk user
2026-06-16 13:40:01 -04:00
Outis 8116fdf258 Merge pull request #106 from outis1one/claude/brave-tesla-hwf1m8
Restore chmod 644 on tmp zip so kiosk user can read it for unzip
2026-06-16 13:26:25 -04:00
Outis 35350d9908 Merge pull request #105 from outis1one/claude/brave-tesla-hwf1m8
Fix Electron binary extraction: chown dist/ before extracting as kios…
2026-06-16 13:21:17 -04:00
Outis 6621f9221b Merge pull request #104 from outis1one/claude/brave-tesla-hwf1m8
Fix Electron binary extraction failing silently during upgrade
2026-06-16 13:13:09 -04:00
2 changed files with 268 additions and 20 deletions
+90 -1
View File
@@ -59,6 +59,38 @@ The installer will guide you through configuration during setup.
---
## Offline / Air-Gapped Download
If the kiosk machine can't reach GitHub directly (no browser, restrictive proxy, or you just prefer to grab the script on another computer and carry it over via USB), download it ahead of time instead of using the `curl`/`wget` one-liner above.
> **Note:** This only avoids needing internet access *to fetch the script*. The installer itself still requires the kiosk machine to have internet access while it runs — it uses `apt` to install packages, pulls Node.js from NodeSource, and runs `npm install` to fetch Electron (~120MB). There is currently no fully air-gapped/offline package bundle.
**On a machine with internet access:**
```bash
# Option A: download just the latest installer script
LATEST=$(curl -fsSL https://api.github.com/repos/outis1one/ubuntu-based-kiosk/contents \
| grep -oP 'ubuntu-based-kiosk-v[0-9.]+\.sh' \
| grep -v beta | sort -V | tail -1)
wget "https://github.com/outis1one/ubuntu-based-kiosk/raw/main/$LATEST"
# Option B: download the whole repo as a ZIP (includes all installer versions and addon scripts)
wget https://github.com/outis1one/ubuntu-based-kiosk/archive/refs/heads/main.zip
unzip main.zip
```
Copy the downloaded `.sh` file (or the extracted ZIP contents) to a USB drive, then on the kiosk machine:
```bash
# Mount the USB drive and copy the script over, then:
chmod +x ubuntu-based-kiosk-v*.sh
./ubuntu-based-kiosk-v*.sh
```
The kiosk machine still needs a working internet connection (ethernet, or WiFi configured during Ubuntu install) for the script to complete.
---
## Core Features
### Multi-Site Management
@@ -285,6 +317,9 @@ Both can be used at the same time — they serve different purposes:
- **build-essential** - GCC, make, etc.
- **Python 3** with evdev for PTT
- **jq** - JSON processing
- **curl / git** - Downloading and version control
- **net-tools** - Legacy networking utilities (ifconfig, netstat, etc.)
- **ncdu** - Disk usage analyzer for troubleshooting
---
@@ -343,6 +378,57 @@ id kiosk
sudo -u kiosk DISPLAY=:0 xdpyinfo
```
**External monitor/TV (HDMI) shows nothing, or shows a cropped/scaled picture:**
Any connected display beyond the primary is mirrored automatically at the **primary's exact resolution** (not the external display's own native resolution) — both at kiosk login/boot (via Openbox autostart) and live when plugged/unplugged afterward (via a udev rule that triggers `kiosk-hotplug.service`). Both paths call the same `/usr/local/bin/kiosk-mirror-display.sh`. If the external display doesn't natively list the primary's resolution (e.g. a 1366x768 laptop panel mirrored to a 1920x1080-native TV), a matching mode is generated on the fly with `cvt` and forced onto the output — most monitors/TVs accept a close, non-native CVT timing without issue, but a few strict ones may reject it (see below).
```bash
# List outputs and check if the external display is detected
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr
# Look for your output (e.g. HDMI1/HDMI2/HDMI-1) as "connected" with a mode list.
# Check what the mirroring logic actually did (native mode vs. forced CVT mode, or failures)
journalctl | grep "KIOSK:" | tail -20
# Check whether the hotplug handler fired
sudo journalctl -u kiosk-hotplug.service -n 20
# Manually re-trigger it
sudo systemctl start kiosk-hotplug.service
# Run the mirroring logic by hand for more verbose output
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority bash -x /usr/local/bin/kiosk-mirror-display.sh
```
If the output shows `disconnected`, it's a cabling/port/EDID issue, not software — try a different cable/port or a monitor known to work.
If a forced CVT mode is rejected by the display (blank screen only after mirroring runs, works fine before), that display's EDID doesn't accept out-of-spec timings — you'll need to manually pick one of its natively listed modes instead:
```bash
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr --output HDMI2 --mode 1360x768 --same-as eDP1
```
**No sound over HDMI (audio only from laptop/built-in speakers):**
Whenever an external display is connected/mirrored, `kiosk-audio-route.sh` switches PipeWire's default sink to whichever sink's name contains `hdmi`, and moves any already-playing audio stream onto it. It's called at kiosk login (after PipeWire is confirmed ready) and by `kiosk-hotplug.service` on every plug/unplug — see `/usr/local/bin/kiosk-mirror-display.sh` above for the display side of the same hotplug event.
```bash
# List sinks and confirm an HDMI one exists (name will contain "hdmi")
sudo -u kiosk pactl list sinks short
# Check what the routing logic actually did
journalctl | grep "KIOSK: audio routed\|KIOSK: failed to route" | tail -10
# Check current default sink
sudo -u kiosk pactl get-default-sink
# Manually re-trigger routing
sudo systemctl start kiosk-hotplug.service
# Force it by hand if needed (replace with your sink name from the list above)
sudo -u kiosk pactl set-default-sink alsa_output.pci-0000_00_1f.3.hdmi-stereo
```
If no sink name contains `hdmi`, the audio codec on that HDMI port either isn't exposed by ALSA/PipeWire on this hardware, or the monitor/TV doesn't report HDMI audio support in its EDID (common on monitors that only do video) — in that case there's no PipeWire-side fix, audio has to come from the laptop speakers or a separate cable.
**Audio not working:**
```bash
# Check PipeWire (use menu: Advanced → Audio Diagnostics)
@@ -1087,6 +1173,9 @@ See the LICENSE file in the repository for full terms.
**Current Version:** 1.0.3
**Recent Updates (v1.0.3):**
- **HDMI/external display mirroring:** any connected display beyond the primary (e.g. HDMI-out to a monitor/TV) is now mirrored automatically at the primary's exact resolution — generating a custom `cvt` mode if the external display doesn't natively list it — both at kiosk login/boot and live on plug/unplug via a new udev-triggered `kiosk-hotplug.service`. Previously the external output was left inactive even when detected by X, and would otherwise mirror at its own native resolution instead of matching the kiosk panel
- **HDMI audio routing:** audio now follows the same hotplug event — the default PipeWire sink automatically switches to the HDMI audio output when an external display is connected/mirrored, and back to the built-in sink when it's disconnected (`kiosk-audio-route.sh`)
- **Package install:** installer now also installs `net-tools` and `ncdu` (alongside the already-installed `curl` and `git`)
- **Touch input fix (keyring):** added `--password-store=basic` to the Electron launch. Under LightDM autologin the GNOME keyring stays locked; when Chromium accessed it, the keyring unlock dialog grabbed all keyboard/touch input — the kiosk rendered fine but ignored every tap and keypress. This flag stops Electron from using the keyring, so the dialog never appears.
- **Touch gesture fix (libinput):** any touch screen is now forced to the `libinput` driver via `/etc/X11/xorg.conf.d/99-finger-libinput.conf` (matched by hardware capability, so it works on any brand and never affects keyboards, mice, or the pen/stylus). Some drivers — notably `wacom` — only do single-touch pointer emulation and never pass real multitouch to Chromium, so 1-finger and 2-finger swipe gestures could not fire. libinput delivers proper multitouch.
- **Upgrade reliability:** `start.sh` is now refreshed on every upgrade alongside `main.js` and `preload.js`
@@ -1128,7 +1217,7 @@ See the LICENSE file in the repository for full terms.
**Known Limitations:**
- Raspberry Pi support untested in production
- No web-based configuration (CLI menu only)
- Single display only (extended desktop not supported)
- Extended desktop not supported — additional connected displays (e.g. HDMI-out to a monitor/TV) are automatically **mirrored**, not extended
---
+177 -18
View File
@@ -3844,6 +3844,8 @@ complete_uninstall() {
echo "[5/13] Removing scripts..."
sudo rm -f /usr/local/bin/kiosk-*
sudo rm -f /usr/local/bin/rtc-wake.sh
sudo rm -f /etc/udev/rules.d/99-kiosk-hotplug.rules
sudo udevadm control --reload-rules 2>/dev/null || true
# Remove CUPS
echo "[6/13] Removing CUPS..."
@@ -3953,7 +3955,8 @@ first_time_install() {
libegl-mesa0 libegl1-mesa-dev libgles2-mesa-dev \
pipewire pipewire-pulse pipewire-alsa wireplumber pipewire-audio-client-libraries alsa-utils libnotify-bin \
gstreamer1.0-pipewire libspa-0.2-bluetooth \
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip \
net-tools ncdu
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
sudo apt install -y intel-gpu-tools xserver-xorg-video-intel \
@@ -7388,9 +7391,118 @@ TOUCHCFG
# Create empty xbindkeysrc to prevent errors
sudo -u "$KIOSK_USER" touch "$KIOSK_HOME/.xbindkeysrc"
# Shared logic for mirroring any connected display beyond the primary at
# the primary's exact resolution (forcing a custom CVT mode if the
# external output doesn't natively list it). Called from both the
# Openbox autostart below (already running as kiosk user in the X
# session) and kiosk-hotplug.sh (root, via systemd/udev — wraps the call
# with sudo -u kiosk DISPLAY=:0 XAUTHORITY=...).
sudo tee /usr/local/bin/kiosk-mirror-display.sh > /dev/null <<'MIRRORSCRIPT'
#!/bin/bash
# Assumes it's run with DISPLAY/XAUTHORITY already set for the kiosk user's
# X session (either inherited, as from Openbox autostart, or exported by the
# caller). Mirrors every connected non-primary output at the primary's exact
# current resolution so kiosk content isn't cropped/letterboxed/blank on a
# TV/monitor with a different native resolution than the kiosk panel.
QUERY=$(xrandr --query 2>/dev/null)
[ -z "$QUERY" ] && exit 0
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
[ -z "$PRIMARY_OUTPUT" ] && exit 0
PRIMARY_RES=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '$1==p{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+x[0-9]+\+/){split($i,a,"+"); print a[1]; exit}}')
[ -z "$PRIMARY_RES" ] && exit 0
for OUT in $(echo "$QUERY" | awk '/ connected/{print $1}'); do
[ "$OUT" = "$PRIMARY_OUTPUT" ] && continue
HAS_NATIVE=$(echo "$QUERY" | awk -v out="$OUT" -v res="$PRIMARY_RES" '
$0 ~ "^"out" " {infound=1; next}
/^[^ \t]/ {infound=0}
infound && $1==res {print "yes"; exit}
')
if [ "$HAS_NATIVE" = "yes" ]; then
xrandr --output "$OUT" --mode "$PRIMARY_RES" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
&& logger "KIOSK: mirrored $OUT at native $PRIMARY_RES" \
|| logger "KIOSK: mirror of $OUT at $PRIMARY_RES failed"
continue
fi
# $OUT doesn't natively list the primary's resolution - force a matching mode
CVT_LINE=$(cvt "${PRIMARY_RES%x*}" "${PRIMARY_RES#*x}" 2>/dev/null | grep Modeline)
MODENAME=$(echo "$CVT_LINE" | sed -n 's/^Modeline "\([^"]*\)".*/\1/p')
TIMINGS=$(echo "$CVT_LINE" | sed -n 's/^Modeline "[^"]*" *//p')
if [ -z "$MODENAME" ] || [ -z "$TIMINGS" ]; then
logger "KIOSK: could not generate a $PRIMARY_RES mode for $OUT (cvt failed or missing)"
continue
fi
xrandr --newmode "$MODENAME" $TIMINGS 2>/dev/null
xrandr --addmode "$OUT" "$MODENAME" 2>/dev/null
xrandr --output "$OUT" --mode "$MODENAME" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
&& logger "KIOSK: mirrored $OUT at forced $PRIMARY_RES ($MODENAME)" \
|| logger "KIOSK: mirror of $OUT at forced $PRIMARY_RES failed"
done
MIRRORSCRIPT
sudo chmod +x /usr/local/bin/kiosk-mirror-display.sh
# Shared logic for routing audio to an HDMI audio sink whenever an
# external (non-primary) display is connected/mirrored, and back to the
# built-in sink when it isn't. Requires PipeWire/pipewire-pulse to
# already be running (pactl needs a live socket), so unlike
# kiosk-mirror-display.sh this is called later in autostart, after the
# "wait for PipeWire/ALSA" steps below — and from kiosk-hotplug.sh, where
# the system is already fully booted by the time it fires.
sudo tee /usr/local/bin/kiosk-audio-route.sh > /dev/null <<'AUDIOSCRIPT'
#!/bin/bash
# Assumes DISPLAY/XAUTHORITY are set (for xrandr) and pactl already has a
# working PipeWire/pulse socket for the invoking context.
QUERY=$(xrandr --query 2>/dev/null)
[ -z "$QUERY" ] && exit 0
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
[ -z "$PRIMARY_OUTPUT" ] && exit 0
EXTERNAL_CONNECTED=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '/ connected/ && $1!=p{f=1} END{print (f==1)?"yes":"no"}')
HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) ~ /hdmi/{print $2; exit}')
NON_HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) !~ /hdmi/{print $2; exit}')
route_to() {
local sink="$1" label="$2"
if [ -z "$sink" ]; then
logger "KIOSK: no $label audio sink found, leaving routing unchanged"
return
fi
pactl set-default-sink "$sink" 2>/dev/null \
&& logger "KIOSK: audio routed to $label sink ($sink)" \
|| logger "KIOSK: failed to route audio to $label sink ($sink)"
pactl list sink-inputs short 2>/dev/null | awk '{print $1}' | while read -r sid; do
pactl move-sink-input "$sid" "$sink" 2>/dev/null
done
pactl set-sink-volume "$sink" 100% 2>/dev/null
pactl set-sink-mute "$sink" 0 2>/dev/null
}
if [ "$EXTERNAL_CONNECTED" = "yes" ]; then
route_to "$HDMI_SINK" "HDMI"
else
route_to "$NON_HDMI_SINK" "built-in"
fi
AUDIOSCRIPT
sudo chmod +x /usr/local/bin/kiosk-audio-route.sh
sudo -u "$KIOSK_USER" tee "$KIOSK_HOME/.config/openbox/autostart" > /dev/null <<'AUTOSTART'
#!/bin/bash
# Mirror any connected external display (e.g. HDMI-out to a monitor/TV) onto
# the primary display, forcing it to the primary's exact resolution.
/usr/local/bin/kiosk-mirror-display.sh
# AGGRESSIVE DPMS disable - multiple methods
xset s off
xset s noblank
@@ -7460,6 +7572,9 @@ for i in {1..10}; do
sleep 1
done
# Route audio to HDMI if an external display is connected/mirrored, else built-in
/usr/local/bin/kiosk-audio-route.sh
# Set audio levels (speakers 100%, mic 100%, mic unmuted)
pactl set-sink-volume @DEFAULT_SINK@ 100%
pactl set-source-volume @DEFAULT_SOURCE@ 100%
@@ -7528,6 +7643,40 @@ sleep 2
AUTOSTART
sudo chmod 750 "$KIOSK_HOME/.config/openbox/autostart"
# HDMI/display hotplug: re-mirror any newly connected external display
# without waiting for the next login. Triggered by udev on DRM "change"
# events (monitor plugged/unplugged), which starts a oneshot systemd
# service that re-runs the same kiosk-mirror-display.sh logic used at
# Openbox autostart, as root, so it wraps the call with sudo -u kiosk.
sudo tee /usr/local/bin/kiosk-hotplug.sh > /dev/null <<'EOF'
#!/bin/bash
# Give X a moment to finish enumerating the output after the hotplug event
sleep 2
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority /usr/local/bin/kiosk-mirror-display.sh
kiosk_uid=$(id -u kiosk)
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority XDG_RUNTIME_DIR="/run/user/${kiosk_uid}" /usr/local/bin/kiosk-audio-route.sh
EOF
sudo chmod +x /usr/local/bin/kiosk-hotplug.sh
sudo tee /etc/systemd/system/kiosk-hotplug.service > /dev/null <<'EOF'
[Unit]
Description=Kiosk Display Hotplug Handler
[Service]
Type=oneshot
ExecStart=/usr/local/bin/kiosk-hotplug.sh
StandardOutput=journal
StandardError=journal
EOF
sudo tee /etc/udev/rules.d/99-kiosk-hotplug.rules > /dev/null <<'EOF'
SUBSYSTEM=="drm", ACTION=="change", TAG+="systemd", ENV{SYSTEMD_WANTS}="kiosk-hotplug.service"
EOF
sudo systemctl daemon-reload
sudo udevadm control --reload-rules
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
sudo mkdir -p /etc/X11/xorg.conf.d/
sudo tee /etc/X11/xorg.conf.d/20-intel.conf > /dev/null <<'EOF'
@@ -7557,23 +7706,7 @@ EndSection
EOF
echo "[19/27] Configuring autologin..."
sudo mkdir -p /etc/lightdm/lightdm.conf.d
# [Seat:*] is required on Ubuntu 22.04+ ([SeatDefaults] is ignored on newer LightDM)
# Also add kiosk user to the autologin group required by newer Ubuntu
sudo groupadd -f autologin
sudo usermod -aG autologin "$KIOSK_USER"
sudo tee /etc/lightdm/lightdm.conf.d/10-kiosk.conf > /dev/null <<EOF
[Seat:*]
autologin-user=$KIOSK_USER
autologin-user-timeout=0
user-session=openbox
autologin-session=openbox
# SECURITY: Greeter security settings
greeter-hide-users=true
greeter-show-manual-login=false
allow-guest=false
EOF
configure_lightdm_autologin
echo "[20/27] Configuring firewall..."
sudo ufw --force enable
@@ -11081,6 +11214,27 @@ import_settings() {
pause
}
# Shared helper: write LightDM autologin config and add kiosk user to required groups.
# Called from both fresh install (step 19/27) and upgrade (step 5/6).
configure_lightdm_autologin() {
sudo mkdir -p /etc/lightdm/lightdm.conf.d
# nopasswdlogin is checked by PAM on Ubuntu 24.04; autologin group for older versions
sudo groupadd -f nopasswdlogin
sudo groupadd -f autologin
sudo usermod -aG nopasswdlogin,autologin "$KIOSK_USER"
# [Seat:*] works on all LightDM versions; [SeatDefaults] is ignored on newer Ubuntu
sudo tee /etc/lightdm/lightdm.conf.d/10-kiosk.conf > /dev/null <<EOF
[Seat:*]
autologin-user=$KIOSK_USER
autologin-user-timeout=0
user-session=openbox
autologin-session=openbox
greeter-hide-users=true
greeter-show-manual-login=false
allow-guest=false
EOF
}
# Shared helper: verify Electron binary exists, download if missing, fix sandbox perms.
# Called from both fresh install (step 17/27) and upgrade (step 5/6).
install_electron_binary() {
@@ -11322,6 +11476,11 @@ upgrade_kiosk() {
sudo rm -f "$config_backup"
fi
# Ensure LightDM autologin config exists and groups are correct.
# The upgrade preserves node_modules but does not re-run the full install,
# so this may be the first time the config is written on new hardware.
configure_lightdm_autologin
# Force any touch screen to use libinput (proper multitouch for Chromium).
# Remove the old wacom-touch override from earlier versions — it sorts after
# this file and would otherwise win and re-bind the device to the wacom driver.