With --ozone-platform=x11, Chromium defaults touch event detection to
'auto' and may not identify the hardware as a touchscreen, so touchstart/
touchend never fire in the renderer. --touch-events=enabled forces W3C
touch events on unconditionally, restoring two-finger swipe navigation.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
The upgrade was wiping node_modules then relying on npm to re-download the
~120MB Electron binary. npm returns exit 0 even when the download times out,
leaving the kiosk with no Electron binary and a blank screen on next boot.
node_modules only needs to be deleted on a fresh install or when explicitly
changing Electron version. For a JS-file-only upgrade, npm install without
a wipe is either a no-op (no changes) or applies dependency updates cleanly.
The install_electron_binary fallback remains as a safety net.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
Touch handlers used bubble phase (no capture:true), so any page script that
called stopPropagation() on touchstart/touchend — e.g. Authelia's login form
or scroll containers — silently blocked the preload's swipe detection.
Using capture:true fires the preload's listeners in the capture phase (before
any element-level handlers), so swipe works even on pages with their own
touch handling. Applied to both preloads (standard and auto-show keyboard).
Also adds missing [TOUCH] 2-finger HORIZONTAL console.log to the standard
preload so swipe events are visible in electron.log for debugging.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
The duplicate-block pitfall (YAML silently ignores duplicate keys, causing
a white screen) is now called out explicitly in both the script's printed
output and the README. Added a before/after example showing the correct
merged result with the kiosk one_factor rule above the two_factor wildcard.
Also explains why one_factor is required (TOTP/WebAuthn need interactive
second step, impossible via API).
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
Without a timeout, session.defaultSession.fetch() hangs for 1-2 minutes
on TCP timeout when Authelia is unreachable (wrong URL, server down,
firewall). Since createWindow() awaits autheliaAuthenticate(), the main
window is visible but no BrowserView is attached during that wait —
causing a persistent white screen with ibeam cursor.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
- Step 3 now says MERGE (not replace/append) with clear warning to keep existing config
- access_control: kiosk one_factor rule must go ABOVE any existing two_factor rule,
with explanation that Authelia applies rules top-down (first match wins)
- session block: keep existing values; only add the block if none exists yet
- Kiosk can only do one_factor — TOTP/WebAuthn via API is not possible
- Updated in both configure_authelia() printed output and README Authentication section
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
The upgrade_kiosk() path deleted node_modules then ran npm install but
never checked the binary or set chrome-sandbox permissions — so every
upgrade produced a blank screen.
Changes:
- Extract electron binary verification, fallback downloads, and
chrome-sandbox chmod 4755 into a shared install_electron_binary()
function called by both step 17/27 (fresh install) and step 5/6
(upgrade_kiosk) so neither path can silently skip the permission fix
- Add repair_electron() function: stops display, re-runs
install_electron_binary, restarts lightdm — no SSH needed
- Wire repair_electron as Advanced menu option 12 "Fix Blank Screen"
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
The ~120MB Electron binary download was silently failing because npm's
default 60s fetch timeout is too short on slower connections.
Changes to step 17/27:
- Set npm fetch-timeout to 600s and retries to 5 before running npm install
- If binary still missing after npm install, retry via install.js with
ELECTRON_FORCE_DOWNLOAD=true
- If still missing, fall back to direct wget download of the exact
versioned zip from GitHub releases (300s timeout, 3 tries, shows progress)
- Exit 1 with clear message if all three attempts fail
- Log chrome-sandbox permission step for visibility
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
/home/kiosk/ has 750 permissions so the install user can't read inside
it. The -f check and both jq reads were running as the current user and
failing silently, causing the false "config.json not found" error.
Changed:
[[ ! -f "$config_file" ]] → sudo test -f "$config_file"
jq -r ... "$config_file" → sudo -u kiosk jq -r ... "$config_file"
jq ... > "$tmp" → sudo -u kiosk jq ... > "$tmp" && sudo mv
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
npm install returns 0 even when Electron's postinstall binary download
fails, leaving node_modules/electron/dist/electron missing and causing
a blank screen with no useful error.
After npm install, explicitly check for the binary. If absent, retry
via ELECTRON_FORCE_DOWNLOAD=true node install.js. If still missing,
print a clear error and exit 1 instead of silently continuing to a
broken install.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
New file ubuntu-based-kiosk-v1.0.2.sh containing all changes made
since v1.0.1:
- Authelia auto-login addon (Addons → 5): AES-256 encrypted credentials,
startup API auth, full Dockerized server-side setup printed on save
- Fix: PipeWire .config dirs created as root caused Permission denied
at step [5.5/27] on fresh Ubuntu 24.04 minimal installs
- README install commands now pull latest script dynamically via
GitHub contents API (no more hardcoded version numbers)
SCRIPT_VERSION and VERSION constants updated to 1.0.2.
README changelog and current version updated to 1.0.2.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
After configure_authelia() saves credentials, it now prints the full
Dockerized Authelia server-side checklist: argon2 hash generation
command, users.yml kiosk user template, configuration.yml session
duration and access_control rules, and a docker compose restart step.
README gains a new Authentication section under Optional Add-ons
covering the same steps in Markdown with a table comparing Authelia
SSO vs HTTP Basic Auth (both can coexist).
Also clarifies that the Authelia password is encrypted at rest and
not stored in plain text.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
Adds an Authelia Auto-Login addon (Addons menu → 5) that:
- Prompts for Authelia URL, username, and password
- Encrypts the password with AES-256-CBC keyed from /etc/machine-id
via scrypt (the encrypted blob is machine-specific and useless elsewhere)
- Stores autheliaURL, autheliaUsername, autheliaEncryptedPassword in config.json
On every kiosk startup, main.js decrypts the password and calls
Authelia's /api/firstfactor with keepMeLoggedIn:true before any
BrowserViews are created. Electron's session.defaultSession handles
the Set-Cookie response automatically, so all sites load already
authenticated.
To set up credentials via SSH:
ssh user@kiosk
./ubuntu-based-kiosk-v*.sh → Addons → 5. Authelia Auto-Login
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
sudo mkdir -p created the .config/pipewire/pipewire.conf.d directories
owned by root, causing the subsequent sudo -u kiosk tee to fail with
"Permission denied" at step [5.5/27] on a fresh install.
Switching to sudo -u kiosk mkdir -p ensures the directories are owned
by the kiosk user before the tee writes into them.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
Quick Install section now queries the GitHub contents API to find and
download the latest ubuntu-based-kiosk-v*.sh script dynamically, so the
README never needs a manual version bump when a new release is pushed.
Post-install "run again" references use `ls ubuntu-based-kiosk-v*.sh | sort -V | tail -1`
for the same reason.
Also bumps version references from 1.0.0 → 1.0.1, Electron 41 → 42,
Node.js 20 → 22, and adds the v1.0.1 changelog entry.
https://claude.ai/code/session_01EyjEQLWbTXcZgbMDarf7NU
NetBird v0.60 changed SSH to JWT/IdP-based auth by default.
Using --disable-ssh-auth keeps access controlled purely by NetBird
ACL policies (machine-level, like pre-v0.60 behaviour) without
requiring an identity provider or OIDC flow.
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
All 6 popup BrowserWindows (lockout, prompt, pause, pin, keyboard ×2)
now use contextIsolation:true + popup-preload.js instead of the
deprecated nodeIntegration:true pattern. A new popup-preload.js file
exposes crypto.hashPassword, fs.readPin, ipcRenderer.send/on/once to
the renderer via contextBridge. All affected HTML files updated to use
window.electronAPI.* instead of direct require('electron') calls.
The popup-preload.js heredoc is also added to the upgrade extract_file
list so upgrades re-extract it correctly.
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
BrowserView has been deprecated since Electron 29 and will be removed
in a future major release. This beta migrates all usage to the
WebContentsView API introduced in Electron 28.
Changes in main.js:
- Import WebContentsView instead of BrowserView
- Add bringViewToTop() helper (remove+re-add as last child = on top)
- createWindow: new WebContentsView / contentView.addChildView
- attachView: contentView.removeChildView + bringViewToTop
- showLockoutScreen: contentView.removeChildView for all views
- unlockScreen: bringViewToTop to restore hidden view
- returnToTabs: bringViewToTop instead of setTopBrowserView
- showHiddenTab: bringViewToTop instead of setTopBrowserView
v1.0.0 is kept unchanged. The legacy update_mainjs_keyboard() patch
function is guarded by a grep check that prevents it running against
the new WebContentsView-based main.js.
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
No breaking changes affecting the kiosk app between these versions:
- BrowserView still present (deprecated but not removed until future release)
- WebContentsView destroyed-event change does not apply (app uses BrowserView)
- Session.clearStorageData quotas removal not used
- PDF OOPIF change not relevant
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
- Bump version references from 0.9.9.1/0.9.8 to 1.0.0
- Update script filename to ubuntu-based-kiosk-v1.0.0.sh throughout
- Add v1.0.0 changelog entries (upgrade fix, sudo/timezone fixes)
- Preserve prior version history (v0.9.9.1, v0.9.8) as changelog
- Update Claude model reference to Sonnet 4.6
- Update last-updated date
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
Two issues caused the timezone step to fail on first run:
1. Sudo credential cache (default 15 min) can expire during the long
apt install step before configure_timezone runs. Added `sudo -v`
immediately after the install confirmation prompt to prime the cache
as late as possible, just before the first long-running step.
2. `sudo timedatectl set-timezone` can fail with "Access denied" if
polkit/D-Bus is not yet fully ready in the install environment.
Added a direct fallback (ln -sf localtime + tee /etc/timezone)
that bypasses D-Bus entirely.
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
On Ubuntu 22.04+, useradd creates home directories with 750 permissions,
so the non-root user running the script cannot traverse /home/kiosk to
check file existence with [[ -s ]]. sudo tee (running as root) writes the
files successfully, but the bash test always returned false, falsely
reporting all extractions as failed.
Switch to `sudo test -s` to match the pattern already used elsewhere in
the script (line ~10320) when checking files under /home/kiosk.
https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
- Rename install_kiosk_v0.9.9.1.sh to ubuntu-based-kiosk.sh
- Update all repository URLs from ubk to ubuntu-based-kiosk
- Remove UBK abbreviation from documentation and script headers
- Update installation instructions in Readme.md
- Power menu: Send IPC to views[] instead of mainWindow.webContents
(preload.js runs in BrowserViews, not mainWindow)
- Export: Add chmod 777 to temp dir, use sudo for all file operations,
use sudo tar and fix archive ownership
- Import: Use sudo tar, add proper permissions to temp directory
- PIN entry window: auto-closes after 30 seconds of inactivity
- Pause dialog: auto-closes after 30 seconds of inactivity
- Power menu: converted from native dialog to custom overlay with
30-second timeout (lockout mode still uses native dialog)
- Nav menu already had 30-second timeout
All modal windows and overlays now automatically dismiss after
30 seconds to prevent screens being left open indefinitely.