diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51a6151..7d94837 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: Tests run: python3 -m pytest -p no:cacheprovider - name: Shellcheck - run: shellcheck -S warning install.sh install-online.sh update.sh uninstall.sh tools/release-upload.sh image/build.sh image/stage-voxip/prerun.sh image/stage-voxip/00-voxip/00-run.sh bin/voxip-kiosk-x + run: shellcheck -S warning install.sh install-online.sh update.sh uninstall.sh tools/release-upload.sh image/build.sh image/stage-daynivo/prerun.sh image/stage-daynivo/00-daynivo/00-run.sh bin/daynivo-kiosk-x test-latest: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 332ed87..ae4a9db 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ PY ?= .venv/bin/python DEV := $(CURDIR)/.dev -DEV_ENV := PYTHONPATH=src VOXIP_CONFIG_DIR=$(DEV)/etc VOXIP_STATE_DIR=$(DEV)/state VOXIP_LOG_DIR=$(DEV)/log \ - VOXIP_SHARE_DIR=$(DEV)/share VOXIP_AGENT_RUN_DIR=$(DEV)/run VOXIP_BROWSER_RUN_DIR=$(DEV)/run \ - VOXIP_NETWORK_STATE_DIR=$(DEV)/net VOXIP_HELPER=/nonexistent/voxip-kiosk-helper +DEV_ENV := PYTHONPATH=src DAYNIVO_CONFIG_DIR=$(DEV)/etc DAYNIVO_STATE_DIR=$(DEV)/state DAYNIVO_LOG_DIR=$(DEV)/log \ + DAYNIVO_SHARE_DIR=$(DEV)/share DAYNIVO_AGENT_RUN_DIR=$(DEV)/run DAYNIVO_BROWSER_RUN_DIR=$(DEV)/run \ + DAYNIVO_NETWORK_STATE_DIR=$(DEV)/net DAYNIVO_HELPER=/nonexistent/daynivo-kiosk-helper .PHONY: venv test lint test-bookworm dev image clean @@ -13,8 +13,8 @@ test: $(PY) -m pytest lint: - shellcheck -S warning install.sh update.sh uninstall.sh image/build.sh image/stage-voxip/prerun.sh \ - image/stage-voxip/00-voxip/00-run.sh bin/voxip-kiosk-x + shellcheck -S warning install.sh update.sh uninstall.sh image/build.sh image/stage-daynivo/prerun.sh \ + image/stage-daynivo/00-daynivo/00-run.sh bin/daynivo-kiosk-x # The test suite against the exact Python/Flask/argon2 versions that Raspberry Pi OS Bookworm ships. test-bookworm: @@ -22,7 +22,7 @@ test-bookworm: apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \ python3 python3-flask python3-argon2 python3-websocket python3-pytest shellcheck >/dev/null && \ cp -r /src /work && cd /work && rm -rf .venv && python3 -m pytest -p no:cacheprovider && \ - shellcheck -S warning install.sh install-online.sh update.sh uninstall.sh tools/release-upload.sh image/build.sh bin/voxip-kiosk-x' + shellcheck -S warning install.sh install-online.sh update.sh uninstall.sh tools/release-upload.sh image/build.sh bin/daynivo-kiosk-x' # Web interface on http://127.0.0.1:8080 with throwaway state in .dev/ (system actions fail gracefully). dev: diff --git a/README.md b/README.md index 179622c..dadfbad 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ webinterface **Daynivo Kiosk Manager** op `http://kiosk.local:8080`. een setupcode die op het scherm staat. - Netwerkwijzigingen met automatische rollback. - Geen klantspecifieke code: alles per klant staat in - `/etc/voxip-kiosk/config.json` en kan bij uitrol via de bootpartitie + `/etc/daynivo-kiosk/config.json` en kan bij uitrol via de bootpartitie worden meegegeven. De architectuur en de veiligheidskeuzes staan in @@ -61,7 +61,7 @@ sudo ./install.sh --url "https://schermen-ijsselflat.voxip.nl" --name "IJsselfla ``` Alle opties zijn optioneel. Het script installeert de benodigde pakketten, -maakt de gebruikers `kiosk` en `voxip` aan, installeert de services en +maakt de gebruikers `kiosk` en `daynivo` aan, installeert de services en start de kiosk. Aan het eind toont het de setupcode. Draaide hier eerder de Daynivo-kiosk (`raspberry-pi/install-kiosk.sh` uit @@ -72,14 +72,14 @@ de Daynivo-repository)? Dan neemt `install.sh` de display-URL (inclusief In de webinterface onder **Systeem → Software-updates**: *Nu controleren*, *Bijwerken naar …*, en het vinkje **Automatisch bijwerken**. Elke nacht -tussen 03:00 en 05:00 (`voxip-kiosk-update.timer`) kijkt de kiosk of er een +tussen 03:00 en 05:00 (`daynivo-kiosk-update.timer`) kijkt de kiosk of er een nieuwe release is; met het vinkje aan installeert hij die meteen. Dat werkt ook op een apparaat dat met de image of vanuit een clone is geïnstalleerd. Vanaf de commandoregel: ```bash -sudo /usr/lib/voxip-kiosk/voxip-kiosk-updater --check # alleen kijken -sudo /usr/lib/voxip-kiosk/voxip-kiosk-updater --install # nieuwste release installeren +sudo /usr/lib/daynivo-kiosk/daynivo-kiosk-updater --check # alleen kijken +sudo /usr/lib/daynivo-kiosk/daynivo-kiosk-updater --install # nieuwste release installeren ``` De updater installeert alleen een nieuwere versie met een kloppende @@ -89,15 +89,40 @@ het ook met git: ```bash cd daynivo-kiosk-os -sudo ./update.sh # git pull --ff-only + back-up van /etc/voxip-kiosk + install.sh --upgrade +sudo ./update.sh # git pull --ff-only + back-up van /etc/daynivo-kiosk + install.sh --upgrade ``` Een update overschrijft nooit bestaande configuratie of het -beheerderswachtwoord. Back-ups staan in `/var/backups/voxip-kiosk-*.tar.gz` +beheerderswachtwoord. Back-ups staan in `/var/backups/daynivo-kiosk-*.tar.gz` (de laatste vijf). Op een apparaat met de image staat de broncode in -`/usr/src/voxip-kiosk`. Clone de repository voor updates naar een eigen map, +`/usr/src/daynivo-kiosk`. Clone de repository voor updates naar een eigen map, of pak een release uit en draai daar `sudo ./update.sh --no-pull`. +### Van de VoxIP-namen naar Daynivo + +Kiosks tot en met versie 1.2.x gebruiken nog de oude namen: services +`voxip-kiosk-*`, mappen `/etc/voxip-kiosk`, `/var/lib/voxip-kiosk*` en +`/usr/lib/voxip-kiosk`, en de gebruiker `voxip`. De eerste update naar een +nieuwere versie zet zo'n kiosk eenmalig over, gewoon via de webinterface of +'s nachts automatisch: + +- services, programma's en instellingen krijgen de `daynivo-`-namen; de oude + services worden uitgeschakeld en verwijderd; +- configuratie, beheerderswachtwoord, browserprofiel (offline-cache), logs en + updatestatus verhuizen naar de `daynivo-`-mappen; de oude mapnamen blijven + als verwijzing bestaan; +- de gebruiker `voxip` wordt `daynivo`, met hetzelfde uid, zodat alle + bestanden hun eigenaar houden; +- de netwerkprofielen `voxip-eth0`/`voxip-wlan0` worden `daynivo-eth0`/ + `daynivo-wlan0` (niet zolang er een netwerkwijziging op bevestiging wacht; + dan bij de volgende update); +- wie in de Kiosk Manager was ingelogd, moet één keer opnieuw inloggen. + +Op de bootpartitie blijven `voxip-config.json`, `voxip-authorized_keys` en +`voxip-network-reset` werken, net als de opdracht `voxip-kiosk-ctl`. Bij het +bouwen van een image worden `VOXIP_DEFAULT_URL` en `VOXIP_DEVICE_NAME` nog +gelezen als de `DAYNIVO_`-varianten ontbreken. + ### Verwijderen ```bash @@ -109,7 +134,7 @@ sudo ./uninstall.sh --purge # ook configuratie, status, logs, netwerkprofielen Het image wordt gebouwd met [pi-gen](https://github.com/RPi-Distro/pi-gen), de officiële bouwtool van Raspberry Pi OS. De extra stage -`image/stage-voxip` voert hetzelfde `install.sh` uit als een handmatige +`image/stage-daynivo` voert hetzelfde `install.sh` uit als een handmatige installatie. Vereist: een Linux-buildmachine (x86_64 of arm64) met Docker en git. Op @@ -131,14 +156,14 @@ Instelbaar via omgevingsvariabelen: |---|---|---| | `PI_GEN_REF` | `2024-11-19-raspios-bookworm-armhf` | pi-gen-tag (32-bit) | | `RELEASE` | `bookworm` | `bookworm` of `trixie` (moet bij `PI_GEN_REF` passen) | -| `VOXIP_DEFAULT_URL` | `https://schermen-ijsselflat.voxip.nl` | standaard kiosk-URL | -| `VOXIP_DEVICE_NAME` | `Daynivo Kiosk` | standaard apparaatnaam | +| `DAYNIVO_DEFAULT_URL` | `https://schermen-ijsselflat.voxip.nl` | standaard kiosk-URL | +| `DAYNIVO_DEVICE_NAME` | `Daynivo Kiosk` | standaard apparaatnaam | | `TARGET_HOSTNAME` | `kiosk` | hostname (`http://.local:8080`) | | `ALLOW_DIRTY` | `0` | `1` = bouw de werkmap in plaats van de laatste commit | **Reproduceerbaarheid.** pi-gen staat vast op een tag en de broncode gaat via `git archive` van één commit mee. Beide staan in `BUILD-INFO` -(ook in de image: `/usr/share/voxip-kiosk/BUILD-INFO`). De Debian- en +(ook in de image: `/usr/share/daynivo-kiosk/BUILD-INFO`). De Debian- en Raspberry Pi-pakketten komen uit de archieven zoals die op het moment van bouwen zijn. Er bestaat geen snapshot-archief voor Raspberry Pi OS, dus twee builds op verschillende dagen kunnen nieuwere pakketversies bevatten. @@ -199,10 +224,10 @@ sudo daynivo-kiosk-ctl reload # pagina herladen sudo daynivo-kiosk-ctl restart-browser # Chromium herstarten sudo daynivo-kiosk-ctl health # healthcheck-rapport sudo daynivo-kiosk-ctl maintenance on|off # healthcheck tijdelijk niets laten herstellen -journalctl -u voxip-kiosk-browser -u voxip-kiosk-agent -f +journalctl -u daynivo-kiosk-browser -u daynivo-kiosk-agent -f ``` -### Configuratie — `/etc/voxip-kiosk/config.json` +### Configuratie — `/etc/daynivo-kiosk/config.json` | Sleutel | Standaard | Betekenis | |---|---|---| @@ -270,8 +295,8 @@ make dev # http://127.0.0.1:8080 met tijdelijke mappen in .dev/ | Symptoom | Oplossing | |---|---| -| Zwart scherm na opstarten | `sudo daynivo-kiosk-ctl status`. Kijk in de journal van `voxip-kiosk-x`/`voxip-kiosk-browser`. Staat de monitor aan vóór de Pi? | +| Zwart scherm na opstarten | `sudo daynivo-kiosk-ctl status`. Kijk in de journal van `daynivo-kiosk-x`/`daynivo-kiosk-browser`. Staat de monitor aan vóór de Pi? | | Beheerinterface onbereikbaar na netwerkwijziging | Wacht 3 minuten (automatische rollback) of zet `daynivo-network-reset` op de bootpartitie en herstart. | -| Wachtwoord vergeten | `sudo daynivo-kiosk-ctl reset-password` via SSH, of verwijder `/etc/voxip-kiosk/admin.json` met de SD-kaart in een Linux-pc. | +| Wachtwoord vergeten | `sudo daynivo-kiosk-ctl reset-password` via SSH, of verwijder `/etc/daynivo-kiosk/admin.json` met de SD-kaart in een Linux-pc. | | `kiosk.local` werkt niet | Gebruik het IP-adres (staat op het setupscherm en in je router). Windows heeft soms Bonjour/mDNS nodig. Geef iedere kiosk een unieke hostname. | | Onderspanning in het dashboard | Gebruik de officiële 5,1 V/2,5 A-voeding. Onderspanning veroorzaakt crashes en SD-kaartcorruptie. | diff --git a/bin/daynivo-kiosk-agent b/bin/daynivo-kiosk-agent new file mode 100755 index 0000000..bc61d73 --- /dev/null +++ b/bin/daynivo-kiosk-agent @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.agent import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/daynivo-kiosk-browser b/bin/daynivo-kiosk-browser new file mode 100755 index 0000000..83d2eb4 --- /dev/null +++ b/bin/daynivo-kiosk-browser @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.browser import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/daynivo-kiosk-ctl b/bin/daynivo-kiosk-ctl index ecb2b6a..83a7b8e 100755 --- a/bin/daynivo-kiosk-ctl +++ b/bin/daynivo-kiosk-ctl @@ -1,8 +1,8 @@ #!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. import sys -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") from daynivo_kiosk.ctl import main # noqa: E402 diff --git a/bin/daynivo-kiosk-healthcheck b/bin/daynivo-kiosk-healthcheck new file mode 100755 index 0000000..f3af26a --- /dev/null +++ b/bin/daynivo-kiosk-healthcheck @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.healthcheck import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/daynivo-kiosk-helper b/bin/daynivo-kiosk-helper new file mode 100755 index 0000000..1c6fd5f --- /dev/null +++ b/bin/daynivo-kiosk-helper @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.helper import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/daynivo-kiosk-manager b/bin/daynivo-kiosk-manager new file mode 100755 index 0000000..5e84097 --- /dev/null +++ b/bin/daynivo-kiosk-manager @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.manager import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/daynivo-kiosk-updater b/bin/daynivo-kiosk-updater new file mode 100755 index 0000000..a47433a --- /dev/null +++ b/bin/daynivo-kiosk-updater @@ -0,0 +1,9 @@ +#!/usr/bin/python3 -I +# Installed to /usr/lib/daynivo-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. +import sys + +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") + +from daynivo_kiosk.updater import main # noqa: E402 + +sys.exit(main()) diff --git a/bin/voxip-kiosk-x b/bin/daynivo-kiosk-x similarity index 83% rename from bin/voxip-kiosk-x rename to bin/daynivo-kiosk-x index 6754eaa..f459b2c 100755 --- a/bin/voxip-kiosk-x +++ b/bin/daynivo-kiosk-x @@ -2,7 +2,7 @@ # Starts the kiosk X server on vt7 for user "kiosk" (via Xorg.wrap). # A fresh MIT cookie per start; Chromium reads it via XAUTHORITY. set -eu -AUTH="${RUNTIME_DIRECTORY:-/run/voxip-kiosk-x}/Xauthority" +AUTH="${RUNTIME_DIRECTORY:-/run/daynivo-kiosk-x}/Xauthority" umask 077 : > "$AUTH" xauth -q -f "$AUTH" add :0 . "$(mcookie)" diff --git a/bin/voxip-kiosk-agent b/bin/voxip-kiosk-agent deleted file mode 100755 index 856eaff..0000000 --- a/bin/voxip-kiosk-agent +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.agent import main # noqa: E402 - -sys.exit(main()) diff --git a/bin/voxip-kiosk-browser b/bin/voxip-kiosk-browser deleted file mode 100755 index bb9858f..0000000 --- a/bin/voxip-kiosk-browser +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.browser import main # noqa: E402 - -sys.exit(main()) diff --git a/bin/voxip-kiosk-healthcheck b/bin/voxip-kiosk-healthcheck deleted file mode 100755 index 39e2fe5..0000000 --- a/bin/voxip-kiosk-healthcheck +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.healthcheck import main # noqa: E402 - -sys.exit(main()) diff --git a/bin/voxip-kiosk-helper b/bin/voxip-kiosk-helper deleted file mode 100755 index cf3c7ee..0000000 --- a/bin/voxip-kiosk-helper +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.helper import main # noqa: E402 - -sys.exit(main()) diff --git a/bin/voxip-kiosk-manager b/bin/voxip-kiosk-manager deleted file mode 100755 index 8417caf..0000000 --- a/bin/voxip-kiosk-manager +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.manager import main # noqa: E402 - -sys.exit(main()) diff --git a/bin/voxip-kiosk-updater b/bin/voxip-kiosk-updater deleted file mode 100755 index 38a68bf..0000000 --- a/bin/voxip-kiosk-updater +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python3 -I -# Installed to /usr/lib/voxip-kiosk/ by install.sh. -I: ignore PYTHON* env and user site-packages. -import sys - -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") - -from daynivo_kiosk.updater import main # noqa: E402 - -sys.exit(main()) diff --git a/config/avahi-voxip.service b/config/avahi-daynivo.service similarity index 100% rename from config/avahi-voxip.service rename to config/avahi-daynivo.service diff --git a/config/chromium/voxip-kiosk.json b/config/chromium/daynivo-kiosk.json similarity index 100% rename from config/chromium/voxip-kiosk.json rename to config/chromium/daynivo-kiosk.json diff --git a/config/logrotate b/config/logrotate index 4100229..272d888 100644 --- a/config/logrotate +++ b/config/logrotate @@ -1,4 +1,4 @@ -/var/log/voxip-kiosk/*.log { +/var/log/daynivo-kiosk/*.log { weekly rotate 8 maxsize 2M @@ -6,6 +6,6 @@ delaycompress missingok notifempty - create 0640 voxip voxip - su voxip voxip + create 0640 daynivo daynivo + su daynivo daynivo } diff --git a/config/plymouth/daynivo-kiosk/daynivo-kiosk.plymouth b/config/plymouth/daynivo-kiosk/daynivo-kiosk.plymouth new file mode 100644 index 0000000..265aa6d --- /dev/null +++ b/config/plymouth/daynivo-kiosk/daynivo-kiosk.plymouth @@ -0,0 +1,8 @@ +[Plymouth Theme] +Name=daynivo-kiosk +Description=Daynivo Kiosk boot splash (logo on white) +ModuleName=script + +[script] +ImageDir=/usr/share/plymouth/themes/daynivo-kiosk +ScriptFile=/usr/share/plymouth/themes/daynivo-kiosk/daynivo-kiosk.script diff --git a/config/plymouth/voxip-kiosk/voxip-kiosk.script b/config/plymouth/daynivo-kiosk/daynivo-kiosk.script similarity index 100% rename from config/plymouth/voxip-kiosk/voxip-kiosk.script rename to config/plymouth/daynivo-kiosk/daynivo-kiosk.script diff --git a/config/plymouth/voxip-kiosk/logo.png b/config/plymouth/daynivo-kiosk/logo.png similarity index 100% rename from config/plymouth/voxip-kiosk/logo.png rename to config/plymouth/daynivo-kiosk/logo.png diff --git a/config/plymouth/voxip-kiosk/voxip-kiosk.plymouth b/config/plymouth/voxip-kiosk/voxip-kiosk.plymouth deleted file mode 100644 index bd8902d..0000000 --- a/config/plymouth/voxip-kiosk/voxip-kiosk.plymouth +++ /dev/null @@ -1,8 +0,0 @@ -[Plymouth Theme] -Name=voxip-kiosk -Description=Daynivo Kiosk boot splash (logo on white) -ModuleName=script - -[script] -ImageDir=/usr/share/plymouth/themes/voxip-kiosk -ScriptFile=/usr/share/plymouth/themes/voxip-kiosk/voxip-kiosk.script diff --git a/config/sudoers b/config/sudoers index 4df319a..88b2eba 100644 --- a/config/sudoers +++ b/config/sudoers @@ -1,4 +1,4 @@ -# Daynivo Kiosk OS: the web interface (user voxip) may run exactly one program +# Daynivo Kiosk OS: the web interface (user daynivo) may run exactly one program # as root: the restricted helper, which validates all of its input itself. -Defaults:voxip !requiretty -voxip ALL=(root) NOPASSWD: /usr/lib/voxip-kiosk/voxip-kiosk-helper +Defaults:daynivo !requiretty +daynivo ALL=(root) NOPASSWD: /usr/lib/daynivo-kiosk/daynivo-kiosk-helper diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 9d8b5aa..855b92e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -11,7 +11,7 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt. - Eén HTTPS-pagina fullscreen in Chromium, zonder desktopomgeving. - Lokale webbeheerinterface (*Daynivo Kiosk Manager*) op poort 8080. - Geen klantspecifieke code: alles wat per klant verschilt staat in - `/etc/voxip-kiosk/config.json` en kan bij uitrol via de bootpartitie + `/etc/daynivo-kiosk/config.json` en kan bij uitrol via de bootpartitie worden meegegeven (`daynivo-config.json`). ## Overzicht @@ -19,25 +19,25 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt. ``` ┌──────────────────────── Raspberry Pi ────────────────────────┐ │ │ - HDMI ◄────────┤ voxip-kiosk-x.service Xorg :0 op vt7 (user kiosk) │ + HDMI ◄────────┤ daynivo-kiosk-x.service Xorg :0 op vt7 (user kiosk) │ │ ▲ │ │ │ DISPLAY=:0 │ - │ voxip-kiosk-browser.service Chromium --kiosk (user kiosk) │ + │ daynivo-kiosk-browser.service Chromium --kiosk (user kiosk) │ │ ▲ CDP 127.0.0.1:9222 │ │ │ ┌─────────────────────────────┐ │ - │ ├──┤ voxip-kiosk-agent.service │ navigatie, offline-│ + │ ├──┤ daynivo-kiosk-agent.service │ navigatie, offline-│ │ │ │ (user kiosk) │ pagina, verversen, │ │ │ └─────────────────────────────┘ hang-detectie │ │ │ │ - LAN :8080 ───►│ voxip-kiosk-manager.service Flask + gunicorn (user voxip) │ + LAN :8080 ───►│ daynivo-kiosk-manager.service Flask + gunicorn (user daynivo) │ │ │ sudo -n (één commando) │ │ ▼ │ - │ voxip-kiosk-helper root, vaste werkwoorden, │ + │ daynivo-kiosk-helper root, vaste werkwoorden, │ │ strikte invoervalidatie │ │ │ - │ voxip-kiosk-healthcheck.timer elke minuut, root │ - │ voxip-network-guard.service netwerk-rollback bij boot │ - │ voxip-boot-import.service config/SSH-sleutels vanaf │ + │ daynivo-kiosk-healthcheck.timer elke minuut, root │ + │ daynivo-network-guard.service netwerk-rollback bij boot │ + │ daynivo-boot-import.service config/SSH-sleutels vanaf │ │ de bootpartitie │ └──────────────────────────────────────────────────────────────┘ ``` @@ -46,16 +46,16 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt. | Onderdeel | Gebruiker | Taak | |---|---|---| -| `voxip-kiosk-x` | `kiosk` (via Xorg.wrap) | Minimale X-server op vt7, zonder cursor, zonder TCP. | -| `voxip-kiosk-browser` | `kiosk` | Past rotatie/resolutie/DPMS toe (xrandr/xset), ruimt een vastgelopen profiel op en start Chromium. | -| `voxip-kiosk-agent` | `kiosk` | Bestuurt Chromium via het DevTools Protocol op localhost: offline-pagina, URL-wissel zonder herstart, periodiek verversen, hang-detectie. | -| `voxip-kiosk-manager` | `voxip` | Flask-webinterface (gunicorn, 1 worker, 4 threads). | -| `voxip-kiosk-helper` | `root` (via sudo) | Enige geprivilegieerde ingang: reboot, uitschakelen, Chromium herstarten, hostname, wifi-land, wifi-scan, netwerkconfiguratie + rollback, updates controleren en starten. | -| `voxip-kiosk-updater` | `root` (timer, of eigen transient unit via de helper) | Haalt de nieuwste release op (HTTPS, SHA-256), pakt hem uit in `/opt/daynivo-kiosk-os/` en draait `update.sh --no-pull`. Nooit een oudere of gelijke versie. | -| `voxip-kiosk-healthcheck` | `root` | Bewaakt alle services en herstelt ze, met logging. | +| `daynivo-kiosk-x` | `kiosk` (via Xorg.wrap) | Minimale X-server op vt7, zonder cursor, zonder TCP. | +| `daynivo-kiosk-browser` | `kiosk` | Past rotatie/resolutie/DPMS toe (xrandr/xset), ruimt een vastgelopen profiel op en start Chromium. | +| `daynivo-kiosk-agent` | `kiosk` | Bestuurt Chromium via het DevTools Protocol op localhost: offline-pagina, URL-wissel zonder herstart, periodiek verversen, hang-detectie. | +| `daynivo-kiosk-manager` | `daynivo` | Flask-webinterface (gunicorn, 1 worker, 4 threads). | +| `daynivo-kiosk-helper` | `root` (via sudo) | Enige geprivilegieerde ingang: reboot, uitschakelen, Chromium herstarten, hostname, wifi-land, wifi-scan, netwerkconfiguratie + rollback, updates controleren en starten. | +| `daynivo-kiosk-updater` | `root` (timer, of eigen transient unit via de helper) | Haalt de nieuwste release op (HTTPS, SHA-256), pakt hem uit in `/opt/daynivo-kiosk-os/` en draait `update.sh --no-pull`. Nooit een oudere of gelijke versie. | +| `daynivo-kiosk-healthcheck` | `root` | Bewaakt alle services en herstelt ze, met logging. | De webinterface draait **nooit** als root. De sudoers-regel staat -uitsluitend `/usr/lib/voxip-kiosk/voxip-kiosk-helper` toe. De helper: +uitsluitend `/usr/lib/daynivo-kiosk/daynivo-kiosk-helper` toe. De helper: - draait met `python3 -I` (geen `PYTHONPATH`, geen user site-packages); - kent alleen een vaste lijst werkwoorden; interne werkwoorden (zoals @@ -69,8 +69,8 @@ uitsluitend `/usr/lib/voxip-kiosk/voxip-kiosk-helper` toe. De helper: Xorg en Chromium zijn aparte services. Daardoor is *Chromium herstarten* snel (X blijft draaien) en geeft het exitcode van Chromium direct aan -systemd door. `voxip-kiosk-browser` heeft `Requires=` en `PartOf=` op -`voxip-kiosk-x`: valt X weg, dan start de browser opnieuw mee. +systemd door. `daynivo-kiosk-browser` heeft `Requires=` en `PartOf=` op +`daynivo-kiosk-x`: valt X weg, dan start de browser opnieuw mee. ### Chromium besturen via CDP @@ -86,7 +86,7 @@ webinterface gebruiken dit om: ### Offline-gedrag Chromium start altijd op een lokale startpagina -(`/usr/share/voxip-kiosk/www/start.html`). De agent controleert met een +(`/usr/share/daynivo-kiosk/www/start.html`). De agent controleert met een HTTPS-verzoek (mét certificaatvalidatie) of de doel-URL bereikbaar is en navigeert pas dan. De offline-pagina verschijnt alleen als de pagina niet **geladen** kan worden (startpagina, Chromium-foutpagina). Valt het @@ -111,13 +111,13 @@ draait) kan het apparaat dus claimen, iemand anders op het netwerk niet. 1. De helper maakt een snapshot van `/etc/NetworkManager/system-connections` en van de actieve verbindingen. -2. Hij schrijft het nieuwe profiel (`voxip-eth0` / `voxip-wlan0`, prioriteit +2. Hij schrijft het nieuwe profiel (`daynivo-eth0` / `daynivo-wlan0`, prioriteit 100) en plant een rollback-timer (`systemd-run`, 180 s). 3. Activatie gebeurt asynchroon, zodat het HTTP-antwoord nog aankomt. 4. De beheerder bevestigt binnen 180 s (eventueel via het nieuwe adres), anders zet de timer de snapshot terug. 5. Valt de stroom uit tijdens die periode, dan zet - `voxip-network-guard.service` de snapshot terug bij het opstarten, nog + `daynivo-network-guard.service` de snapshot terug bij het opstarten, nog vóór NetworkManager start. 6. Noodherstel: een leeg bestand `daynivo-network-reset` op de bootpartitie verwijdert bij de volgende boot alle Daynivo-netwerkprofielen (terug naar @@ -125,12 +125,12 @@ draait) kan het apparaat dus claimen, iemand anders op het netwerk niet. ### Configuratie -- `/etc/voxip-kiosk/config.json`: eigenaar `voxip`, groep `kiosk`, 0640. +- `/etc/daynivo-kiosk/config.json`: eigenaar `daynivo`, groep `kiosk`, 0640. Wordt atomair opgeslagen (tijdelijk bestand, `fsync`, `rename`, `fsync` van de map) met een `.bak` van de vorige versie. Ongeldige waarden vallen bij het laden terug op de standaard, zodat de kiosk altijd start. Onbekende sleutels blijven bewaard (vooruit-/achteruitcompatibel). -- `/etc/voxip-kiosk/admin.json`: Argon2id-hash, 0600, alleen `voxip`. +- `/etc/daynivo-kiosk/admin.json`: Argon2id-hash, 0600, alleen `daynivo`. - Updates (`install.sh --upgrade` / `update.sh` / de updater) overschrijven nooit bestaande configuratie. De updater draait in een eigen systemd-unit, zodat het herstarten van de beheerinterface tijdens `install.sh` de update @@ -179,7 +179,7 @@ daynivo-kiosk-os/ ├── install.sh installatie op bestaande Pi OS + gebruikt door image-build ├── update.sh update met backup van configuratie ├── uninstall.sh verwijderen (--purge voor alles) -├── bin/ dunne launchers → /usr/lib/voxip-kiosk/ +├── bin/ dunne launchers → /usr/lib/daynivo-kiosk/ ├── src/daynivo_kiosk/ Python-package (alle logica) │ ├── config.py laden/valideren/atomair opslaan │ ├── validation.py gedeelde invoervalidatie @@ -197,7 +197,7 @@ daynivo-kiosk-os/ ├── www/ lokale kioskpagina's (start, offline, setup) ├── systemd/ unit-bestanden ├── config/ standaardconfig, sudoers, journald, logrotate, … -├── image/ pi-gen image-builder (stage-voxip) +├── image/ pi-gen image-builder (stage-daynivo) ├── tests/ pytest-suite └── docs/ architectuur, hardwaretest ``` diff --git a/docs/HARDWARE-TEST.md b/docs/HARDWARE-TEST.md index 4e8356c..458f55e 100644 --- a/docs/HARDWARE-TEST.md +++ b/docs/HARDWARE-TEST.md @@ -20,7 +20,7 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype. - [ ] Binnen 90 s na stroom aan verschijnt het setupscherm met de setupcode, `http://kiosk.local:8080` en het IP-adres. Er is geen muiscursor en er zijn geen dialoogvensters. -- [ ] SSH is uit (`ssh voxipadmin@kiosk.local` wordt geweigerd), en er is +- [ ] SSH is uit (`ssh daynivoadmin@kiosk.local` wordt geweigerd), en er is geen bruikbaar standaardwachtwoord. ## 2. Initiële configuratie @@ -47,7 +47,7 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype. (zie Logboek → Kiosk-agent). - [ ] Screenshot op de Kiosk-pagina toont wat er op het scherm staat. - [ ] Daynivo-URL met `?token=`: het token is overal gemaskeerd - (dashboard, `daynivo-kiosk-ctl status`, `journalctl -u voxip-kiosk-agent`). + (dashboard, `daynivo-kiosk-ctl status`, `journalctl -u daynivo-kiosk-agent`). ## 4. Herstel @@ -61,9 +61,9 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype. Zet de URL daarna terug. - [ ] Vastgelopen pagina: open via SSH-tunnel DevTools of zet een testpagina met `while(true){}` in. Na ±15 s herlaadt de agent, na ±30 s herstart Chromium. -- [ ] `sudo systemctl stop voxip-kiosk-agent`: de healthcheck start hem binnen 2 minuten. +- [ ] `sudo systemctl stop daynivo-kiosk-agent`: de healthcheck start hem binnen 2 minuten. - [ ] De webinterface blijft werken terwijl Chromium gestopt is - (`sudo systemctl stop voxip-kiosk-browser`). + (`sudo systemctl stop daynivo-kiosk-browser`). ## 5. Netwerk @@ -123,11 +123,11 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype. op Gitea: "beschikbaar". *Bijwerken naar …*: binnen enkele minuten is de nieuwe versie actief, de beheerinterface komt terug, configuratie en wachtwoord ongewijzigd. -- [ ] *Automatisch bijwerken* aan, `sudo systemctl start voxip-kiosk-update.service`: +- [ ] *Automatisch bijwerken* aan, `sudo systemctl start daynivo-kiosk-update.service`: de nieuwere release wordt geïnstalleerd. Met het vinkje uit: alleen gecontroleerd. - [ ] `curl -fsSL https://daynivo.nl/kiosk/install.sh | sudo bash` op een verse Raspberry Pi OS Lite: installeert de nieuwste release, setupcode op het scherm. - [ ] `sudo ./uninstall.sh --purge` op een testkaart: geen Daynivo-services of - -bestanden meer (`systemctl list-unit-files | grep voxip` is leeg). + -bestanden meer (`systemctl list-unit-files | grep daynivo` is leeg). - [ ] Installatie op een bestaande Raspberry Pi OS Lite (Bookworm) met de Daynivo-kiosk erop: URL overgenomen, `display-kiosk.service` uitgeschakeld. diff --git a/image/boot-README.txt b/image/boot-README.txt index c7f7b7b..07957dd 100644 --- a/image/boot-README.txt +++ b/image/boot-README.txt @@ -8,7 +8,7 @@ een fout; de reden staat dan in daynivo-config.error.txt). daynivo-config.json Instellingen voor deze kiosk. Zie daynivo-config.example.json. Toegestaan: - alle sleutels uit /etc/voxip-kiosk/config.json plus "hostname" en + alle sleutels uit /etc/daynivo-kiosk/config.json plus "hostname" en "wifi_country". Voorbeeld: { @@ -20,7 +20,7 @@ daynivo-config.json daynivo-authorized_keys Openbare SSH-sleutels (één per regel). SSH wordt dan ingeschakeld, alleen - met sleutel-login, voor de beheerder (voxipadmin of de gebruiker die je + met sleutel-login, voor de beheerder (daynivoadmin of de gebruiker die je in Raspberry Pi Imager hebt aangemaakt). daynivo-network-reset diff --git a/image/build.sh b/image/build.sh index 52dddd6..d8f0493 100755 --- a/image/build.sh +++ b/image/build.sh @@ -8,8 +8,8 @@ # Environment (all optional): # PI_GEN_REF pi-gen tag/branch (32-bit armhf). Default: pinned Bookworm release. # RELEASE bookworm | trixie (must match PI_GEN_REF). Default: bookworm. -# VOXIP_DEFAULT_URL kiosk URL baked into the default config. -# VOXIP_DEVICE_NAME default device name. +# DAYNIVO_DEFAULT_URL kiosk URL baked into the default config. +# DAYNIVO_DEVICE_NAME default device name. # TARGET_HOSTNAME default hostname (the admin UI is at http://.local:8080). # ALLOW_DIRTY=1 build from the working tree instead of the committed HEAD. # @@ -23,8 +23,9 @@ OUT="$ROOT/image/deploy" PI_GEN_REPO="${PI_GEN_REPO:-https://github.com/RPi-Distro/pi-gen.git}" PI_GEN_REF="${PI_GEN_REF:-2024-11-19-raspios-bookworm-armhf}" RELEASE="${RELEASE:-bookworm}" -VOXIP_DEFAULT_URL="${VOXIP_DEFAULT_URL:-https://schermen-ijsselflat.voxip.nl}" -VOXIP_DEVICE_NAME="${VOXIP_DEVICE_NAME:-Daynivo Kiosk}" +# VOXIP_* are the names from before the rename and still work. +DAYNIVO_DEFAULT_URL="${DAYNIVO_DEFAULT_URL:-${VOXIP_DEFAULT_URL:-https://schermen-ijsselflat.voxip.nl}}" +DAYNIVO_DEVICE_NAME="${DAYNIVO_DEVICE_NAME:-${VOXIP_DEVICE_NAME:-Daynivo Kiosk}}" TARGET_HOSTNAME="${TARGET_HOSTNAME:-kiosk}" NATIVE=0 [[ ${1:-} == "--native" ]] && NATIVE=1 @@ -45,13 +46,13 @@ git clone --quiet --depth 1 --branch "$PI_GEN_REF" "$PI_GEN_REPO" "$WORK/pi-gen" PI_GEN_COMMIT="$(git -C "$WORK/pi-gen" rev-parse HEAD)" PIGEN="$WORK/pi-gen" -# Do not export the plain Lite image from stage2; ours is exported after stage-voxip. +# Do not export the plain Lite image from stage2; ours is exported after stage-daynivo. touch "$PIGEN/stage2/SKIP_IMAGES" rm -f "$PIGEN/stage2/EXPORT_NOOBS" echo "==> Daynivo-stage voorbereiden" -cp -a "$ROOT/image/stage-voxip" "$PIGEN/stage-voxip" -PAYLOAD="$PIGEN/stage-voxip/00-voxip/files/voxip-kiosk" +cp -a "$ROOT/image/stage-daynivo" "$PIGEN/stage-daynivo" +PAYLOAD="$PIGEN/stage-daynivo/00-daynivo/files/daynivo-kiosk" mkdir -p "$PAYLOAD" if [[ ${ALLOW_DIRTY:-0} == 1 ]] || ! git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1; then echo " (werkmap wordt gebruikt, niet de laatste commit)" @@ -67,9 +68,9 @@ else fi BUILD_DATE="$(date -u +%Y-%m-%d)" -cat > "$PIGEN/stage-voxip/00-voxip/files/build.env" < "$PIGEN/stage-daynivo/00-daynivo/files/build.env" < "$PAYLOAD/BUILD-INFO" < Image bouwen (dit duurt 30–90 minuten)" diff --git a/image/stage-daynivo/00-daynivo/00-run.sh b/image/stage-daynivo/00-daynivo/00-run.sh new file mode 100755 index 0000000..9816a34 --- /dev/null +++ b/image/stage-daynivo/00-daynivo/00-run.sh @@ -0,0 +1,23 @@ +#!/bin/bash -e +# Install Daynivo Kiosk OS into the image with the same install.sh that is +# used on existing Raspberry Pi OS installations. + +# shellcheck disable=SC1091 +source files/build.env + +rm -rf "${ROOTFS_DIR}/usr/src/daynivo-kiosk" +install -d "${ROOTFS_DIR}/usr/src/daynivo-kiosk" +cp -a files/daynivo-kiosk/. "${ROOTFS_DIR}/usr/src/daynivo-kiosk/" + +on_chroot << EOF_CHROOT +/usr/src/daynivo-kiosk/install.sh --image --url $(printf %q "${DAYNIVO_DEFAULT_URL}") --name $(printf %q "${DAYNIVO_DEVICE_NAME}") +install -m 0644 /usr/src/daynivo-kiosk/BUILD-INFO /usr/share/daynivo-kiosk/BUILD-INFO +# No usable default password: unlocked only by Raspberry Pi Imager credentials. +passwd -l ${FIRST_USER_NAME} +systemctl disable ssh.service 2>/dev/null || true +apt-get clean +EOF_CHROOT + +# Instructions next to config.txt for whoever opens the boot partition. +install -m 0644 files/daynivo-kiosk/image/boot-README.txt "${ROOTFS_DIR}/boot/firmware/DAYNIVO-LEESMIJ.txt" +install -m 0644 files/daynivo-kiosk/image/daynivo-config.example.json "${ROOTFS_DIR}/boot/firmware/daynivo-config.example.json" diff --git a/image/stage-voxip/EXPORT_IMAGE b/image/stage-daynivo/EXPORT_IMAGE similarity index 100% rename from image/stage-voxip/EXPORT_IMAGE rename to image/stage-daynivo/EXPORT_IMAGE diff --git a/image/stage-voxip/prerun.sh b/image/stage-daynivo/prerun.sh similarity index 100% rename from image/stage-voxip/prerun.sh rename to image/stage-daynivo/prerun.sh diff --git a/image/stage-voxip/00-voxip/00-run.sh b/image/stage-voxip/00-voxip/00-run.sh deleted file mode 100755 index 94c8beb..0000000 --- a/image/stage-voxip/00-voxip/00-run.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e -# Install Daynivo Kiosk OS into the image with the same install.sh that is -# used on existing Raspberry Pi OS installations. - -# shellcheck disable=SC1091 -source files/build.env - -rm -rf "${ROOTFS_DIR}/usr/src/voxip-kiosk" -install -d "${ROOTFS_DIR}/usr/src/voxip-kiosk" -cp -a files/voxip-kiosk/. "${ROOTFS_DIR}/usr/src/voxip-kiosk/" - -on_chroot << EOF_CHROOT -/usr/src/voxip-kiosk/install.sh --image --url $(printf %q "${VOXIP_DEFAULT_URL}") --name $(printf %q "${VOXIP_DEVICE_NAME}") -install -m 0644 /usr/src/voxip-kiosk/BUILD-INFO /usr/share/voxip-kiosk/BUILD-INFO -# No usable default password: unlocked only by Raspberry Pi Imager credentials. -passwd -l ${FIRST_USER_NAME} -systemctl disable ssh.service 2>/dev/null || true -apt-get clean -EOF_CHROOT - -# Instructions next to config.txt for whoever opens the boot partition. -install -m 0644 files/voxip-kiosk/image/boot-README.txt "${ROOTFS_DIR}/boot/firmware/VOXIP-LEESMIJ.txt" -install -m 0644 files/voxip-kiosk/image/daynivo-config.example.json "${ROOTFS_DIR}/boot/firmware/daynivo-config.example.json" diff --git a/install.sh b/install.sh index ed2c5e0..978f5f2 100755 --- a/install.sh +++ b/install.sh @@ -8,9 +8,9 @@ # # sudo ./install.sh [--url https://…] [--name "Hal begane grond"] [--hostname hal-bg] # sudo ./install.sh --upgrade # update code, keep configuration -# ./install.sh --image … # used by image/stage-voxip (no service starts) +# ./install.sh --image … # used by image/stage-daynivo (no service starts) # -# Existing configuration in /etc/voxip-kiosk is never overwritten. +# Existing configuration in /etc/daynivo-kiosk is never overwritten. set -euo pipefail @@ -21,15 +21,15 @@ NAME="" NEW_HOSTNAME="" FORCE=0 -LIB=/usr/lib/voxip-kiosk -SHARE=/usr/share/voxip-kiosk -DOC=/usr/share/doc/voxip-kiosk -ETC=/etc/voxip-kiosk -UNITS=(voxip-kiosk-x.service voxip-kiosk-browser.service voxip-kiosk-agent.service voxip-kiosk-manager.service - voxip-kiosk-healthcheck.service voxip-kiosk-healthcheck.timer voxip-network-guard.service voxip-boot-import.service - voxip-kiosk-update.service voxip-kiosk-update.timer) -ENABLE=(voxip-kiosk-x.service voxip-kiosk-browser.service voxip-kiosk-agent.service voxip-kiosk-manager.service - voxip-kiosk-healthcheck.timer voxip-network-guard.service voxip-boot-import.service voxip-kiosk-update.timer) +LIB=/usr/lib/daynivo-kiosk +SHARE=/usr/share/daynivo-kiosk +DOC=/usr/share/doc/daynivo-kiosk +ETC=/etc/daynivo-kiosk +UNITS=(daynivo-kiosk-x.service daynivo-kiosk-browser.service daynivo-kiosk-agent.service daynivo-kiosk-manager.service + daynivo-kiosk-healthcheck.service daynivo-kiosk-healthcheck.timer daynivo-network-guard.service daynivo-boot-import.service + daynivo-kiosk-update.service daynivo-kiosk-update.timer) +ENABLE=(daynivo-kiosk-x.service daynivo-kiosk-browser.service daynivo-kiosk-agent.service daynivo-kiosk-manager.service + daynivo-kiosk-healthcheck.timer daynivo-network-guard.service daynivo-boot-import.service daynivo-kiosk-update.timer) say() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } warn() { printf '\033[1;33mLet op:\033[0m %s\n' "$*" >&2; } @@ -106,6 +106,75 @@ pkg_available() { apt-cache policy "$1" 2>/dev/null | grep -q 'Candidate: [0-9]' apt-get install -y --no-install-recommends "${PKGS[@]}" } +# --- migration from the VoxIP names --------------------------------------------------- +# Kiosks installed before the rename (up to 1.2.x) use voxip-* services and folders +# and a "voxip" user. Move them over once, keeping the configuration, the password, +# the browser profile (offline cache) and the network settings. The old folder +# names stay as symlinks for whatever still runs from the old version, such as +# the updater that started this upgrade. +if [[ -d /etc/voxip-kiosk && ! -L /etc/voxip-kiosk && ! -e /etc/daynivo-kiosk ]]; then + say "Overstappen van de VoxIP-namen naar Daynivo" + if [[ $LIVE -eq 1 ]]; then + # Not voxip-kiosk-update.service: a nightly auto-update runs this very script in it. + systemctl stop voxip-kiosk-healthcheck.timer voxip-kiosk-update.timer voxip-kiosk-agent.service \ + voxip-kiosk-browser.service voxip-kiosk-x.service voxip-kiosk-manager.service 2>/dev/null || true + fi + for unit in voxip-kiosk-x.service voxip-kiosk-browser.service voxip-kiosk-agent.service voxip-kiosk-manager.service \ + voxip-kiosk-healthcheck.service voxip-kiosk-healthcheck.timer voxip-kiosk-update.service \ + voxip-kiosk-update.timer voxip-network-guard.service voxip-boot-import.service; do + systemctl disable "$unit" >/dev/null 2>&1 || true + rm -f "/etc/systemd/system/$unit" + done + if [[ $LIVE -eq 1 ]]; then systemctl daemon-reload; fi + + for old in /etc/voxip-kiosk /var/lib/voxip-kiosk /var/lib/voxip-kiosk-network /var/lib/voxip-kiosk-browser \ + /var/log/voxip-kiosk /var/cache/voxip-kiosk; do + new="${old/voxip/daynivo}" + if [[ -d $old && ! -L $old && ! -e $new ]]; then + mv "$old" "$new" + ln -s "$new" "$old" + fi + done + + # Same uid and gid, so every file keeps the right owner. + if id voxip >/dev/null 2>&1 && ! id daynivo >/dev/null 2>&1; then + usermod -l daynivo -d /var/lib/daynivo-kiosk voxip + if getent group voxip >/dev/null; then groupmod -n daynivo voxip; fi + fi + + # Network profiles written by the web interface; not while a change awaits confirmation. + if [[ ! -f /var/lib/daynivo-kiosk-network/pending.json ]]; then + renamed=0 + for iface in eth0 wlan0; do + old=/etc/NetworkManager/system-connections/voxip-$iface.nmconnection + new=/etc/NetworkManager/system-connections/daynivo-$iface.nmconnection + if [[ -f $old && ! -e $new ]]; then + sed -i "s/^id=voxip-$iface\$/id=daynivo-$iface/" "$old" + mv "$old" "$new" + chmod 0600 "$new" + renamed=1 + fi + done + if [[ $renamed -eq 1 && $LIVE -eq 1 ]]; then nmcli connection reload 2>/dev/null || true; fi + fi + + rm -f /etc/sudoers.d/voxip-kiosk /etc/systemd/journald.conf.d/voxip-kiosk.conf \ + /etc/systemd/system.conf.d/voxip-watchdog.conf /etc/logrotate.d/voxip-kiosk \ + /etc/avahi/services/voxip-kiosk.service /etc/chromium/policies/managed/voxip-kiosk.json \ + /etc/chromium-browser/policies/managed/voxip-kiosk.json /usr/local/sbin/voxip-kiosk-ctl + if [[ -f /etc/ssh/sshd_config.d/voxip-kiosk.conf ]]; then + mv /etc/ssh/sshd_config.d/voxip-kiosk.conf /etc/ssh/sshd_config.d/daynivo-kiosk.conf + fi + if [[ -f /etc/X11/Xwrapper.config.voxip-orig ]]; then + mv /etc/X11/Xwrapper.config.voxip-orig /etc/X11/Xwrapper.config.daynivo-orig + fi + if [[ -f /etc/systemd/system/display-kiosk.service.voxip-disabled ]]; then + mv /etc/systemd/system/display-kiosk.service.voxip-disabled /etc/systemd/system/display-kiosk.service.daynivo-disabled + fi + # The old programs: an updater that started this install has its code loaded already. + rm -rf /usr/lib/voxip-kiosk /usr/share/voxip-kiosk /usr/share/doc/voxip-kiosk /usr/share/plymouth/themes/voxip-kiosk +fi + # --- users ---------------------------------------------------------------------- say "Gebruikers aanmaken" getent group kiosk >/dev/null || groupadd --system kiosk @@ -114,11 +183,11 @@ id kiosk >/dev/null 2>&1 || useradd --system --gid kiosk --home-dir /home/kiosk for g in video render input audio; do getent group "$g" >/dev/null && usermod -aG "$g" kiosk done -getent group voxip >/dev/null || groupadd --system voxip -id voxip >/dev/null 2>&1 || useradd --system --gid voxip --home-dir /var/lib/voxip-kiosk --no-create-home \ - --shell /usr/sbin/nologin --comment "Daynivo Kiosk Manager" voxip +getent group daynivo >/dev/null || groupadd --system daynivo +id daynivo >/dev/null 2>&1 || useradd --system --gid daynivo --home-dir /var/lib/daynivo-kiosk --no-create-home \ + --shell /usr/sbin/nologin --comment "Daynivo Kiosk Manager" daynivo for g in systemd-journal video; do - getent group "$g" >/dev/null && usermod -aG "$g" voxip + getent group "$g" >/dev/null && usermod -aG "$g" daynivo done # --- application files -------------------------------------------------------------- @@ -135,7 +204,7 @@ rm -rf "$LIB/python.old" mv "$LIB/python.new" "$LIB/python" rm -rf "$LIB/python.old" -for bin in voxip-kiosk-agent voxip-kiosk-browser voxip-kiosk-healthcheck voxip-kiosk-helper voxip-kiosk-manager voxip-kiosk-updater voxip-kiosk-x; do +for bin in daynivo-kiosk-agent daynivo-kiosk-browser daynivo-kiosk-healthcheck daynivo-kiosk-helper daynivo-kiosk-manager daynivo-kiosk-updater daynivo-kiosk-x; do install -m 0755 -o root -g root "$SRC/bin/$bin" "$LIB/$bin" done install -m 0755 -o root -g root "$SRC/bin/daynivo-kiosk-ctl" /usr/local/sbin/daynivo-kiosk-ctl @@ -151,10 +220,10 @@ install -m 0644 "$SRC"/docs/*.md "$DOC/" # --- configuration ------------------------------------------------------------------- say "Configuratie" -install -d -o voxip -g kiosk -m 2750 "$ETC" -install -d -o voxip -g voxip -m 0750 /var/lib/voxip-kiosk -install -d -o root -g root -m 0755 /var/lib/voxip-kiosk-network -install -d -o voxip -g voxip -m 0750 /var/log/voxip-kiosk +install -d -o daynivo -g kiosk -m 2750 "$ETC" +install -d -o daynivo -g daynivo -m 0750 /var/lib/daynivo-kiosk +install -d -o root -g root -m 0755 /var/lib/daynivo-kiosk-network +install -d -o daynivo -g daynivo -m 0750 /var/log/daynivo-kiosk # Migrate from Daynivo's raspberry-pi/install-kiosk.sh: take over its URL, then disable it. LEGACY_KIOSK_UNIT=/etc/systemd/system/display-kiosk.service @@ -165,13 +234,13 @@ if [[ -f $LEGACY_KIOSK_UNIT ]]; then say "URL overgenomen van de Daynivo-kioskinstallatie" fi if [[ $LIVE -eq 1 ]]; then systemctl disable --now display-kiosk.service 2>/dev/null || true; fi - mv "$LEGACY_KIOSK_UNIT" "$LEGACY_KIOSK_UNIT.voxip-disabled" + mv "$LEGACY_KIOSK_UNIT" "$LEGACY_KIOSK_UNIT.daynivo-disabled" fi PYRUN=(python3 -I -c) "${PYRUN[@]}" ' import json, os, sys -sys.path.insert(0, "/usr/lib/voxip-kiosk/python") +sys.path.insert(0, "/usr/lib/daynivo-kiosk/python") from daynivo_kiosk import config as c path, default, url, name = sys.argv[1:5] updates = {} @@ -194,36 +263,36 @@ else: c.atomic_write_json(c.Path(path), data) print("Nieuwe configuratie aangemaakt") ' "$ETC/config.json" "$SRC/config/config.default.json" "$URL" "$NAME" || die "Ongeldige --url of --name." -chown voxip:kiosk "$ETC/config.json" "$ETC/config.json.bak" 2>/dev/null || true +chown daynivo:kiosk "$ETC/config.json" "$ETC/config.json.bak" 2>/dev/null || true chmod 0640 "$ETC/config.json" -touch "$ETC/.config.lock" && chown voxip:kiosk "$ETC/.config.lock" && chmod 0640 "$ETC/.config.lock" -[[ -f $ETC/admin.json ]] && chown voxip:voxip "$ETC/admin.json" && chmod 0600 "$ETC/admin.json" +touch "$ETC/.config.lock" && chown daynivo:kiosk "$ETC/.config.lock" && chmod 0640 "$ETC/.config.lock" +[[ -f $ETC/admin.json ]] && chown daynivo:daynivo "$ETC/admin.json" && chmod 0600 "$ETC/admin.json" # --- system integration ---------------------------------------------------------------- say "Systeemintegratie" TMP_SUDOERS="$(mktemp)" install -m 0440 "$SRC/config/sudoers" "$TMP_SUDOERS" visudo -cqf "$TMP_SUDOERS" || die "sudoers-bestand ongeldig" -mv "$TMP_SUDOERS" /etc/sudoers.d/voxip-kiosk -chown root:root /etc/sudoers.d/voxip-kiosk +mv "$TMP_SUDOERS" /etc/sudoers.d/daynivo-kiosk +chown root:root /etc/sudoers.d/daynivo-kiosk -install -D -m 0644 "$SRC/config/journald.conf" /etc/systemd/journald.conf.d/voxip-kiosk.conf -install -D -m 0644 "$SRC/config/watchdog.conf" /etc/systemd/system.conf.d/voxip-watchdog.conf -install -D -m 0644 "$SRC/config/logrotate" /etc/logrotate.d/voxip-kiosk +install -D -m 0644 "$SRC/config/journald.conf" /etc/systemd/journald.conf.d/daynivo-kiosk.conf +install -D -m 0644 "$SRC/config/watchdog.conf" /etc/systemd/system.conf.d/daynivo-watchdog.conf +install -D -m 0644 "$SRC/config/logrotate" /etc/logrotate.d/daynivo-kiosk -if [[ -f /etc/X11/Xwrapper.config && ! -f /etc/X11/Xwrapper.config.voxip-orig ]]; then - cp -a /etc/X11/Xwrapper.config /etc/X11/Xwrapper.config.voxip-orig +if [[ -f /etc/X11/Xwrapper.config && ! -f /etc/X11/Xwrapper.config.daynivo-orig ]]; then + cp -a /etc/X11/Xwrapper.config /etc/X11/Xwrapper.config.daynivo-orig fi install -D -m 0644 "$SRC/config/Xwrapper.config" /etc/X11/Xwrapper.config for dir in /etc/chromium/policies/managed /etc/chromium-browser/policies/managed; do - install -D -m 0644 "$SRC/config/chromium/voxip-kiosk.json" "$dir/voxip-kiosk.json" + install -D -m 0644 "$SRC/config/chromium/daynivo-kiosk.json" "$dir/daynivo-kiosk.json" done -ADMIN_PORT="$(python3 -I -c 'import sys; sys.path.insert(0, "/usr/lib/voxip-kiosk/python"); from daynivo_kiosk.config import load_config; print(load_config(__import__("pathlib").Path(sys.argv[1]))["admin_port"])' "$ETC/config.json")" +ADMIN_PORT="$(python3 -I -c 'import sys; sys.path.insert(0, "/usr/lib/daynivo-kiosk/python"); from daynivo_kiosk.config import load_config; print(load_config(__import__("pathlib").Path(sys.argv[1]))["admin_port"])' "$ETC/config.json")" install -d -m 0755 /etc/avahi/services -sed "s#8080#${ADMIN_PORT}#" "$SRC/config/avahi-voxip.service" > /etc/avahi/services/voxip-kiosk.service -chmod 0644 /etc/avahi/services/voxip-kiosk.service +sed "s#8080#${ADMIN_PORT}#" "$SRC/config/avahi-daynivo.service" > /etc/avahi/services/daynivo-kiosk.service +chmod 0644 /etc/avahi/services/daynivo-kiosk.service # Swap: zram in RAM instead of a swap file on the SD card (Trixie's rpi-swap already does this). if dpkg -s systemd-zram-generator >/dev/null 2>&1 && ! dpkg -s rpi-swap >/dev/null 2>&1; then @@ -263,18 +332,18 @@ done # Boot splash: logo on white (config/plymouth). Rebuilding the initramfs takes a while # on a Pi 3, so only when the theme changed. -SPLASH_DIR=/usr/share/plymouth/themes/voxip-kiosk +SPLASH_DIR=/usr/share/plymouth/themes/daynivo-kiosk install -d -m 0755 "$SPLASH_DIR" -install -m 0644 "$SRC"/config/plymouth/voxip-kiosk/* "$SPLASH_DIR/" -if [[ ! -f /var/lib/voxip-kiosk/previous-plymouth-theme ]]; then - plymouth-set-default-theme > /var/lib/voxip-kiosk/previous-plymouth-theme 2>/dev/null || true +install -m 0644 "$SRC"/config/plymouth/daynivo-kiosk/* "$SPLASH_DIR/" +if [[ ! -f /var/lib/daynivo-kiosk/previous-plymouth-theme ]]; then + plymouth-set-default-theme > /var/lib/daynivo-kiosk/previous-plymouth-theme 2>/dev/null || true fi SPLASH_SUM="$(cat "$SPLASH_DIR"/* | sha256sum | cut -d' ' -f1)" -if [[ "$(plymouth-set-default-theme 2>/dev/null)" != voxip-kiosk || "$(cat /var/lib/voxip-kiosk/splash.sha256 2>/dev/null)" != "$SPLASH_SUM" ]]; then +if [[ "$(plymouth-set-default-theme 2>/dev/null)" != daynivo-kiosk || "$(cat /var/lib/daynivo-kiosk/splash.sha256 2>/dev/null)" != "$SPLASH_SUM" ]]; then say "Opstartscherm instellen (initramfs bijwerken, dit duurt even)" - plymouth-set-default-theme voxip-kiosk + plymouth-set-default-theme daynivo-kiosk if update-initramfs -u -k all >/dev/null 2>&1; then - echo "$SPLASH_SUM" > /var/lib/voxip-kiosk/splash.sha256 + echo "$SPLASH_SUM" > /var/lib/daynivo-kiosk/splash.sha256 else warn "initramfs bijwerken mislukt; het opstartscherm verschijnt mogelijk pas later tijdens het opstarten." fi @@ -286,8 +355,8 @@ for dm in lightdm.service gdm3.service sddm.service; do if systemctl is-enabled --quiet "$dm" 2>/dev/null; then warn "$dm wordt uitgeschakeld (de kiosk gebruikt een eigen minimale X-sessie)." systemctl disable "$dm" 2>/dev/null || true - grep -qx "$dm" /var/lib/voxip-kiosk/disabled-display-managers 2>/dev/null \ - || echo "$dm" >> /var/lib/voxip-kiosk/disabled-display-managers + grep -qx "$dm" /var/lib/daynivo-kiosk/disabled-display-managers 2>/dev/null \ + || echo "$dm" >> /var/lib/daynivo-kiosk/disabled-display-managers fi if [[ $LIVE -eq 1 ]] && systemctl is-active --quiet "$dm" 2>/dev/null; then warn "$dm wordt gestopt: de desktop op het scherm sluit nu af." @@ -302,15 +371,15 @@ for unit in "${UNITS[@]}"; do done if [[ $LIVE -eq 1 ]]; then systemctl daemon-reload; fi systemctl enable "${ENABLE[@]}" NetworkManager.service avahi-daemon.service >/dev/null -if [[ ! -f /var/lib/voxip-kiosk/previous-default-target ]]; then - systemctl get-default > /var/lib/voxip-kiosk/previous-default-target 2>/dev/null || true +if [[ ! -f /var/lib/daynivo-kiosk/previous-default-target ]]; then + systemctl get-default > /var/lib/daynivo-kiosk/previous-default-target 2>/dev/null || true fi systemctl set-default multi-user.target >/dev/null if [[ -n $NEW_HOSTNAME && $LIVE -eq 0 ]]; then warn "--hostname wordt genegeerd in image-modus (gebruik TARGET_HOSTNAME van pi-gen)." elif [[ -n $NEW_HOSTNAME ]]; then - "$LIB/voxip-kiosk-helper" set-hostname "$NEW_HOSTNAME" >/dev/null || die "Ongeldige hostname: $NEW_HOSTNAME" + "$LIB/daynivo-kiosk-helper" set-hostname "$NEW_HOSTNAME" >/dev/null || die "Ongeldige hostname: $NEW_HOSTNAME" fi if [[ $LIVE -eq 0 ]]; then @@ -321,11 +390,11 @@ fi say "Services starten" systemctl restart systemd-journald.service || true systemctl restart avahi-daemon.service || true -systemctl restart voxip-kiosk-manager.service voxip-kiosk-agent.service -systemctl start voxip-kiosk-healthcheck.timer voxip-kiosk-update.timer -systemctl reset-failed voxip-kiosk-x.service voxip-kiosk-browser.service 2>/dev/null || true -systemctl restart voxip-kiosk-x.service -systemctl restart voxip-kiosk-browser.service +systemctl restart daynivo-kiosk-manager.service daynivo-kiosk-agent.service +systemctl start daynivo-kiosk-healthcheck.timer daynivo-kiosk-update.timer +systemctl reset-failed daynivo-kiosk-x.service daynivo-kiosk-browser.service 2>/dev/null || true +systemctl restart daynivo-kiosk-x.service +systemctl restart daynivo-kiosk-browser.service HOST="$(hostname)" SCHEME=http diff --git a/pyproject.toml b/pyproject.toml index bc3630d..914e1c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "voxip-kiosk" +name = "daynivo-kiosk" dynamic = ["version"] description = "Daynivo Kiosk OS — kiosk runtime and Daynivo Kiosk Manager" requires-python = ">=3.11" diff --git a/src/daynivo_kiosk/agent.py b/src/daynivo_kiosk/agent.py index aa1a007..bcc79d9 100644 --- a/src/daynivo_kiosk/agent.py +++ b/src/daynivo_kiosk/agent.py @@ -1,4 +1,4 @@ -"""voxip-kiosk-agent — keeps the kiosk page where it should be. +"""daynivo-kiosk-agent — keeps the kiosk page where it should be. Runs as user ``kiosk`` and steers Chromium through the DevTools Protocol on 127.0.0.1: @@ -33,7 +33,7 @@ from .config import admin_url, load_config from .paths import Paths, load_paths from .validation import mask_url -log = logging.getLogger("voxip-kiosk-agent") +log = logging.getLogger("daynivo-kiosk-agent") TICK_SECONDS = 5 PROBE_MAX_AGE_LOADING = 10 diff --git a/src/daynivo_kiosk/browser.py b/src/daynivo_kiosk/browser.py index 8a8028e..ad78c2f 100644 --- a/src/daynivo_kiosk/browser.py +++ b/src/daynivo_kiosk/browser.py @@ -1,6 +1,6 @@ -"""voxip-kiosk-browser — prepares the display and runs Chromium. +"""daynivo-kiosk-browser — prepares the display and runs Chromium. -Started by ``voxip-kiosk-browser.service`` as user ``kiosk`` once the X +Started by ``daynivo-kiosk-browser.service`` as user ``kiosk`` once the X server is up. Exit status tells systemd whether to restart: 1 when ``browser_restart`` is enabled (``Restart=on-failure`` restarts it and the start limit catches crash loops), 0 when it is disabled. @@ -25,7 +25,7 @@ from .config import admin_url, load_config from .paths import Paths, load_paths from .validation import mask_url, parse_resolution -log = logging.getLogger("voxip-kiosk-browser") +log = logging.getLogger("daynivo-kiosk-browser") CDP_PORT = 9222 CHROMIUM_CANDIDATES = ("/usr/bin/chromium-browser", "/usr/bin/chromium") @@ -212,14 +212,14 @@ def clean_profile(profile_dir: Path) -> None: profile = data.setdefault("profile", {}) profile["exit_type"] = "Normal" profile["exited_cleanly"] = True - tmp = prefs.with_suffix(".voxip-tmp") + tmp = prefs.with_suffix(".daynivo-tmp") tmp.write_text(json.dumps(data), encoding="utf-8") os.replace(tmp, prefs) def profile_dirs(config: dict[str, Any]) -> tuple[Path, Path]: - runtime = Path(os.environ.get("RUNTIME_DIRECTORY", "/run/voxip-kiosk-browser")) - state = Path(os.environ.get("STATE_DIRECTORY", "/var/lib/voxip-kiosk-browser")) + runtime = Path(os.environ.get("RUNTIME_DIRECTORY", "/run/daynivo-kiosk-browser")) + state = Path(os.environ.get("STATE_DIRECTORY", "/var/lib/daynivo-kiosk-browser")) profile = state / "profile" if config.get("browser_profile") == "persistent" else runtime / "profile" if config.get("browser_profile") != "persistent" and (state / "profile").exists(): shutil.rmtree(state / "profile", ignore_errors=True) diff --git a/src/daynivo_kiosk/config.py b/src/daynivo_kiosk/config.py index 13ae4c1..070c324 100644 --- a/src/daynivo_kiosk/config.py +++ b/src/daynivo_kiosk/config.py @@ -236,7 +236,7 @@ def save_config(path: Path, updates: dict[str, Any]) -> dict[str, Any]: lock_path = path.with_name(".config.lock") with _thread_lock: # Read-only is enough for flock and works for every writer (the web - # interface as voxip, the helper as root), whoever created the file. + # interface as daynivo, the helper as root), whoever created the file. lock_fd = os.open(str(lock_path), os.O_RDONLY | os.O_CREAT, 0o640) try: fcntl.flock(lock_fd, fcntl.LOCK_EX) diff --git a/src/daynivo_kiosk/ctl.py b/src/daynivo_kiosk/ctl.py index a80d31a..b9bb261 100644 --- a/src/daynivo_kiosk/ctl.py +++ b/src/daynivo_kiosk/ctl.py @@ -48,7 +48,7 @@ def cmd_setup_code(_args) -> int: return 1 code = setupcode.read(paths.setup_code_file) if not code: - print("Nog geen setupcode; start de beheerinterface: sudo systemctl restart voxip-kiosk-manager") + print("Nog geen setupcode; start de beheerinterface: sudo systemctl restart daynivo-kiosk-manager") return 1 print(code) return 0 @@ -65,10 +65,10 @@ def cmd_reset_password(args) -> int: code = setupcode.generate() setupcode.write(paths.setup_code_file, code) try: - os.chown(paths.setup_code_file, pwd.getpwnam("voxip").pw_uid, grp.getgrnam("kiosk").gr_gid) + os.chown(paths.setup_code_file, pwd.getpwnam("daynivo").pw_uid, grp.getgrnam("kiosk").gr_gid) except KeyError: pass - subprocess.run(["systemctl", "restart", "voxip-kiosk-manager.service"], check=False) + subprocess.run(["systemctl", "restart", "daynivo-kiosk-manager.service"], check=False) print(f"Wachtwoord verwijderd. Nieuwe setupcode: {code}") print("Open de beheerinterface en stel een nieuw wachtwoord in; de code staat ook op het kioskscherm.") return 0 diff --git a/src/daynivo_kiosk/healthcheck.py b/src/daynivo_kiosk/healthcheck.py index 114683d..3cd3b86 100644 --- a/src/daynivo_kiosk/healthcheck.py +++ b/src/daynivo_kiosk/healthcheck.py @@ -1,4 +1,4 @@ -"""voxip-kiosk-healthcheck — runs every minute (timer) as root. +"""daynivo-kiosk-healthcheck — runs every minute (timer) as root. Keeps every kiosk service alive without hiding problems: each recovery is logged, and a crash loop that hit systemd's start limit is retried only @@ -21,7 +21,7 @@ from .cdp import CDP, CDPError from .config import load_config from .paths import Paths, load_paths -log = logging.getLogger("voxip-kiosk-healthcheck") +log = logging.getLogger("daynivo-kiosk-healthcheck") ALWAYS_ON = (services.AGENT_UNIT, services.MANAGER_UNIT) DISPLAY_UNITS = (services.X_UNIT, services.BROWSER_UNIT) @@ -147,7 +147,7 @@ class HealthCheck: def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(prog="voxip-kiosk-healthcheck") + parser = argparse.ArgumentParser(prog="daynivo-kiosk-healthcheck") parser.add_argument("--check-only", action="store_true", help="alleen rapporteren, niets herstellen") parser.add_argument("--json", action="store_true", help="rapport als JSON") args = parser.parse_args(argv) diff --git a/src/daynivo_kiosk/helper.py b/src/daynivo_kiosk/helper.py index 0edb31c..e51dcf5 100644 --- a/src/daynivo_kiosk/helper.py +++ b/src/daynivo_kiosk/helper.py @@ -1,11 +1,11 @@ -"""voxip-kiosk-helper — the only privileged entry point of Daynivo Kiosk OS. +"""daynivo-kiosk-helper — the only privileged entry point of Daynivo Kiosk OS. Runs as root, either through ``sudo -n`` from the web interface (user -``voxip``) or from systemd units. It accepts a fixed set of verbs, validates +``daynivo``) or from systemd units. It accepts a fixed set of verbs, validates every argument itself, never invokes a shell and prints a single JSON object on stdout. -Usage: voxip-kiosk-helper [args] (network-apply reads JSON on stdin) +Usage: daynivo-kiosk-helper [args] (network-apply reads JSON on stdin) """ from __future__ import annotations @@ -27,13 +27,13 @@ from . import netconfig, updater from . import validation as v from .paths import Paths, default_paths -HELPER_PATH = "/usr/lib/voxip-kiosk/voxip-kiosk-helper" -ROLLBACK_UNIT = "voxip-network-rollback" -UPDATE_UNIT = "voxip-kiosk-update-now" -UPDATER_PATH = "/usr/lib/voxip-kiosk/voxip-kiosk-updater" -ACTIVATE_UNIT = "voxip-network-activate" +HELPER_PATH = "/usr/lib/daynivo-kiosk/daynivo-kiosk-helper" +ROLLBACK_UNIT = "daynivo-network-rollback" +UPDATE_UNIT = "daynivo-kiosk-update-now" +UPDATER_PATH = "/usr/lib/daynivo-kiosk/daynivo-kiosk-updater" +ACTIVATE_UNIT = "daynivo-network-activate" BOOT_DIRS = (Path("/boot/firmware"), Path("/boot")) -# Files on the boot partition. The voxip-* names are from before the rename to +# Files on the boot partition. The daynivo-* names are from before the rename to # Daynivo and keep working, so existing SD cards and instructions stay valid. RESET_TRIGGERS = ("daynivo-network-reset", "voxip-network-reset") IMPORT_CONFIGS = ("voxip-config.json", "daynivo-config.json") # applied in this order: the Daynivo name wins @@ -83,24 +83,24 @@ class Helper: # -- power & browser ------------------------------------------------- def reboot(self) -> dict[str, Any]: - self.run(["systemd-run", "--on-active=3", "--unit=voxip-power-reboot", "/bin/systemctl", "reboot"]) + self.run(["systemd-run", "--on-active=3", "--unit=daynivo-power-reboot", "/bin/systemctl", "reboot"]) log(syslog.LOG_NOTICE, "Herstart aangevraagd via beheerinterface") return {"message": "De Raspberry Pi wordt over enkele seconden herstart."} def poweroff(self) -> dict[str, Any]: - self.run(["systemd-run", "--on-active=3", "--unit=voxip-power-off", "/bin/systemctl", "poweroff"]) + self.run(["systemd-run", "--on-active=3", "--unit=daynivo-power-off", "/bin/systemctl", "poweroff"]) log(syslog.LOG_NOTICE, "Uitschakelen aangevraagd via beheerinterface") return {"message": "De Raspberry Pi wordt over enkele seconden uitgeschakeld."} def restart_browser(self) -> dict[str, Any]: - self.run(["systemctl", "reset-failed", "voxip-kiosk-browser.service", "voxip-kiosk-x.service"], check=False) - self.run(["systemctl", "restart", "--no-block", "voxip-kiosk-browser.service"]) + self.run(["systemctl", "reset-failed", "daynivo-kiosk-browser.service", "daynivo-kiosk-x.service"], check=False) + self.run(["systemctl", "restart", "--no-block", "daynivo-kiosk-browser.service"]) log(syslog.LOG_NOTICE, "Chromium wordt herstart") return {"message": "Chromium wordt herstart."} def restart_manager(self) -> dict[str, Any]: # Delayed so the web interface can still answer the request that asked for it. - self.run(["systemd-run", "--on-active=2", "--unit=voxip-manager-restart", "/bin/systemctl", "restart", "voxip-kiosk-manager.service"]) + self.run(["systemd-run", "--on-active=2", "--unit=daynivo-manager-restart", "/bin/systemctl", "restart", "daynivo-kiosk-manager.service"]) log(syslog.LOG_NOTICE, "Beheerinterface wordt herstart") return {"message": "De beheerinterface wordt herstart."} @@ -326,7 +326,7 @@ class Helper: def _chown_config(self, path: Path) -> None: try: - uid = pwd.getpwnam("voxip").pw_uid + uid = pwd.getpwnam("daynivo").pw_uid gid = grp.getgrnam("kiosk").gr_gid except KeyError: return @@ -392,7 +392,7 @@ class Helper: os.chown(ssh_dir, user.pw_uid, user.pw_gid) sshd_dir = self.etc / "ssh" / "sshd_config.d" sshd_dir.mkdir(parents=True, exist_ok=True) - (sshd_dir / "voxip-kiosk.conf").write_text( + (sshd_dir / "daynivo-kiosk.conf").write_text( "# Beheerd door Daynivo Kiosk OS: alleen inloggen met SSH-sleutels.\n" "PasswordAuthentication no\nKbdInteractiveAuthentication no\nPermitRootLogin no\n", encoding="utf-8", @@ -449,9 +449,9 @@ def _parse_json(text: str) -> Any: def main(argv: list[str] | None = None, helper: Helper | None = None, environ: dict[str, str] | None = None) -> int: argv = sys.argv[1:] if argv is None else argv environ = os.environ if environ is None else environ - syslog.openlog("voxip-kiosk-helper", 0, syslog.LOG_DAEMON) + syslog.openlog("daynivo-kiosk-helper", 0, syslog.LOG_DAEMON) if not argv: - print(json.dumps({"ok": False, "error": "Gebruik: voxip-kiosk-helper [argumenten]"})) + print(json.dumps({"ok": False, "error": "Gebruik: daynivo-kiosk-helper [argumenten]"})) return 2 verb, args = argv[0], argv[1:] caller = environ.get("SUDO_USER") @@ -460,7 +460,7 @@ def main(argv: list[str] | None = None, helper: Helper | None = None, environ: d print(json.dumps({"ok": False, "error": "Opdracht niet toegestaan"})) return 1 if helper is None and os.geteuid() != 0: - print(json.dumps({"ok": False, "error": "voxip-kiosk-helper moet als root draaien"})) + print(json.dumps({"ok": False, "error": "daynivo-kiosk-helper moet als root draaien"})) return 1 helper = helper or Helper() stdin = sys.stdin.read(16385) if verb == "network-apply" else "" diff --git a/src/daynivo_kiosk/manager.py b/src/daynivo_kiosk/manager.py index e6a8c78..a338532 100644 --- a/src/daynivo_kiosk/manager.py +++ b/src/daynivo_kiosk/manager.py @@ -1,4 +1,4 @@ -"""voxip-kiosk-manager — starts the web interface under gunicorn. +"""daynivo-kiosk-manager — starts the web interface under gunicorn. Reads port and HTTPS settings from the kiosk configuration, creates a self-signed certificate when HTTPS is enabled and none exists yet, then @@ -19,8 +19,8 @@ from . import logutil from .config import load_config from .paths import Paths, load_paths -log = logging.getLogger("voxip-kiosk-manager") -PYTHON_LIB = "/usr/lib/voxip-kiosk/python" +log = logging.getLogger("daynivo-kiosk-manager") +PYTHON_LIB = "/usr/lib/daynivo-kiosk/python" def ensure_certificate(paths: Paths) -> tuple[Path, Path]: diff --git a/src/daynivo_kiosk/netconfig.py b/src/daynivo_kiosk/netconfig.py index 17e9274..a91bc0f 100644 --- a/src/daynivo_kiosk/netconfig.py +++ b/src/daynivo_kiosk/netconfig.py @@ -15,7 +15,7 @@ from typing import Any from . import validation as v INTERFACES = {"eth0": "ethernet", "wlan0": "wifi"} -PROFILE_PREFIX = "voxip-" +PROFILE_PREFIX = "daynivo-" ROLLBACK_SECONDS = 180 diff --git a/src/daynivo_kiosk/paths.py b/src/daynivo_kiosk/paths.py index 7846137..fc33b57 100644 --- a/src/daynivo_kiosk/paths.py +++ b/src/daynivo_kiosk/paths.py @@ -1,7 +1,7 @@ """Filesystem locations used by every Daynivo Kiosk component. The defaults match the installed layout. Unprivileged components may -override them through ``VOXIP_*`` environment variables (used by the test +override them through ``DAYNIVO_*`` environment variables (used by the test suite and for local development). The root helper always uses :func:`default_paths` and never reads the environment. """ @@ -15,15 +15,15 @@ from pathlib import Path @dataclass(frozen=True) class Paths: - config_dir: Path = Path("/etc/voxip-kiosk") - state_dir: Path = Path("/var/lib/voxip-kiosk") - network_state_dir: Path = Path("/var/lib/voxip-kiosk-network") - agent_run_dir: Path = Path("/run/voxip-kiosk-agent") - browser_run_dir: Path = Path("/run/voxip-kiosk-browser") - health_run_dir: Path = Path("/run/voxip-kiosk-health") - share_dir: Path = Path("/usr/share/voxip-kiosk") - log_dir: Path = Path("/var/log/voxip-kiosk") - helper: Path = Path("/usr/lib/voxip-kiosk/voxip-kiosk-helper") + config_dir: Path = Path("/etc/daynivo-kiosk") + state_dir: Path = Path("/var/lib/daynivo-kiosk") + network_state_dir: Path = Path("/var/lib/daynivo-kiosk-network") + agent_run_dir: Path = Path("/run/daynivo-kiosk-agent") + browser_run_dir: Path = Path("/run/daynivo-kiosk-browser") + health_run_dir: Path = Path("/run/daynivo-kiosk-health") + share_dir: Path = Path("/usr/share/daynivo-kiosk") + log_dir: Path = Path("/var/log/daynivo-kiosk") + helper: Path = Path("/usr/lib/daynivo-kiosk/daynivo-kiosk-helper") nm_connections_dir: Path = Path("/etc/NetworkManager/system-connections") @property @@ -90,15 +90,15 @@ def default_paths() -> Paths: _ENV = { - "config_dir": "VOXIP_CONFIG_DIR", - "state_dir": "VOXIP_STATE_DIR", - "network_state_dir": "VOXIP_NETWORK_STATE_DIR", - "agent_run_dir": "VOXIP_AGENT_RUN_DIR", - "browser_run_dir": "VOXIP_BROWSER_RUN_DIR", - "health_run_dir": "VOXIP_HEALTH_RUN_DIR", - "share_dir": "VOXIP_SHARE_DIR", - "log_dir": "VOXIP_LOG_DIR", - "helper": "VOXIP_HELPER", + "config_dir": "DAYNIVO_CONFIG_DIR", + "state_dir": "DAYNIVO_STATE_DIR", + "network_state_dir": "DAYNIVO_NETWORK_STATE_DIR", + "agent_run_dir": "DAYNIVO_AGENT_RUN_DIR", + "browser_run_dir": "DAYNIVO_BROWSER_RUN_DIR", + "health_run_dir": "DAYNIVO_HEALTH_RUN_DIR", + "share_dir": "DAYNIVO_SHARE_DIR", + "log_dir": "DAYNIVO_LOG_DIR", + "helper": "DAYNIVO_HELPER", } diff --git a/src/daynivo_kiosk/services.py b/src/daynivo_kiosk/services.py index fc872cc..ff653d7 100644 --- a/src/daynivo_kiosk/services.py +++ b/src/daynivo_kiosk/services.py @@ -5,11 +5,11 @@ from __future__ import annotations import subprocess from typing import Any -BROWSER_UNIT = "voxip-kiosk-browser.service" -X_UNIT = "voxip-kiosk-x.service" -AGENT_UNIT = "voxip-kiosk-agent.service" -MANAGER_UNIT = "voxip-kiosk-manager.service" -HEALTH_UNIT = "voxip-kiosk-healthcheck.service" +BROWSER_UNIT = "daynivo-kiosk-browser.service" +X_UNIT = "daynivo-kiosk-x.service" +AGENT_UNIT = "daynivo-kiosk-agent.service" +MANAGER_UNIT = "daynivo-kiosk-manager.service" +HEALTH_UNIT = "daynivo-kiosk-healthcheck.service" # Units whose logs the web interface may show (label → journalctl -u args). LOG_SOURCES: dict[str, tuple[str, list[str]]] = { @@ -18,7 +18,7 @@ LOG_SOURCES: dict[str, tuple[str, list[str]]] = { "agent": ("Kiosk-agent", [AGENT_UNIT]), "health": ("Healthcheck", [HEALTH_UNIT]), "manager": ("Beheerinterface", [MANAGER_UNIT]), - "network": ("Netwerk", ["NetworkManager.service", "voxip-network-guard.service", "voxip-network-rollback.service", "voxip-network-activate.service"]), + "network": ("Netwerk", ["NetworkManager.service", "daynivo-network-guard.service", "daynivo-network-rollback.service", "daynivo-network-activate.service"]), "system": ("Volledig systeem", []), } LOG_LINES = (50, 100, 200, 500) diff --git a/src/daynivo_kiosk/updater.py b/src/daynivo_kiosk/updater.py index 1576b56..917b433 100644 --- a/src/daynivo_kiosk/updater.py +++ b/src/daynivo_kiosk/updater.py @@ -1,4 +1,4 @@ -"""voxip-kiosk-updater — installs new Daynivo Kiosk OS releases (runs as root). +"""daynivo-kiosk-updater — installs new Daynivo Kiosk OS releases (runs as root). A release is a tag ``vX.Y.Z`` on the Gitea repository with two assets: ``daynivo-kiosk-os-X.Y.Z.tar.gz`` and its ``.sha256``. The updater @@ -11,9 +11,9 @@ A release is a tag ``vX.Y.Z`` on the Gitea repository with two assets: It never installs an older or equal version. Usage:: - voxip-kiosk-updater --check # only check - voxip-kiosk-updater --auto # check; install when auto_update is on (daily timer) - voxip-kiosk-updater --install # check and install when newer (button in the web interface) + daynivo-kiosk-updater --check # only check + daynivo-kiosk-updater --auto # check; install when auto_update is on (daily timer) + daynivo-kiosk-updater --install # check and install when newer (button in the web interface) """ from __future__ import annotations @@ -39,12 +39,12 @@ from . import logutil from .config import atomic_write_json, load_config from .paths import Paths, default_paths, read_version -log = logging.getLogger("voxip-kiosk-updater") +log = logging.getLogger("daynivo-kiosk-updater") RELEASE_API = "https://git.rothman.nl/api/v1/repos/rothman/daynivo-kiosk-os/releases/latest" ASSET_PREFIX = "daynivo-kiosk-os-" RELEASE_DIR = Path("/opt/daynivo-kiosk-os") -CACHE_DIR = Path("/var/cache/voxip-kiosk") +CACHE_DIR = Path("/var/cache/daynivo-kiosk") KEEP_RELEASES = 2 MAX_DOWNLOAD = 64 * 1024 * 1024 USER_AGENT = "Daynivo-Kiosk-OS/updater" @@ -219,7 +219,7 @@ class Updater: def main(argv: list[str] | None = None, updater: Updater | None = None) -> int: - parser = argparse.ArgumentParser(prog="voxip-kiosk-updater", description="Daynivo Kiosk OS bijwerken.") + parser = argparse.ArgumentParser(prog="daynivo-kiosk-updater", description="Daynivo Kiosk OS bijwerken.") mode = parser.add_mutually_exclusive_group(required=True) mode.add_argument("--check", action="store_true", help="alleen controleren") mode.add_argument("--auto", action="store_true", help="controleren en bijwerken als automatisch bijwerken aan staat") diff --git a/src/daynivo_kiosk/web/__init__.py b/src/daynivo_kiosk/web/__init__.py index 88f8e7d..3016815 100644 --- a/src/daynivo_kiosk/web/__init__.py +++ b/src/daynivo_kiosk/web/__init__.py @@ -48,7 +48,7 @@ def create_app(paths: Paths | None = None, *, helper: Any = None, cdp: Any = Non app = Flask(__name__) app.secret_key = _secret_key(paths) app.config.update( - SESSION_COOKIE_NAME="voxip_session", + SESSION_COOKIE_NAME="daynivo_session", SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE="Strict", SESSION_COOKIE_SECURE=config["admin_https"], @@ -58,7 +58,7 @@ def create_app(paths: Paths | None = None, *, helper: Any = None, cdp: Any = Non ) credentials = CredentialStore(paths.admin_file, paths.setup_code_file) credentials.ensure_setup_code() - app.extensions["voxip"] = Services( + app.extensions["daynivo"] = Services( paths=paths, credentials=credentials, throttle=LoginThrottle(), diff --git a/src/daynivo_kiosk/web/auth.py b/src/daynivo_kiosk/web/auth.py index b91b477..08c792d 100644 --- a/src/daynivo_kiosk/web/auth.py +++ b/src/daynivo_kiosk/web/auth.py @@ -21,7 +21,7 @@ HASHER = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=2, hash_len= MIN_LENGTH = 10 MAX_LENGTH = 128 -WEAK = {"admin", "administrator", "password", "wachtwoord", "raspberry", "voxip", "kiosk", "welkom", "welcome", "qwerty", "123456"} +WEAK = {"admin", "administrator", "password", "wachtwoord", "raspberry", "daynivo", "kiosk", "welkom", "welcome", "qwerty", "123456"} def password_problem(password: str, confirm: str | None = None) -> str | None: diff --git a/src/daynivo_kiosk/web/views.py b/src/daynivo_kiosk/web/views.py index 4a9188c..ef63c41 100644 --- a/src/daynivo_kiosk/web/views.py +++ b/src/daynivo_kiosk/web/views.py @@ -22,14 +22,14 @@ from . import security from .auth import password_problem bp = Blueprint("ui", __name__) -audit_log = logging.getLogger("voxip-kiosk-audit") +audit_log = logging.getLogger("daynivo-kiosk-audit") IDLE_TIMEOUT = 3600 PUBLIC_ENDPOINTS = {"ui.login", "ui.setup", "static"} def svc(): - return current_app.extensions["voxip"] + return current_app.extensions["daynivo"] def cfg() -> dict[str, Any]: diff --git a/systemd/voxip-boot-import.service b/systemd/daynivo-boot-import.service similarity index 75% rename from systemd/voxip-boot-import.service rename to systemd/daynivo-boot-import.service index cdea75b..c95c7ec 100644 --- a/systemd/voxip-boot-import.service +++ b/systemd/daynivo-boot-import.service @@ -1,8 +1,8 @@ [Unit] Description=Daynivo configuratie en SSH-sleutels importeren vanaf de bootpartitie -Documentation=file:///usr/share/doc/voxip-kiosk/README.md +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md After=local-fs.target -Before=voxip-kiosk-manager.service voxip-kiosk-browser.service ssh.service +Before=daynivo-kiosk-manager.service daynivo-kiosk-browser.service ssh.service ConditionPathExistsGlob=|/boot/firmware/daynivo-config.json ConditionPathExistsGlob=|/boot/firmware/daynivo-authorized_keys ConditionPathExistsGlob=|/boot/daynivo-config.json @@ -15,7 +15,7 @@ ConditionPathExistsGlob=|/boot/voxip-authorized_keys [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-helper boot-import +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-helper boot-import [Install] WantedBy=multi-user.target diff --git a/systemd/voxip-kiosk-agent.service b/systemd/daynivo-kiosk-agent.service similarity index 65% rename from systemd/voxip-kiosk-agent.service rename to systemd/daynivo-kiosk-agent.service index 0224583..b1e9784 100644 --- a/systemd/voxip-kiosk-agent.service +++ b/systemd/daynivo-kiosk-agent.service @@ -1,18 +1,18 @@ [Unit] Description=Daynivo Kiosk agent (navigatie, offlinepagina, verversen) -Documentation=file:///usr/share/doc/voxip-kiosk/README.md -After=voxip-kiosk-browser.service +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md +After=daynivo-kiosk-browser.service [Service] Type=simple User=kiosk Group=kiosk -RuntimeDirectory=voxip-kiosk-agent +RuntimeDirectory=daynivo-kiosk-agent RuntimeDirectoryMode=0755 -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-agent +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-agent Restart=always RestartSec=5 -SyslogIdentifier=voxip-kiosk-agent +SyslogIdentifier=daynivo-kiosk-agent NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes diff --git a/systemd/daynivo-kiosk-browser.service b/systemd/daynivo-kiosk-browser.service new file mode 100644 index 0000000..2470adf --- /dev/null +++ b/systemd/daynivo-kiosk-browser.service @@ -0,0 +1,36 @@ +[Unit] +Description=Daynivo Kiosk Chromium +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md +Requires=daynivo-kiosk-x.service +After=daynivo-kiosk-x.service daynivo-boot-import.service +# Restarting or stopping X restarts/stops the browser as well. +PartOf=daynivo-kiosk-x.service +# A crash loop stops after 6 starts in 10 minutes; the healthcheck logs it +# and retries after a cool-down (see daynivo-kiosk-healthcheck). +StartLimitIntervalSec=600 +StartLimitBurst=6 + +[Service] +Type=simple +User=kiosk +Group=kiosk +Environment=DISPLAY=:0 +Environment=XAUTHORITY=/run/daynivo-kiosk-x/Xauthority +Environment=HOME=/home/kiosk +RuntimeDirectory=daynivo-kiosk-browser +RuntimeDirectoryMode=0755 +StateDirectory=daynivo-kiosk-browser +StateDirectoryMode=0700 +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-browser +# daynivo-kiosk-browser exits 1 after a crash when browser_restart is on, 0 when it is off. +Restart=on-failure +RestartSec=5 +TimeoutStopSec=15 +KillMode=control-group +OOMScoreAdjust=-100 +LogRateLimitIntervalSec=30s +LogRateLimitBurst=300 +SyslogIdentifier=daynivo-kiosk-browser + +[Install] +WantedBy=multi-user.target diff --git a/systemd/daynivo-kiosk-healthcheck.service b/systemd/daynivo-kiosk-healthcheck.service new file mode 100644 index 0000000..4be5f25 --- /dev/null +++ b/systemd/daynivo-kiosk-healthcheck.service @@ -0,0 +1,11 @@ +[Unit] +Description=Daynivo Kiosk healthcheck +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md + +[Service] +Type=oneshot +RuntimeDirectory=daynivo-kiosk-health +RuntimeDirectoryPreserve=yes +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-healthcheck +SyslogIdentifier=daynivo-kiosk-healthcheck +TimeoutStartSec=60 diff --git a/systemd/voxip-kiosk-healthcheck.timer b/systemd/daynivo-kiosk-healthcheck.timer similarity index 100% rename from systemd/voxip-kiosk-healthcheck.timer rename to systemd/daynivo-kiosk-healthcheck.timer diff --git a/systemd/voxip-kiosk-manager.service b/systemd/daynivo-kiosk-manager.service similarity index 63% rename from systemd/voxip-kiosk-manager.service rename to systemd/daynivo-kiosk-manager.service index 26f8cdc..4a3bdc0 100644 --- a/systemd/voxip-kiosk-manager.service +++ b/systemd/daynivo-kiosk-manager.service @@ -1,27 +1,27 @@ [Unit] Description=Daynivo Kiosk Manager (webbeheer) -Documentation=file:///usr/share/doc/voxip-kiosk/README.md -After=network.target voxip-boot-import.service +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md +After=network.target daynivo-boot-import.service StartLimitIntervalSec=300 StartLimitBurst=10 [Service] Type=simple -User=voxip -Group=voxip +User=daynivo +Group=daynivo # systemd-journal: read logs; video: vcgencmd (voltage/throttling) SupplementaryGroups=systemd-journal video -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-manager +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-manager Restart=always RestartSec=3 UMask=0027 -LogsDirectory=voxip-kiosk +LogsDirectory=daynivo-kiosk LogsDirectoryMode=0750 -SyslogIdentifier=voxip-kiosk-manager +SyslogIdentifier=daynivo-kiosk-manager # No NoNewPrivileges/ProtectSystem/ProtectHome: the helper started through -# "sudo -n voxip-kiosk-helper" inherits this unit's mount namespace and must +# "sudo -n daynivo-kiosk-helper" inherits this unit's mount namespace and must # be able to write /etc (hostname, NetworkManager profiles). The web process -# itself runs unprivileged as user voxip and can only write its own dirs. +# itself runs unprivileged as user daynivo and can only write its own dirs. # Also no ProtectKernelTunables/ProtectKernelModules/LockPersonality, # RestrictSUIDSGID, SystemCall*, ...: for a non-root unit those imply # NoNewPrivileges, and sudo then refuses to run (tests/test_units.py). diff --git a/systemd/voxip-kiosk-update.service b/systemd/daynivo-kiosk-update.service similarity index 54% rename from systemd/voxip-kiosk-update.service rename to systemd/daynivo-kiosk-update.service index 8d66f39..b7abf3a 100644 --- a/systemd/voxip-kiosk-update.service +++ b/systemd/daynivo-kiosk-update.service @@ -1,11 +1,11 @@ [Unit] Description=Daynivo Kiosk OS: controleren op updates (en installeren als dat aan staat) -Documentation=file:///usr/share/doc/voxip-kiosk/README.md +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md Wants=network-online.target After=network-online.target [Service] Type=oneshot -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-updater --auto +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-updater --auto TimeoutStartSec=1h -SyslogIdentifier=voxip-kiosk-updater +SyslogIdentifier=daynivo-kiosk-updater diff --git a/systemd/voxip-kiosk-update.timer b/systemd/daynivo-kiosk-update.timer similarity index 100% rename from systemd/voxip-kiosk-update.timer rename to systemd/daynivo-kiosk-update.timer diff --git a/systemd/voxip-kiosk-x.service b/systemd/daynivo-kiosk-x.service similarity index 80% rename from systemd/voxip-kiosk-x.service rename to systemd/daynivo-kiosk-x.service index 497ebf7..dff20ab 100644 --- a/systemd/voxip-kiosk-x.service +++ b/systemd/daynivo-kiosk-x.service @@ -1,6 +1,6 @@ [Unit] Description=Daynivo Kiosk X-server (vt7) -Documentation=file:///usr/share/doc/voxip-kiosk/README.md +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md After=systemd-user-sessions.service systemd-logind.service Conflicts=getty@tty7.service StartLimitIntervalSec=600 @@ -20,10 +20,10 @@ StandardOutput=journal StandardError=journal UtmpIdentifier=tty7 UtmpMode=user -RuntimeDirectory=voxip-kiosk-x +RuntimeDirectory=daynivo-kiosk-x RuntimeDirectoryMode=0700 ExecStartPre=+/usr/bin/chvt 7 -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-x +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-x Restart=always RestartSec=3 diff --git a/systemd/voxip-network-guard.service b/systemd/daynivo-network-guard.service similarity index 70% rename from systemd/voxip-network-guard.service rename to systemd/daynivo-network-guard.service index 6de085a..545db2d 100644 --- a/systemd/voxip-network-guard.service +++ b/systemd/daynivo-network-guard.service @@ -1,6 +1,6 @@ [Unit] Description=Daynivo netwerkherstel bij opstarten (rollback en noodreset) -Documentation=file:///usr/share/doc/voxip-kiosk/README.md +Documentation=file:///usr/share/doc/daynivo-kiosk/README.md DefaultDependencies=no After=local-fs.target Before=NetworkManager.service network-pre.target shutdown.target @@ -10,7 +10,7 @@ Conflicts=shutdown.target [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-helper network-boot-guard +ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-helper network-boot-guard [Install] WantedBy=multi-user.target diff --git a/systemd/voxip-kiosk-browser.service b/systemd/voxip-kiosk-browser.service deleted file mode 100644 index aaa6ad1..0000000 --- a/systemd/voxip-kiosk-browser.service +++ /dev/null @@ -1,36 +0,0 @@ -[Unit] -Description=Daynivo Kiosk Chromium -Documentation=file:///usr/share/doc/voxip-kiosk/README.md -Requires=voxip-kiosk-x.service -After=voxip-kiosk-x.service voxip-boot-import.service -# Restarting or stopping X restarts/stops the browser as well. -PartOf=voxip-kiosk-x.service -# A crash loop stops after 6 starts in 10 minutes; the healthcheck logs it -# and retries after a cool-down (see voxip-kiosk-healthcheck). -StartLimitIntervalSec=600 -StartLimitBurst=6 - -[Service] -Type=simple -User=kiosk -Group=kiosk -Environment=DISPLAY=:0 -Environment=XAUTHORITY=/run/voxip-kiosk-x/Xauthority -Environment=HOME=/home/kiosk -RuntimeDirectory=voxip-kiosk-browser -RuntimeDirectoryMode=0755 -StateDirectory=voxip-kiosk-browser -StateDirectoryMode=0700 -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-browser -# voxip-kiosk-browser exits 1 after a crash when browser_restart is on, 0 when it is off. -Restart=on-failure -RestartSec=5 -TimeoutStopSec=15 -KillMode=control-group -OOMScoreAdjust=-100 -LogRateLimitIntervalSec=30s -LogRateLimitBurst=300 -SyslogIdentifier=voxip-kiosk-browser - -[Install] -WantedBy=multi-user.target diff --git a/systemd/voxip-kiosk-healthcheck.service b/systemd/voxip-kiosk-healthcheck.service deleted file mode 100644 index fe263bd..0000000 --- a/systemd/voxip-kiosk-healthcheck.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Daynivo Kiosk healthcheck -Documentation=file:///usr/share/doc/voxip-kiosk/README.md - -[Service] -Type=oneshot -RuntimeDirectory=voxip-kiosk-health -RuntimeDirectoryPreserve=yes -ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-healthcheck -SyslogIdentifier=voxip-kiosk-healthcheck -TimeoutStartSec=60 diff --git a/tests/conftest.py b/tests/conftest.py index 5b23459..528eb36 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -96,7 +96,7 @@ def quiet_system(monkeypatch): "available": True, "wifi_country": "NL", "devices": { iface: {"interface": iface, "kind": kind, "present": True, "state": "connected", "state_label": "Verbonden", - "connected": True, "connection": f"voxip-{iface}", "addresses": ["192.168.10.20/24"], "gateway": "192.168.10.1", + "connected": True, "connection": f"daynivo-{iface}", "addresses": ["192.168.10.20/24"], "gateway": "192.168.10.1", "dns": ["192.168.10.1"], "hwaddr": "B8:27:EB:00:00:01", "profile": {"exists": True, "method": "dhcp", "address": "", "gateway": "", "dns": "", "ssid": "Kantoor", "hidden": False}} for iface, kind in (("eth0", "ethernet"), ("wlan0", "wifi")) @@ -130,7 +130,7 @@ PASSWORD = "Correct-Paard-Batterij-42" @pytest.fixture def logged_in(app, client, paths): """A client with a configured admin password and an active session.""" - app.extensions["voxip"].credentials.set_password(PASSWORD) + app.extensions["daynivo"].credentials.set_password(PASSWORD) page = client.get("/login") token = csrf_from(page) resp = client.post("/login", data={"password": PASSWORD, "csrf_token": token}) diff --git a/tests/test_helper.py b/tests/test_helper.py index 2b67759..582c982 100644 --- a/tests/test_helper.py +++ b/tests/test_helper.py @@ -35,7 +35,7 @@ def helper(paths, tmp_path, boot): etc.mkdir() (etc / "hosts").write_text("127.0.0.1\tlocalhost\n127.0.1.1\tkiosk\n") run = Recorder({"nmcli -t -f": "aaaa-1111\n"}) - return h.Helper(paths=paths, run=run, etc=etc, boot_dirs=(boot,), helper_path="/usr/lib/voxip-kiosk/voxip-kiosk-helper") + return h.Helper(paths=paths, run=run, etc=etc, boot_dirs=(boot,), helper_path="/usr/lib/daynivo-kiosk/daynivo-kiosk-helper") def run_main(helper, argv, env=None, capsys=None): @@ -45,17 +45,17 @@ def run_main(helper, argv, env=None, capsys=None): def test_internal_verbs_refused_via_sudo(helper, capsys): - code, out = run_main(helper, ["network-restore"], {"SUDO_USER": "voxip"}, capsys) + code, out = run_main(helper, ["network-restore"], {"SUDO_USER": "daynivo"}, capsys) assert code == 1 and out["ok"] is False - code, out = run_main(helper, ["boot-import"], {"SUDO_USER": "voxip"}, capsys) + code, out = run_main(helper, ["boot-import"], {"SUDO_USER": "daynivo"}, capsys) assert code == 1 assert helper.run.commands == [] def test_public_verb_via_sudo(helper, capsys): - code, out = run_main(helper, ["restart-browser"], {"SUDO_USER": "voxip"}, capsys) + code, out = run_main(helper, ["restart-browser"], {"SUDO_USER": "daynivo"}, capsys) assert code == 0 and out["ok"] is True - assert helper.run.ran("systemctl", "restart", "--no-block", "voxip-kiosk-browser.service") + assert helper.run.ran("systemctl", "restart", "--no-block", "daynivo-kiosk-browser.service") def test_unknown_verb_and_bad_arity(helper, capsys): @@ -99,7 +99,7 @@ ETH_STATIC = {"interface": "eth0", "method": "static", "address": "192.168.5.10/ def test_network_apply_snapshot_pending_and_timers(helper, paths): (paths.nm_connections_dir / "Wired connection 1.nmconnection").write_text("[connection]\nid=Wired connection 1\n") result = helper.network_apply(ETH_STATIC) - keyfile = paths.nm_connections_dir / "voxip-eth0.nmconnection" + keyfile = paths.nm_connections_dir / "daynivo-eth0.nmconnection" assert keyfile.exists() and oct(keyfile.stat().st_mode & 0o777) == "0o600" assert "address1=192.168.5.10/24,192.168.5.1" in keyfile.read_text() assert (paths.network_backup_dir / "Wired connection 1.nmconnection").exists() @@ -108,8 +108,8 @@ def test_network_apply_snapshot_pending_and_timers(helper, paths): assert pending["deadline"] - pending["created"] == 180 assert result["pending"]["interface"] == "eth0" runs = [c for c in helper.run.commands if c[0] == "systemd-run"] - assert runs[0][1:3] == ["--unit=voxip-network-rollback", "--on-active=180"] and runs[0][-1] == "network-restore" - assert runs[1][1:3] == ["--unit=voxip-network-activate", "--on-active=2"] and runs[1][-2:] == ["network-activate", "eth0"] + assert runs[0][1:3] == ["--unit=daynivo-network-rollback", "--on-active=180"] and runs[0][-1] == "network-restore" + assert runs[1][1:3] == ["--unit=daynivo-network-activate", "--on-active=2"] and runs[1][-2:] == ["network-activate", "eth0"] def test_second_apply_refused_while_pending(helper): @@ -123,8 +123,8 @@ def test_confirm_clears_pending(helper, paths): helper.network_confirm() assert not paths.network_pending_file.exists() assert not paths.network_backup_dir.exists() - assert (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists() - assert helper.run.ran("systemctl", "stop", "voxip-network-rollback.timer") + assert (paths.nm_connections_dir / "daynivo-eth0.nmconnection").exists() + assert helper.run.ran("systemctl", "stop", "daynivo-network-rollback.timer") def test_restore_puts_old_profiles_back(helper, paths): @@ -134,7 +134,7 @@ def test_restore_puts_old_profiles_back(helper, paths): old.unlink() helper.network_restore() assert old.exists() - assert not (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists() + assert not (paths.nm_connections_dir / "daynivo-eth0.nmconnection").exists() assert not paths.network_pending_file.exists() assert helper.run.ran("nmcli", "--wait", "30", "connection", "up", "uuid", "aaaa-1111") @@ -152,7 +152,7 @@ def test_wifi_keeps_existing_password_for_same_ssid(helper, paths): helper.network_confirm() helper.network_apply({"interface": "wlan0", "method": "static", "address": "10.0.0.9/24", "gateway": "10.0.0.1", "dns": "10.0.0.1", "wifi": {"ssid": "Kantoor", "psk": ""}}) - assert "psk=geheim-wachtwoord" in (paths.nm_connections_dir / "voxip-wlan0.nmconnection").read_text() + assert "psk=geheim-wachtwoord" in (paths.nm_connections_dir / "daynivo-wlan0.nmconnection").read_text() helper.network_confirm() with pytest.raises(h.HelperError, match="wachtwoord"): helper.network_apply({"interface": "wlan0", "method": "dhcp", "wifi": {"ssid": "Ander", "psk": ""}}) @@ -165,22 +165,22 @@ def test_boot_guard_rolls_back_and_honours_reset(helper, paths, boot): helper.run.commands.clear() result = helper.network_boot_guard() assert result == {"rolled_back": True} - assert not (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists() + assert not (paths.nm_connections_dir / "daynivo-eth0.nmconnection").exists() assert not any(c[0] == "nmcli" for c in helper.run.commands), "NetworkManager is not running yet at boot" - (paths.nm_connections_dir / "voxip-wlan0.nmconnection").write_text("x") + (paths.nm_connections_dir / "daynivo-wlan0.nmconnection").write_text("x") (boot / "daynivo-network-reset").write_text("") assert helper.network_boot_guard() == {"reset": True} - assert not (paths.nm_connections_dir / "voxip-wlan0.nmconnection").exists() + assert not (paths.nm_connections_dir / "daynivo-wlan0.nmconnection").exists() assert not (boot / "daynivo-network-reset").exists() assert old.exists() def test_boot_guard_still_honours_the_old_reset_name(helper, paths, boot): - (paths.nm_connections_dir / "voxip-eth0.nmconnection").write_text("x") + (paths.nm_connections_dir / "daynivo-eth0.nmconnection").write_text("x") (boot / "voxip-network-reset").write_text("") assert helper.network_boot_guard() == {"reset": True} - assert not (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists() + assert not (paths.nm_connections_dir / "daynivo-eth0.nmconnection").exists() assert not (boot / "voxip-network-reset").exists() @@ -230,7 +230,7 @@ def test_update_verbs_are_public_and_install_runs_in_its_own_unit(helper): def test_update_install_reports_a_running_update(helper): def busy(args, timeout=30, check=True, input=None): - return subprocess.CompletedProcess(args, 1, stdout="", stderr="Unit voxip-kiosk-update-now.service already exists.") + return subprocess.CompletedProcess(args, 1, stdout="", stderr="Unit daynivo-kiosk-update-now.service already exists.") helper.run = busy with pytest.raises(h.HelperError, match="al een update"): diff --git a/tests/test_netconfig.py b/tests/test_netconfig.py index 53e8466..d021fb4 100644 --- a/tests/test_netconfig.py +++ b/tests/test_netconfig.py @@ -27,7 +27,7 @@ def test_keyfile_static_ethernet(): req = n.validate_request({"interface": "eth0", "method": "static", "address": "10.1.2.3/16", "gateway": "10.1.0.1", "dns": ["10.1.0.1"]}) text = n.build_keyfile(req, uuid="11111111-2222-3333-4444-555555555555") kf = n.read_keyfile(text) - assert kf.get("connection", "id") == "voxip-eth0" + assert kf.get("connection", "id") == "daynivo-eth0" assert kf.get("connection", "type") == "ethernet" assert kf.get("connection", "autoconnect-priority") == "100" assert kf.get("ipv4", "method") == "manual" diff --git a/tests/test_units.py b/tests/test_units.py index 4168935..8e07e7c 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -22,8 +22,8 @@ def settings(unit): def test_manager_can_use_sudo_for_the_helper(): - unit = settings("voxip-kiosk-manager.service") - assert unit["User"] == "voxip" + unit = settings("daynivo-kiosk-manager.service") + assert unit["User"] == "daynivo" for key in IMPLY_NO_NEW_PRIVILEGES: assert unit.get(key, "no") in ("no", "false", ""), key for key in ("ProtectSystem", "ProtectHome", "PrivateTmp"): diff --git a/tests/test_web.py b/tests/test_web.py index 54c36c7..601e907 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -52,7 +52,7 @@ def test_setup_without_csrf_is_rejected(client, paths): # --- login & session ------------------------------------------------------------- def test_login_logout(app, client): - app.extensions["voxip"].credentials.set_password(PASSWORD) + app.extensions["daynivo"].credentials.set_password(PASSWORD) assert client.get("/").status_code == 302 tok = csrf_from(client.get("/login")) assert "Onjuist" in client.post("/login", data={"csrf_token": tok, "password": "fout-wachtwoord"}).get_data(as_text=True) @@ -63,7 +63,7 @@ def test_login_logout(app, client): def test_session_cookie_flags(app, client): - app.extensions["voxip"].credentials.set_password(PASSWORD) + app.extensions["daynivo"].credentials.set_password(PASSWORD) tok = csrf_from(client.get("/login")) resp = client.post("/login", data={"csrf_token": tok, "password": PASSWORD}) cookie = resp.headers["Set-Cookie"] @@ -71,7 +71,7 @@ def test_session_cookie_flags(app, client): def test_login_throttling(app, client): - app.extensions["voxip"].credentials.set_password(PASSWORD) + app.extensions["daynivo"].credentials.set_password(PASSWORD) tok = csrf_from(client.get("/login")) for _ in range(5): client.post("/login", data={"csrf_token": tok, "password": "verkeerd-wachtwoord"}) @@ -156,7 +156,7 @@ def test_security_headers(client): def test_api_requires_login(app, client): - app.extensions["voxip"].credentials.set_password(PASSWORD) + app.extensions["daynivo"].credentials.set_password(PASSWORD) resp = client.get("/api/status") assert resp.status_code == 401 and resp.json["error"] diff --git a/uninstall.sh b/uninstall.sh index 7eb125f..2ed3611 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -15,16 +15,16 @@ PURGE=0 [[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { sed -n '3,10p' "$0" | sed 's/^# \{0,1\}//'; exit 0; } [[ $EUID -eq 0 ]] || { echo "Voer dit script uit met sudo." >&2; exit 1; } -UNITS=(voxip-kiosk-healthcheck.timer voxip-kiosk-healthcheck.service voxip-kiosk-agent.service - voxip-kiosk-browser.service voxip-kiosk-x.service voxip-kiosk-manager.service - voxip-network-guard.service voxip-boot-import.service voxip-kiosk-update.timer voxip-kiosk-update.service) +UNITS=(daynivo-kiosk-healthcheck.timer daynivo-kiosk-healthcheck.service daynivo-kiosk-agent.service + daynivo-kiosk-browser.service daynivo-kiosk-x.service daynivo-kiosk-manager.service + daynivo-network-guard.service daynivo-boot-import.service daynivo-kiosk-update.timer daynivo-kiosk-update.service) -PREVIOUS_TARGET="$(cat /var/lib/voxip-kiosk/previous-default-target 2>/dev/null || true)" -PREVIOUS_SPLASH="$(cat /var/lib/voxip-kiosk/previous-plymouth-theme 2>/dev/null || true)" -mapfile -t DISABLED_DMS < <(cat /var/lib/voxip-kiosk/disabled-display-managers 2>/dev/null) +PREVIOUS_TARGET="$(cat /var/lib/daynivo-kiosk/previous-default-target 2>/dev/null || true)" +PREVIOUS_SPLASH="$(cat /var/lib/daynivo-kiosk/previous-plymouth-theme 2>/dev/null || true)" +mapfile -t DISABLED_DMS < <(cat /var/lib/daynivo-kiosk/disabled-display-managers 2>/dev/null) echo "==> Services stoppen en verwijderen" -systemctl stop voxip-network-rollback.timer 2>/dev/null || true +systemctl stop daynivo-network-rollback.timer 2>/dev/null || true for unit in "${UNITS[@]}"; do systemctl disable --now "$unit" 2>/dev/null || true rm -f "/etc/systemd/system/$unit" @@ -32,42 +32,47 @@ done systemctl daemon-reload echo "==> Bestanden verwijderen" -rm -rf /usr/lib/voxip-kiosk /usr/share/voxip-kiosk /usr/share/doc/voxip-kiosk +rm -rf /usr/lib/daynivo-kiosk /usr/share/daynivo-kiosk /usr/share/doc/daynivo-kiosk rm -f /usr/local/sbin/daynivo-kiosk-ctl /usr/local/sbin/voxip-kiosk-ctl -rm -f /etc/sudoers.d/voxip-kiosk -rm -f /etc/systemd/journald.conf.d/voxip-kiosk.conf /etc/systemd/system.conf.d/voxip-watchdog.conf -rm -f /etc/logrotate.d/voxip-kiosk /etc/avahi/services/voxip-kiosk.service -rm -f /etc/chromium/policies/managed/voxip-kiosk.json /etc/chromium-browser/policies/managed/voxip-kiosk.json +# Symlinks left by the move from the VoxIP names +for link in /etc/voxip-kiosk /var/lib/voxip-kiosk /var/lib/voxip-kiosk-network /var/lib/voxip-kiosk-browser \ + /var/log/voxip-kiosk /var/cache/voxip-kiosk; do + if [[ -L $link ]]; then rm -f "$link"; fi +done +rm -f /etc/sudoers.d/daynivo-kiosk +rm -f /etc/systemd/journald.conf.d/daynivo-kiosk.conf /etc/systemd/system.conf.d/daynivo-watchdog.conf +rm -f /etc/logrotate.d/daynivo-kiosk /etc/avahi/services/daynivo-kiosk.service +rm -f /etc/chromium/policies/managed/daynivo-kiosk.json /etc/chromium-browser/policies/managed/daynivo-kiosk.json rm -f /etc/systemd/zram-generator.conf -rm -f /etc/ssh/sshd_config.d/voxip-kiosk.conf -if [[ -f /etc/X11/Xwrapper.config.voxip-orig ]]; then - mv /etc/X11/Xwrapper.config.voxip-orig /etc/X11/Xwrapper.config +rm -f /etc/ssh/sshd_config.d/daynivo-kiosk.conf +if [[ -f /etc/X11/Xwrapper.config.daynivo-orig ]]; then + mv /etc/X11/Xwrapper.config.daynivo-orig /etc/X11/Xwrapper.config else rm -f /etc/X11/Xwrapper.config fi -if [[ -d /usr/share/plymouth/themes/voxip-kiosk ]]; then +if [[ -d /usr/share/plymouth/themes/daynivo-kiosk ]]; then echo "==> Opstartscherm terugzetten (${PREVIOUS_SPLASH:-text})" - rm -rf /usr/share/plymouth/themes/voxip-kiosk + rm -rf /usr/share/plymouth/themes/daynivo-kiosk plymouth-set-default-theme -R "${PREVIOUS_SPLASH:-text}" >/dev/null 2>&1 || true fi -if [[ -f /etc/systemd/system/display-kiosk.service.voxip-disabled ]]; then - echo " (de eerdere Daynivo-kioskservice staat nog als display-kiosk.service.voxip-disabled)" +if [[ -f /etc/systemd/system/display-kiosk.service.daynivo-disabled ]]; then + echo " (de eerdere Daynivo-kioskservice staat nog als display-kiosk.service.daynivo-disabled)" fi if [[ $PURGE -eq 1 ]]; then echo "==> Configuratie, status, logs en gebruikers verwijderen" - rm -rf /etc/voxip-kiosk /var/lib/voxip-kiosk /var/lib/voxip-kiosk-network /var/lib/voxip-kiosk-browser /var/log/voxip-kiosk + rm -rf /etc/daynivo-kiosk /var/lib/daynivo-kiosk /var/lib/daynivo-kiosk-network /var/lib/daynivo-kiosk-browser /var/log/daynivo-kiosk # Downloaded releases (install-online.sh and the updater); safe even when running from there. - rm -rf /opt/daynivo-kiosk-os /var/cache/voxip-kiosk - rm -f /etc/NetworkManager/system-connections/voxip-eth0.nmconnection /etc/NetworkManager/system-connections/voxip-wlan0.nmconnection + rm -rf /opt/daynivo-kiosk-os /var/cache/daynivo-kiosk + rm -f /etc/NetworkManager/system-connections/daynivo-eth0.nmconnection /etc/NetworkManager/system-connections/daynivo-wlan0.nmconnection nmcli connection reload 2>/dev/null || true userdel -r kiosk 2>/dev/null || true - userdel voxip 2>/dev/null || true + userdel daynivo 2>/dev/null || true groupdel kiosk 2>/dev/null || true - groupdel voxip 2>/dev/null || true + groupdel daynivo 2>/dev/null || true else - echo " Configuratie bewaard in /etc/voxip-kiosk (verwijderen met --purge)." - echo " Daynivo-netwerkprofielen (voxip-eth0/voxip-wlan0) blijven actief." + echo " Configuratie bewaard in /etc/daynivo-kiosk (verwijderen met --purge)." + echo " Daynivo-netwerkprofielen (daynivo-eth0/daynivo-wlan0) blijven actief." fi if [[ -n $PREVIOUS_TARGET ]]; then systemctl set-default "$PREVIOUS_TARGET" >/dev/null 2>&1 || true; fi diff --git a/update.sh b/update.sh index c9d6fb3..72338a4 100755 --- a/update.sh +++ b/update.sh @@ -5,7 +5,7 @@ # sudo ./update.sh # git pull --ff-only, back up config, install --upgrade # sudo ./update.sh --no-pull # install the code as it is in this directory # -# The configuration in /etc/voxip-kiosk is backed up first and never overwritten. +# The configuration in /etc/daynivo-kiosk is backed up first and never overwritten. set -euo pipefail @@ -15,7 +15,7 @@ PULL=1 [[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { sed -n '3,9p' "$0" | sed 's/^# \{0,1\}//'; exit 0; } [[ $EUID -eq 0 ]] || { echo "Voer dit script uit met sudo." >&2; exit 1; } -BEFORE="$(cat /usr/share/voxip-kiosk/VERSION 2>/dev/null || echo 'niet geïnstalleerd')" +BEFORE="$(cat /usr/share/daynivo-kiosk/VERSION 2>/dev/null || cat /usr/share/voxip-kiosk/VERSION 2>/dev/null || echo 'niet geïnstalleerd')" if [[ $PULL -eq 1 && -d "$SRC/.git" ]]; then echo "==> Laatste versie ophalen" @@ -23,16 +23,19 @@ if [[ $PULL -eq 1 && -d "$SRC/.git" ]]; then sudo -u "$OWNER" git -C "$SRC" pull --ff-only fi -if [[ -d /etc/voxip-kiosk ]]; then - BACKUP="/var/backups/voxip-kiosk-$(date +%Y%m%d-%H%M%S).tar.gz" +# Before the rename to Daynivo (up to 1.2.x) the configuration lived in /etc/voxip-kiosk. +CONF_DIR=daynivo-kiosk +if [[ ! -d /etc/daynivo-kiosk && -d /etc/voxip-kiosk ]]; then CONF_DIR=voxip-kiosk; fi +if [[ -d /etc/$CONF_DIR ]]; then + BACKUP="/var/backups/daynivo-kiosk-$(date +%Y%m%d-%H%M%S).tar.gz" echo "==> Configuratie back-uppen naar $BACKUP" install -d -m 0700 /var/backups - tar -C /etc -czf "$BACKUP" voxip-kiosk + tar -C /etc -czf "$BACKUP" "$CONF_DIR" chmod 0600 "$BACKUP" # keep the five most recent backups - ls -1t /var/backups/voxip-kiosk-*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f + ls -1t /var/backups/daynivo-kiosk-*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f fi "$SRC/install.sh" --upgrade -echo "==> Bijgewerkt: $BEFORE → $(cat /usr/share/voxip-kiosk/VERSION)" +echo "==> Bijgewerkt: $BEFORE → $(cat /usr/share/daynivo-kiosk/VERSION)"