diff --git a/Readme.md b/Readme.md index d1ec8f8..24a9f96 100644 --- a/Readme.md +++ b/Readme.md @@ -91,7 +91,7 @@ Useful options (`iso/build-iso.sh --help` for all): | Option | Effect | |---|---| -| `--unattended` | First-boot install takes every default with no prompts (skips the Core Settings menu) and reboots into the kiosk. Set sites afterwards in the Web UI (`http://:8090`) or `./install.sh`. | +| `--unattended` | First-boot install takes every default with no prompts (skips the Core Settings menu) and reboots into the kiosk. Set sites afterwards in the Web UI (`http://:8888`) or `./install.sh`. | | `--username NAME [--password PASS]` | Pre-set the admin account (password is prompted for if omitted; only a hash goes on the ISO). Not `kiosk`. | | `--hostname`, `--ssh-key FILE`, `--locale`, `--keyboard` | Pre-set those. | | `--auto-network` / `--auto-storage` | Skip the network screen (DHCP on ethernet) / wipe the largest disk without asking. | @@ -1585,7 +1585,7 @@ full migration pass. - **Fix:** the CUPS menu could report an installed CUPS as "not installed" (`dpkg -l | grep -q` failing under `set -o pipefail`). **Previous (v2.17.0):** -- **Web UI now installs by default** during first-time provisioning (fixed port 8090, no prompt) instead of being opt-in — the Addons menu entry still works standalone for reconfiguring the port or reinstalling it on a kiosk provisioned before this change. +- **Web UI now installs by default** during first-time provisioning (port 8888 for new installs, 8090 on older ones; no prompt) instead of being opt-in — the Addons menu entry still works standalone for reconfiguring the port or reinstalling it on a kiosk provisioned before this change. - **The web UI can now install/reconfigure CUPS Printing, LMS Server, Squeezelite Player, and Asterisk Intercom, and check for updates** — the same four addons plus Update named directly. Every one of these is the exact same interactive `action_*` function the terminal menu already uses (no prompt/mutation refactor of any addon file), driven by piping the right answers on stdin — the same technique this project's own bash tests already use to drive these functions. - **Privilege model:** the web service itself still runs as `$KIOSK_USER` with zero ambient `sudo`. A new narrow, allow-listed root helper is the only way it ever gains privilege — reachable only via a single-path passwordless sudo rule (generated and validated with `visudo -c -f` before being installed), and it re-checks its own fixed action allow-list before dispatching anything. Chosen over running the whole service as root after asking directly: since this repo has no login of its own by design, a request that reaches the web UI with no reverse proxy in front is effectively unauthenticated, so the allow-list bounds what that can actually do to five vetted actions, never a root shell. - Long-running installs stream live output to the browser via Server-Sent Events, one action at a time — a second request while one is in flight gets a clear `409`, never silently queued or dropped. diff --git a/iso/build-iso.sh b/iso/build-iso.sh index 43630e6..79e2e1f 100755 --- a/iso/build-iso.sh +++ b/iso/build-iso.sh @@ -18,7 +18,7 @@ # ~/ubuntu-based-kiosk - interactively by default (same prompts as a # manual install), or with --unattended taking every default and # rebooting straight into the kiosk. Configure sites afterwards via -# the Web UI (http://:8090) or ./install.sh. +# the Web UI (http://:8888) or ./install.sh. # # Nothing in the original ISO is changed except /boot/grub/grub.cfg # (menu title, plus the `autoinstall` kernel argument with --no-confirm); diff --git a/kiosk-app/main.js b/kiosk-app/main.js index 02f97f4..ba043ff 100644 --- a/kiosk-app/main.js +++ b/kiosk-app/main.js @@ -1226,6 +1226,19 @@ function historyHome(){ markActivity(); } +// Power menu -> Lock now: put up the lock screen right away (the same one +// the inactivity timeout shows). Only when password protection is on and a +// code is set - showLockoutScreen refuses otherwise, so a kiosk with no +// code can't be locked with nothing to unlock it. +function lockNow(){ + if(!enablePasswordProtection||!lockoutPassword){ + console.log('[LOCKOUT] Lock now ignored - password protection is off'); + return; + } + console.log('[LOCKOUT] Lock now requested from the power menu'); + showLockoutScreen('unlock'); +} + function showPinEntry(){ if(pinWindow&&!pinWindow.isDestroyed()){ pinWindow.focus(); @@ -1545,7 +1558,7 @@ function showPowerMenu(){ // For normal mode, use custom overlay with 30-second timeout console.log('[POWER] Showing custom power menu overlay'); - const powerInfo={version:VERSION,localIP:localIP,vpnIP:vpnIP.trim()}; + const powerInfo={version:VERSION,localIP:localIP,vpnIP:vpnIP.trim(),canLock:!!(enablePasswordProtection&&lockoutPassword)}; // Send to all views (preload.js runs in views, not mainWindow) for(const view of views){ if(view&&view.webContents&&!view.webContents.isDestroyed()){ @@ -1730,6 +1743,7 @@ async function createWindow(){ if(action==='shutdown')exec('systemctl poweroff'); else if(action==='restart')exec('systemctl reboot'); else if(action==='reload'){app.relaunch();app.quit();} + else if(action==='lock')lockNow(); }); ipcMain.on('toggle-hidden',toggleHidden); ipcMain.on('history-nav',(event,direction)=>{ diff --git a/kiosk-app/preload.js b/kiosk-app/preload.js index b71d873..9001bd1 100644 --- a/kiosk-app/preload.js +++ b/kiosk-app/preload.js @@ -666,6 +666,16 @@ window.addEventListener('DOMContentLoaded',()=>{ ipcRenderer.send('power-action','reload'); }); + // Only offered when password protection is on (set in showPowerMenu). + const lockBtn=document.createElement('button'); + lockBtn.id='power-menu-lock'; + lockBtn.textContent='🔒 Lock now'; + lockBtn.style.cssText=btnStyle+'background:#8e44ad;color:white;display:none;'; + lockBtn.addEventListener('click',()=>{ + hidePowerMenu(); + ipcRenderer.send('power-action','lock'); + }); + const cancelBtn=document.createElement('button'); cancelBtn.textContent='Cancel'; cancelBtn.style.cssText=btnStyle+'background:#7f8c8d;color:white;'; @@ -673,6 +683,7 @@ window.addEventListener('DOMContentLoaded',()=>{ hidePowerMenu(); }); + buttonsDiv.appendChild(lockBtn); buttonsDiv.appendChild(shutdownBtn); buttonsDiv.appendChild(restartBtn); buttonsDiv.appendChild(reloadBtn); @@ -708,6 +719,8 @@ window.addEventListener('DOMContentLoaded',()=>{ } infoDiv.innerHTML=infoText; } + const lockBtn=document.getElementById('power-menu-lock'); + if(lockBtn)lockBtn.style.display=(info&&info.canLock)?'':'none'; powerMenu.style.display='flex'; powerMenuVisible=true; diff --git a/lib/provision.sh b/lib/provision.sh index 71aad38..a6764d1 100644 --- a/lib/provision.sh +++ b/lib/provision.sh @@ -328,7 +328,7 @@ provision_configure_webui() { return 0 fi - local port="8090" + local port="8888" webui_write_env_file "$port" webui_write_unit_file webui_write_helper_script diff --git a/menus/addon_webui.sh b/menus/addon_webui.sh index ec01bec..ec52280 100644 --- a/menus/addon_webui.sh +++ b/menus/addon_webui.sh @@ -59,9 +59,9 @@ webui_is_active() { webui_port() { if sudo test -f "$WEBUI_ENV_DIR/webui.env" 2>/dev/null; then - sudo grep -oP '^PORT=\K.*' "$WEBUI_ENV_DIR/webui.env" 2>/dev/null || echo "8090" + sudo grep -oP '^PORT=\K.*' "$WEBUI_ENV_DIR/webui.env" 2>/dev/null || echo "8888" else - echo "8090" + echo "8888" fi } @@ -281,7 +281,7 @@ action_webui_install() { ask_yes_no "Install the Web UI?" "n" || { echo "Cancelled"; return; } local port - port=$(ask_integer "Port to listen on" "8090" 1024 65535) + port=$(ask_integer "Port to listen on" "8888" 1024 65535) echo "Installing app files and npm dependencies..." if ! webui_install_app_files; then @@ -321,6 +321,8 @@ action_webui_reconfigure() { webui_write_env_file "$port" sudo systemctl restart kiosk-webui sudo ufw allow "${port}/tcp" comment 'Kiosk Web UI' 2>/dev/null || true + # The old port is no longer used - close it. + sudo ufw delete allow "${current_port}/tcp" 2>/dev/null || true log_success "Web UI now listening on port ${port}" } diff --git a/webui/server.js b/webui/server.js index 598782a..a4b987c 100644 --- a/webui/server.js +++ b/webui/server.js @@ -294,7 +294,7 @@ app.put('/api/region', (req, res) => { runRegionHelper('region-set', input, res); }); -const PORT = process.env.PORT || 8090; +const PORT = process.env.PORT || 8888; const BIND_ADDR = process.env.BIND_ADDR || '0.0.0.0'; if (require.main === module) {