Rename every remaining voxip name to daynivo, with a one-time migration
CI / test-bookworm (push) Successful in 29s
CI / test-latest (push) Successful in 31s

Services (daynivo-kiosk-*, daynivo-network-guard, daynivo-boot-import),
programs in /usr/lib/daynivo-kiosk, folders /etc, /var/lib, /var/log and
/var/cache daynivo-kiosk*, the system user daynivo, DAYNIVO_* settings,
the plymouth theme, network profiles daynivo-eth0/wlan0, the image stage
and its first user daynivoadmin.

install.sh moves a kiosk installed up to 1.2.x over once: old services
stopped and removed, folders moved (configuration, password, browser
profile, logs) with symlinks under the old names, the voxip user renamed
with the same uid, network profiles renamed unless a change awaits
confirmation, and old leftovers removed. Tested by upgrading a configured
1.2.0 installation in a container, and running the install a second time.

Old names keep working where people type or place them: voxip-config.json,
voxip-authorized_keys, voxip-network-reset, voxip-kiosk-ctl, and
VOXIP_DEFAULT_URL / VOXIP_DEVICE_NAME for image builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rothmanandClaude Opus 5.5 committed 2026-11-05 23:58:03 +01:00
1 parent 6733aacb6e
commit eb0242c182
68 files changed
+527 -424

No files matched your search

+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- name: Tests - name: Tests
run: python3 -m pytest -p no:cacheprovider run: python3 -m pytest -p no:cacheprovider
- name: Shellcheck - 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: test-latest:
runs-on: ubuntu-latest runs-on: ubuntu-latest
+6 -6
View File
@@ -1,8 +1,8 @@
PY ?= .venv/bin/python PY ?= .venv/bin/python
DEV := $(CURDIR)/.dev DEV := $(CURDIR)/.dev
DEV_ENV := PYTHONPATH=src VOXIP_CONFIG_DIR=$(DEV)/etc VOXIP_STATE_DIR=$(DEV)/state VOXIP_LOG_DIR=$(DEV)/log \ DEV_ENV := PYTHONPATH=src DAYNIVO_CONFIG_DIR=$(DEV)/etc DAYNIVO_STATE_DIR=$(DEV)/state DAYNIVO_LOG_DIR=$(DEV)/log \
VOXIP_SHARE_DIR=$(DEV)/share VOXIP_AGENT_RUN_DIR=$(DEV)/run VOXIP_BROWSER_RUN_DIR=$(DEV)/run \ DAYNIVO_SHARE_DIR=$(DEV)/share DAYNIVO_AGENT_RUN_DIR=$(DEV)/run DAYNIVO_BROWSER_RUN_DIR=$(DEV)/run \
VOXIP_NETWORK_STATE_DIR=$(DEV)/net VOXIP_HELPER=/nonexistent/voxip-kiosk-helper DAYNIVO_NETWORK_STATE_DIR=$(DEV)/net DAYNIVO_HELPER=/nonexistent/daynivo-kiosk-helper
.PHONY: venv test lint test-bookworm dev image clean .PHONY: venv test lint test-bookworm dev image clean
@@ -13,8 +13,8 @@ test:
$(PY) -m pytest $(PY) -m pytest
lint: lint:
shellcheck -S warning install.sh update.sh uninstall.sh image/build.sh image/stage-voxip/prerun.sh \ shellcheck -S warning install.sh update.sh uninstall.sh image/build.sh image/stage-daynivo/prerun.sh \
image/stage-voxip/00-voxip/00-run.sh bin/voxip-kiosk-x 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. # The test suite against the exact Python/Flask/argon2 versions that Raspberry Pi OS Bookworm ships.
test-bookworm: test-bookworm:
@@ -22,7 +22,7 @@ test-bookworm:
apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \ 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 && \ 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 && \ 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). # Web interface on http://127.0.0.1:8080 with throwaway state in .dev/ (system actions fail gracefully).
dev: dev:
+41 -16
View File
@@ -12,7 +12,7 @@ webinterface **Daynivo Kiosk Manager** op `http://kiosk.local:8080`.
een setupcode die op het scherm staat. een setupcode die op het scherm staat.
- Netwerkwijzigingen met automatische rollback. - Netwerkwijzigingen met automatische rollback.
- Geen klantspecifieke code: alles per klant staat in - 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. worden meegegeven.
De architectuur en de veiligheidskeuzes staan in 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, 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. start de kiosk. Aan het eind toont het de setupcode.
Draaide hier eerder de Daynivo-kiosk (`raspberry-pi/install-kiosk.sh` uit 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*, In de webinterface onder **Systeem → Software-updates**: *Nu controleren*,
*Bijwerken naar …*, en het vinkje **Automatisch bijwerken**. Elke nacht *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 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. ook op een apparaat dat met de image of vanuit een clone is geïnstalleerd.
Vanaf de commandoregel: Vanaf de commandoregel:
```bash ```bash
sudo /usr/lib/voxip-kiosk/voxip-kiosk-updater --check # alleen kijken sudo /usr/lib/daynivo-kiosk/daynivo-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 --install # nieuwste release installeren
``` ```
De updater installeert alleen een nieuwere versie met een kloppende De updater installeert alleen een nieuwere versie met een kloppende
@@ -89,15 +89,40 @@ het ook met git:
```bash ```bash
cd daynivo-kiosk-os 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 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 (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`. 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 ### Verwijderen
```bash ```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), 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 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. installatie.
Vereist: een Linux-buildmachine (x86_64 of arm64) met Docker en git. Op 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) | | `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) | | `RELEASE` | `bookworm` | `bookworm` of `trixie` (moet bij `PI_GEN_REF` passen) |
| `VOXIP_DEFAULT_URL` | `https://schermen-ijsselflat.voxip.nl` | standaard kiosk-URL | | `DAYNIVO_DEFAULT_URL` | `https://schermen-ijsselflat.voxip.nl` | standaard kiosk-URL |
| `VOXIP_DEVICE_NAME` | `Daynivo Kiosk` | standaard apparaatnaam | | `DAYNIVO_DEVICE_NAME` | `Daynivo Kiosk` | standaard apparaatnaam |
| `TARGET_HOSTNAME` | `kiosk` | hostname (`http://<hostname>.local:8080`) | | `TARGET_HOSTNAME` | `kiosk` | hostname (`http://<hostname>.local:8080`) |
| `ALLOW_DIRTY` | `0` | `1` = bouw de werkmap in plaats van de laatste commit | | `ALLOW_DIRTY` | `0` | `1` = bouw de werkmap in plaats van de laatste commit |
**Reproduceerbaarheid.** pi-gen staat vast op een tag en de broncode **Reproduceerbaarheid.** pi-gen staat vast op een tag en de broncode
gaat via `git archive` van één commit mee. Beide staan in `BUILD-INFO` 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 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 bouwen zijn. Er bestaat geen snapshot-archief voor Raspberry Pi OS, dus
twee builds op verschillende dagen kunnen nieuwere pakketversies bevatten. 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 restart-browser # Chromium herstarten
sudo daynivo-kiosk-ctl health # healthcheck-rapport sudo daynivo-kiosk-ctl health # healthcheck-rapport
sudo daynivo-kiosk-ctl maintenance on|off # healthcheck tijdelijk niets laten herstellen 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 | | Sleutel | Standaard | Betekenis |
|---|---|---| |---|---|---|
@@ -270,8 +295,8 @@ make dev # http://127.0.0.1:8080 met tijdelijke mappen in .dev/
| Symptoom | Oplossing | | 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. | | 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. | | `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. | | Onderspanning in het dashboard | Gebruik de officiële 5,1 V/2,5 A-voeding. Onderspanning veroorzaakt crashes en SD-kaartcorruptie. |
+9
View File
@@ -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())
+9
View File
@@ -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())
+2 -2
View File
@@ -1,8 +1,8 @@
#!/usr/bin/python3 -I #!/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 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 from daynivo_kiosk.ctl import main # noqa: E402
+9
View File
@@ -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())
+9
View File
@@ -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())
+9
View File
@@ -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())
+9
View File
@@ -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())
+1 -1
View File
@@ -2,7 +2,7 @@
# Starts the kiosk X server on vt7 for user "kiosk" (via Xorg.wrap). # Starts the kiosk X server on vt7 for user "kiosk" (via Xorg.wrap).
# A fresh MIT cookie per start; Chromium reads it via XAUTHORITY. # A fresh MIT cookie per start; Chromium reads it via XAUTHORITY.
set -eu set -eu
AUTH="${RUNTIME_DIRECTORY:-/run/voxip-kiosk-x}/Xauthority" AUTH="${RUNTIME_DIRECTORY:-/run/daynivo-kiosk-x}/Xauthority"
umask 077 umask 077
: > "$AUTH" : > "$AUTH"
xauth -q -f "$AUTH" add :0 . "$(mcookie)" xauth -q -f "$AUTH" add :0 . "$(mcookie)"
-9
View File
@@ -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())
-9
View File
@@ -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())
-9
View File
@@ -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())
-9
View File
@@ -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())
-9
View File
@@ -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())
-9
View File
@@ -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())
File renamed without changes.
File renamed without changes.
+3 -3
View File
@@ -1,4 +1,4 @@
/var/log/voxip-kiosk/*.log { /var/log/daynivo-kiosk/*.log {
weekly weekly
rotate 8 rotate 8
maxsize 2M maxsize 2M
@@ -6,6 +6,6 @@
delaycompress delaycompress
missingok missingok
notifempty notifempty
create 0640 voxip voxip create 0640 daynivo daynivo
su voxip voxip su daynivo daynivo
} }
@@ -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
File renamed without changes.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

@@ -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
+3 -3
View File
@@ -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. # as root: the restricted helper, which validates all of its input itself.
Defaults:voxip !requiretty Defaults:daynivo !requiretty
voxip ALL=(root) NOPASSWD: /usr/lib/voxip-kiosk/voxip-kiosk-helper daynivo ALL=(root) NOPASSWD: /usr/lib/daynivo-kiosk/daynivo-kiosk-helper
+26 -26
View File
@@ -11,7 +11,7 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt.
- Eén HTTPS-pagina fullscreen in Chromium, zonder desktopomgeving. - Eén HTTPS-pagina fullscreen in Chromium, zonder desktopomgeving.
- Lokale webbeheerinterface (*Daynivo Kiosk Manager*) op poort 8080. - Lokale webbeheerinterface (*Daynivo Kiosk Manager*) op poort 8080.
- Geen klantspecifieke code: alles wat per klant verschilt staat in - 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`). worden meegegeven (`daynivo-config.json`).
## Overzicht ## Overzicht
@@ -19,25 +19,25 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt.
``` ```
┌──────────────────────── Raspberry Pi ────────────────────────┐ ┌──────────────────────── 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 │ │ │ DISPLAY=:0 │
│ voxip-kiosk-browser.service Chromium --kiosk (user kiosk) │ │ daynivo-kiosk-browser.service Chromium --kiosk (user kiosk) │
│ ▲ CDP 127.0.0.1:9222 │ │ ▲ CDP 127.0.0.1:9222 │
│ │ ┌─────────────────────────────┐ │ │ │ ┌─────────────────────────────┐ │
│ ├──┤ voxip-kiosk-agent.service │ navigatie, offline-│ │ ├──┤ daynivo-kiosk-agent.service │ navigatie, offline-│
│ │ │ (user kiosk) │ pagina, verversen, │ │ │ │ (user kiosk) │ pagina, verversen, │
│ │ └─────────────────────────────┘ hang-detectie │ │ │ └─────────────────────────────┘ 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) │ │ │ sudo -n (één commando) │
│ ▼ │ │ ▼ │
│ voxip-kiosk-helper root, vaste werkwoorden, │ │ daynivo-kiosk-helper root, vaste werkwoorden, │
│ strikte invoervalidatie │ │ strikte invoervalidatie │
│ │ │ │
│ voxip-kiosk-healthcheck.timer elke minuut, root │ │ daynivo-kiosk-healthcheck.timer elke minuut, root │
│ voxip-network-guard.service netwerk-rollback bij boot │ │ daynivo-network-guard.service netwerk-rollback bij boot │
│ voxip-boot-import.service config/SSH-sleutels vanaf │ │ daynivo-boot-import.service config/SSH-sleutels vanaf │
│ de bootpartitie │ │ de bootpartitie │
└──────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────┘
``` ```
@@ -46,16 +46,16 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt.
| Onderdeel | Gebruiker | Taak | | Onderdeel | Gebruiker | Taak |
|---|---|---| |---|---|---|
| `voxip-kiosk-x` | `kiosk` (via Xorg.wrap) | Minimale X-server op vt7, zonder cursor, zonder TCP. | | `daynivo-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. | | `daynivo-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. | | `daynivo-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). | | `daynivo-kiosk-manager` | `daynivo` | 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. | | `daynivo-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/<versie>` en draait `update.sh --no-pull`. Nooit een oudere of gelijke versie. | | `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/<versie>` 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-healthcheck` | `root` | Bewaakt alle services en herstelt ze, met logging. |
De webinterface draait **nooit** als root. De sudoers-regel staat 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); - draait met `python3 -I` (geen `PYTHONPATH`, geen user site-packages);
- kent alleen een vaste lijst werkwoorden; interne werkwoorden (zoals - 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* Xorg en Chromium zijn aparte services. Daardoor is *Chromium herstarten*
snel (X blijft draaien) en geeft het exitcode van Chromium direct aan snel (X blijft draaien) en geeft het exitcode van Chromium direct aan
systemd door. `voxip-kiosk-browser` heeft `Requires=` en `PartOf=` op systemd door. `daynivo-kiosk-browser` heeft `Requires=` en `PartOf=` op
`voxip-kiosk-x`: valt X weg, dan start de browser opnieuw mee. `daynivo-kiosk-x`: valt X weg, dan start de browser opnieuw mee.
### Chromium besturen via CDP ### Chromium besturen via CDP
@@ -86,7 +86,7 @@ webinterface gebruiken dit om:
### Offline-gedrag ### Offline-gedrag
Chromium start altijd op een lokale startpagina 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 HTTPS-verzoek (mét certificaatvalidatie) of de doel-URL bereikbaar is en
navigeert pas dan. De offline-pagina verschijnt alleen als de pagina niet navigeert pas dan. De offline-pagina verschijnt alleen als de pagina niet
**geladen** kan worden (startpagina, Chromium-foutpagina). Valt het **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` 1. De helper maakt een snapshot van `/etc/NetworkManager/system-connections`
en van de actieve verbindingen. 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). 100) en plant een rollback-timer (`systemd-run`, 180 s).
3. Activatie gebeurt asynchroon, zodat het HTTP-antwoord nog aankomt. 3. Activatie gebeurt asynchroon, zodat het HTTP-antwoord nog aankomt.
4. De beheerder bevestigt binnen 180 s (eventueel via het nieuwe adres), 4. De beheerder bevestigt binnen 180 s (eventueel via het nieuwe adres),
anders zet de timer de snapshot terug. anders zet de timer de snapshot terug.
5. Valt de stroom uit tijdens die periode, dan zet 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. vóór NetworkManager start.
6. Noodherstel: een leeg bestand `daynivo-network-reset` op de bootpartitie 6. Noodherstel: een leeg bestand `daynivo-network-reset` op de bootpartitie
verwijdert bij de volgende boot alle Daynivo-netwerkprofielen (terug naar 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 ### 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` Wordt atomair opgeslagen (tijdelijk bestand, `fsync`, `rename`, `fsync`
van de map) met een `.bak` van de vorige versie. Ongeldige waarden vallen 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. bij het laden terug op de standaard, zodat de kiosk altijd start.
Onbekende sleutels blijven bewaard (vooruit-/achteruitcompatibel). 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 - Updates (`install.sh --upgrade` / `update.sh` / de updater) overschrijven
nooit bestaande configuratie. De updater draait in een eigen systemd-unit, nooit bestaande configuratie. De updater draait in een eigen systemd-unit,
zodat het herstarten van de beheerinterface tijdens `install.sh` de update 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 ├── install.sh installatie op bestaande Pi OS + gebruikt door image-build
├── update.sh update met backup van configuratie ├── update.sh update met backup van configuratie
├── uninstall.sh verwijderen (--purge voor alles) ├── 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) ├── src/daynivo_kiosk/ Python-package (alle logica)
│ ├── config.py laden/valideren/atomair opslaan │ ├── config.py laden/valideren/atomair opslaan
│ ├── validation.py gedeelde invoervalidatie │ ├── validation.py gedeelde invoervalidatie
@@ -197,7 +197,7 @@ daynivo-kiosk-os/
├── www/ lokale kioskpagina's (start, offline, setup) ├── www/ lokale kioskpagina's (start, offline, setup)
├── systemd/ unit-bestanden ├── systemd/ unit-bestanden
├── config/ standaardconfig, sudoers, journald, logrotate, … ├── config/ standaardconfig, sudoers, journald, logrotate, …
├── image/ pi-gen image-builder (stage-voxip) ├── image/ pi-gen image-builder (stage-daynivo)
├── tests/ pytest-suite ├── tests/ pytest-suite
└── docs/ architectuur, hardwaretest └── docs/ architectuur, hardwaretest
``` ```
+6 -6
View File
@@ -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, - [ ] 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 `http://kiosk.local:8080` en het IP-adres. Er is geen muiscursor en
er zijn geen dialoogvensters. 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. geen bruikbaar standaardwachtwoord.
## 2. Initiële configuratie ## 2. Initiële configuratie
@@ -47,7 +47,7 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
(zie Logboek → Kiosk-agent). (zie Logboek → Kiosk-agent).
- [ ] Screenshot op de Kiosk-pagina toont wat er op het scherm staat. - [ ] Screenshot op de Kiosk-pagina toont wat er op het scherm staat.
- [ ] Daynivo-URL met `?token=`: het token is overal gemaskeerd - [ ] 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 ## 4. Herstel
@@ -61,9 +61,9 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
Zet de URL daarna terug. Zet de URL daarna terug.
- [ ] Vastgelopen pagina: open via SSH-tunnel DevTools of zet een testpagina met - [ ] 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. `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 - [ ] De webinterface blijft werken terwijl Chromium gestopt is
(`sudo systemctl stop voxip-kiosk-browser`). (`sudo systemctl stop daynivo-kiosk-browser`).
## 5. Netwerk ## 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 op Gitea: "beschikbaar". *Bijwerken naar …*: binnen enkele minuten is de
nieuwe versie actief, de beheerinterface komt terug, configuratie en nieuwe versie actief, de beheerinterface komt terug, configuratie en
wachtwoord ongewijzigd. 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. 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 - [ ] `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. Raspberry Pi OS Lite: installeert de nieuwste release, setupcode op het scherm.
- [ ] `sudo ./uninstall.sh --purge` op een testkaart: geen Daynivo-services of - [ ] `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 - [ ] Installatie op een bestaande Raspberry Pi OS Lite (Bookworm) met de
Daynivo-kiosk erop: URL overgenomen, `display-kiosk.service` uitgeschakeld. Daynivo-kiosk erop: URL overgenomen, `display-kiosk.service` uitgeschakeld.
+2 -2
View File
@@ -8,7 +8,7 @@ een fout; de reden staat dan in daynivo-config.error.txt).
daynivo-config.json daynivo-config.json
Instellingen voor deze kiosk. Zie daynivo-config.example.json. Toegestaan: 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: "wifi_country". Voorbeeld:
{ {
@@ -20,7 +20,7 @@ daynivo-config.json
daynivo-authorized_keys daynivo-authorized_keys
Openbare SSH-sleutels (één per regel). SSH wordt dan ingeschakeld, alleen 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). in Raspberry Pi Imager hebt aangemaakt).
daynivo-network-reset daynivo-network-reset
+13 -12
View File
@@ -8,8 +8,8 @@
# Environment (all optional): # Environment (all optional):
# PI_GEN_REF pi-gen tag/branch (32-bit armhf). Default: pinned Bookworm release. # PI_GEN_REF pi-gen tag/branch (32-bit armhf). Default: pinned Bookworm release.
# RELEASE bookworm | trixie (must match PI_GEN_REF). Default: bookworm. # RELEASE bookworm | trixie (must match PI_GEN_REF). Default: bookworm.
# VOXIP_DEFAULT_URL kiosk URL baked into the default config. # DAYNIVO_DEFAULT_URL kiosk URL baked into the default config.
# VOXIP_DEVICE_NAME default device name. # DAYNIVO_DEVICE_NAME default device name.
# TARGET_HOSTNAME default hostname (the admin UI is at http://<hostname>.local:8080). # TARGET_HOSTNAME default hostname (the admin UI is at http://<hostname>.local:8080).
# ALLOW_DIRTY=1 build from the working tree instead of the committed HEAD. # 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_REPO="${PI_GEN_REPO:-https://github.com/RPi-Distro/pi-gen.git}"
PI_GEN_REF="${PI_GEN_REF:-2024-11-19-raspios-bookworm-armhf}" PI_GEN_REF="${PI_GEN_REF:-2024-11-19-raspios-bookworm-armhf}"
RELEASE="${RELEASE:-bookworm}" RELEASE="${RELEASE:-bookworm}"
VOXIP_DEFAULT_URL="${VOXIP_DEFAULT_URL:-https://schermen-ijsselflat.voxip.nl}" # VOXIP_* are the names from before the rename and still work.
VOXIP_DEVICE_NAME="${VOXIP_DEVICE_NAME:-Daynivo Kiosk}" 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}" TARGET_HOSTNAME="${TARGET_HOSTNAME:-kiosk}"
NATIVE=0 NATIVE=0
[[ ${1:-} == "--native" ]] && NATIVE=1 [[ ${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)" PI_GEN_COMMIT="$(git -C "$WORK/pi-gen" rev-parse HEAD)"
PIGEN="$WORK/pi-gen" 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" touch "$PIGEN/stage2/SKIP_IMAGES"
rm -f "$PIGEN/stage2/EXPORT_NOOBS" rm -f "$PIGEN/stage2/EXPORT_NOOBS"
echo "==> Daynivo-stage voorbereiden" echo "==> Daynivo-stage voorbereiden"
cp -a "$ROOT/image/stage-voxip" "$PIGEN/stage-voxip" cp -a "$ROOT/image/stage-daynivo" "$PIGEN/stage-daynivo"
PAYLOAD="$PIGEN/stage-voxip/00-voxip/files/voxip-kiosk" PAYLOAD="$PIGEN/stage-daynivo/00-daynivo/files/daynivo-kiosk"
mkdir -p "$PAYLOAD" mkdir -p "$PAYLOAD"
if [[ ${ALLOW_DIRTY:-0} == 1 ]] || ! git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1; then 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)" echo " (werkmap wordt gebruikt, niet de laatste commit)"
@@ -67,9 +68,9 @@ else
fi fi
BUILD_DATE="$(date -u +%Y-%m-%d)" BUILD_DATE="$(date -u +%Y-%m-%d)"
cat > "$PIGEN/stage-voxip/00-voxip/files/build.env" <<EOF cat > "$PIGEN/stage-daynivo/00-daynivo/files/build.env" <<EOF
VOXIP_DEFAULT_URL=$(printf %q "$VOXIP_DEFAULT_URL") DAYNIVO_DEFAULT_URL=$(printf %q "$DAYNIVO_DEFAULT_URL")
VOXIP_DEVICE_NAME=$(printf %q "$VOXIP_DEVICE_NAME") DAYNIVO_DEVICE_NAME=$(printf %q "$DAYNIVO_DEVICE_NAME")
EOF EOF
cat > "$PAYLOAD/BUILD-INFO" <<EOF cat > "$PAYLOAD/BUILD-INFO" <<EOF
daynivo_kiosk_os=$VERSION daynivo_kiosk_os=$VERSION
@@ -97,11 +98,11 @@ KEYBOARD_LAYOUT="English (US)"
TIMEZONE_DEFAULT=Europe/Amsterdam TIMEZONE_DEFAULT=Europe/Amsterdam
WPA_COUNTRY=NL WPA_COUNTRY=NL
TARGET_HOSTNAME=$TARGET_HOSTNAME TARGET_HOSTNAME=$TARGET_HOSTNAME
FIRST_USER_NAME=voxipadmin FIRST_USER_NAME=daynivoadmin
FIRST_USER_PASS=$FIRST_USER_PASS FIRST_USER_PASS=$FIRST_USER_PASS
DISABLE_FIRST_BOOT_USER_RENAME=1 DISABLE_FIRST_BOOT_USER_RENAME=1
ENABLE_SSH=0 ENABLE_SSH=0
STAGE_LIST="stage0 stage1 stage2 stage-voxip" STAGE_LIST="stage0 stage1 stage2 stage-daynivo"
EOF EOF
echo "==> Image bouwen (dit duurt 30–90 minuten)" echo "==> Image bouwen (dit duurt 30–90 minuten)"
+23
View File
@@ -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"
File renamed without changes.
File renamed without changes.
-23
View File
@@ -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"
+122 -53
View File
@@ -8,9 +8,9 @@
# #
# sudo ./install.sh [--url https://…] [--name "Hal begane grond"] [--hostname hal-bg] # sudo ./install.sh [--url https://…] [--name "Hal begane grond"] [--hostname hal-bg]
# sudo ./install.sh --upgrade # update code, keep configuration # 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 set -euo pipefail
@@ -21,15 +21,15 @@ NAME=""
NEW_HOSTNAME="" NEW_HOSTNAME=""
FORCE=0 FORCE=0
LIB=/usr/lib/voxip-kiosk LIB=/usr/lib/daynivo-kiosk
SHARE=/usr/share/voxip-kiosk SHARE=/usr/share/daynivo-kiosk
DOC=/usr/share/doc/voxip-kiosk DOC=/usr/share/doc/daynivo-kiosk
ETC=/etc/voxip-kiosk ETC=/etc/daynivo-kiosk
UNITS=(voxip-kiosk-x.service voxip-kiosk-browser.service voxip-kiosk-agent.service voxip-kiosk-manager.service UNITS=(daynivo-kiosk-x.service daynivo-kiosk-browser.service daynivo-kiosk-agent.service daynivo-kiosk-manager.service
voxip-kiosk-healthcheck.service voxip-kiosk-healthcheck.timer voxip-network-guard.service voxip-boot-import.service daynivo-kiosk-healthcheck.service daynivo-kiosk-healthcheck.timer daynivo-network-guard.service daynivo-boot-import.service
voxip-kiosk-update.service voxip-kiosk-update.timer) daynivo-kiosk-update.service daynivo-kiosk-update.timer)
ENABLE=(voxip-kiosk-x.service voxip-kiosk-browser.service voxip-kiosk-agent.service voxip-kiosk-manager.service ENABLE=(daynivo-kiosk-x.service daynivo-kiosk-browser.service daynivo-kiosk-agent.service daynivo-kiosk-manager.service
voxip-kiosk-healthcheck.timer voxip-network-guard.service voxip-boot-import.service voxip-kiosk-update.timer) 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' "$*"; } say() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33mLet op:\033[0m %s\n' "$*" >&2; } 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[@]}" 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 ---------------------------------------------------------------------- # --- users ----------------------------------------------------------------------
say "Gebruikers aanmaken" say "Gebruikers aanmaken"
getent group kiosk >/dev/null || groupadd --system kiosk 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 for g in video render input audio; do
getent group "$g" >/dev/null && usermod -aG "$g" kiosk getent group "$g" >/dev/null && usermod -aG "$g" kiosk
done done
getent group voxip >/dev/null || groupadd --system voxip getent group daynivo >/dev/null || groupadd --system daynivo
id voxip >/dev/null 2>&1 || useradd --system --gid voxip --home-dir /var/lib/voxip-kiosk --no-create-home \ 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" voxip --shell /usr/sbin/nologin --comment "Daynivo Kiosk Manager" daynivo
for g in systemd-journal video; do 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 done
# --- application files -------------------------------------------------------------- # --- application files --------------------------------------------------------------
@@ -135,7 +204,7 @@ rm -rf "$LIB/python.old"
mv "$LIB/python.new" "$LIB/python" mv "$LIB/python.new" "$LIB/python"
rm -rf "$LIB/python.old" 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" install -m 0755 -o root -g root "$SRC/bin/$bin" "$LIB/$bin"
done done
install -m 0755 -o root -g root "$SRC/bin/daynivo-kiosk-ctl" /usr/local/sbin/daynivo-kiosk-ctl 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 ------------------------------------------------------------------- # --- configuration -------------------------------------------------------------------
say "Configuratie" say "Configuratie"
install -d -o voxip -g kiosk -m 2750 "$ETC" install -d -o daynivo -g kiosk -m 2750 "$ETC"
install -d -o voxip -g voxip -m 0750 /var/lib/voxip-kiosk install -d -o daynivo -g daynivo -m 0750 /var/lib/daynivo-kiosk
install -d -o root -g root -m 0755 /var/lib/voxip-kiosk-network install -d -o root -g root -m 0755 /var/lib/daynivo-kiosk-network
install -d -o voxip -g voxip -m 0750 /var/log/voxip-kiosk 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. # 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 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" say "URL overgenomen van de Daynivo-kioskinstallatie"
fi fi
if [[ $LIVE -eq 1 ]]; then systemctl disable --now display-kiosk.service 2>/dev/null || true; 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 fi
PYRUN=(python3 -I -c) PYRUN=(python3 -I -c)
"${PYRUN[@]}" ' "${PYRUN[@]}" '
import json, os, sys 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 from daynivo_kiosk import config as c
path, default, url, name = sys.argv[1:5] path, default, url, name = sys.argv[1:5]
updates = {} updates = {}
@@ -194,36 +263,36 @@ else:
c.atomic_write_json(c.Path(path), data) c.atomic_write_json(c.Path(path), data)
print("Nieuwe configuratie aangemaakt") print("Nieuwe configuratie aangemaakt")
' "$ETC/config.json" "$SRC/config/config.default.json" "$URL" "$NAME" || die "Ongeldige --url of --name." ' "$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" chmod 0640 "$ETC/config.json"
touch "$ETC/.config.lock" && chown voxip:kiosk "$ETC/.config.lock" && chmod 0640 "$ETC/.config.lock" touch "$ETC/.config.lock" && chown daynivo:kiosk "$ETC/.config.lock" && chmod 0640 "$ETC/.config.lock"
[[ -f $ETC/admin.json ]] && chown voxip:voxip "$ETC/admin.json" && chmod 0600 "$ETC/admin.json" [[ -f $ETC/admin.json ]] && chown daynivo:daynivo "$ETC/admin.json" && chmod 0600 "$ETC/admin.json"
# --- system integration ---------------------------------------------------------------- # --- system integration ----------------------------------------------------------------
say "Systeemintegratie" say "Systeemintegratie"
TMP_SUDOERS="$(mktemp)" TMP_SUDOERS="$(mktemp)"
install -m 0440 "$SRC/config/sudoers" "$TMP_SUDOERS" install -m 0440 "$SRC/config/sudoers" "$TMP_SUDOERS"
visudo -cqf "$TMP_SUDOERS" || die "sudoers-bestand ongeldig" visudo -cqf "$TMP_SUDOERS" || die "sudoers-bestand ongeldig"
mv "$TMP_SUDOERS" /etc/sudoers.d/voxip-kiosk mv "$TMP_SUDOERS" /etc/sudoers.d/daynivo-kiosk
chown root:root /etc/sudoers.d/voxip-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/journald.conf" /etc/systemd/journald.conf.d/daynivo-kiosk.conf
install -D -m 0644 "$SRC/config/watchdog.conf" /etc/systemd/system.conf.d/voxip-watchdog.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/voxip-kiosk 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 if [[ -f /etc/X11/Xwrapper.config && ! -f /etc/X11/Xwrapper.config.daynivo-orig ]]; then
cp -a /etc/X11/Xwrapper.config /etc/X11/Xwrapper.config.voxip-orig cp -a /etc/X11/Xwrapper.config /etc/X11/Xwrapper.config.daynivo-orig
fi fi
install -D -m 0644 "$SRC/config/Xwrapper.config" /etc/X11/Xwrapper.config 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 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 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 install -d -m 0755 /etc/avahi/services
sed "s#<port>8080</port>#<port>${ADMIN_PORT}</port>#" "$SRC/config/avahi-voxip.service" > /etc/avahi/services/voxip-kiosk.service sed "s#<port>8080</port>#<port>${ADMIN_PORT}</port>#" "$SRC/config/avahi-daynivo.service" > /etc/avahi/services/daynivo-kiosk.service
chmod 0644 /etc/avahi/services/voxip-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). # 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 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 # Boot splash: logo on white (config/plymouth). Rebuilding the initramfs takes a while
# on a Pi 3, so only when the theme changed. # 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 -d -m 0755 "$SPLASH_DIR"
install -m 0644 "$SRC"/config/plymouth/voxip-kiosk/* "$SPLASH_DIR/" install -m 0644 "$SRC"/config/plymouth/daynivo-kiosk/* "$SPLASH_DIR/"
if [[ ! -f /var/lib/voxip-kiosk/previous-plymouth-theme ]]; then if [[ ! -f /var/lib/daynivo-kiosk/previous-plymouth-theme ]]; then
plymouth-set-default-theme > /var/lib/voxip-kiosk/previous-plymouth-theme 2>/dev/null || true plymouth-set-default-theme > /var/lib/daynivo-kiosk/previous-plymouth-theme 2>/dev/null || true
fi fi
SPLASH_SUM="$(cat "$SPLASH_DIR"/* | sha256sum | cut -d' ' -f1)" 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)" 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 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 else
warn "initramfs bijwerken mislukt; het opstartscherm verschijnt mogelijk pas later tijdens het opstarten." warn "initramfs bijwerken mislukt; het opstartscherm verschijnt mogelijk pas later tijdens het opstarten."
fi 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 if systemctl is-enabled --quiet "$dm" 2>/dev/null; then
warn "$dm wordt uitgeschakeld (de kiosk gebruikt een eigen minimale X-sessie)." warn "$dm wordt uitgeschakeld (de kiosk gebruikt een eigen minimale X-sessie)."
systemctl disable "$dm" 2>/dev/null || true systemctl disable "$dm" 2>/dev/null || true
grep -qx "$dm" /var/lib/voxip-kiosk/disabled-display-managers 2>/dev/null \ grep -qx "$dm" /var/lib/daynivo-kiosk/disabled-display-managers 2>/dev/null \
|| echo "$dm" >> /var/lib/voxip-kiosk/disabled-display-managers || echo "$dm" >> /var/lib/daynivo-kiosk/disabled-display-managers
fi fi
if [[ $LIVE -eq 1 ]] && systemctl is-active --quiet "$dm" 2>/dev/null; then 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." warn "$dm wordt gestopt: de desktop op het scherm sluit nu af."
@@ -302,15 +371,15 @@ for unit in "${UNITS[@]}"; do
done done
if [[ $LIVE -eq 1 ]]; then systemctl daemon-reload; fi if [[ $LIVE -eq 1 ]]; then systemctl daemon-reload; fi
systemctl enable "${ENABLE[@]}" NetworkManager.service avahi-daemon.service >/dev/null systemctl enable "${ENABLE[@]}" NetworkManager.service avahi-daemon.service >/dev/null
if [[ ! -f /var/lib/voxip-kiosk/previous-default-target ]]; then if [[ ! -f /var/lib/daynivo-kiosk/previous-default-target ]]; then
systemctl get-default > /var/lib/voxip-kiosk/previous-default-target 2>/dev/null || true systemctl get-default > /var/lib/daynivo-kiosk/previous-default-target 2>/dev/null || true
fi fi
systemctl set-default multi-user.target >/dev/null systemctl set-default multi-user.target >/dev/null
if [[ -n $NEW_HOSTNAME && $LIVE -eq 0 ]]; then if [[ -n $NEW_HOSTNAME && $LIVE -eq 0 ]]; then
warn "--hostname wordt genegeerd in image-modus (gebruik TARGET_HOSTNAME van pi-gen)." warn "--hostname wordt genegeerd in image-modus (gebruik TARGET_HOSTNAME van pi-gen)."
elif [[ -n $NEW_HOSTNAME ]]; then 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 fi
if [[ $LIVE -eq 0 ]]; then if [[ $LIVE -eq 0 ]]; then
@@ -321,11 +390,11 @@ fi
say "Services starten" say "Services starten"
systemctl restart systemd-journald.service || true systemctl restart systemd-journald.service || true
systemctl restart avahi-daemon.service || true systemctl restart avahi-daemon.service || true
systemctl restart voxip-kiosk-manager.service voxip-kiosk-agent.service systemctl restart daynivo-kiosk-manager.service daynivo-kiosk-agent.service
systemctl start voxip-kiosk-healthcheck.timer voxip-kiosk-update.timer systemctl start daynivo-kiosk-healthcheck.timer daynivo-kiosk-update.timer
systemctl reset-failed voxip-kiosk-x.service voxip-kiosk-browser.service 2>/dev/null || true systemctl reset-failed daynivo-kiosk-x.service daynivo-kiosk-browser.service 2>/dev/null || true
systemctl restart voxip-kiosk-x.service systemctl restart daynivo-kiosk-x.service
systemctl restart voxip-kiosk-browser.service systemctl restart daynivo-kiosk-browser.service
HOST="$(hostname)" HOST="$(hostname)"
SCHEME=http SCHEME=http
+1 -1
View File
@@ -1,5 +1,5 @@
[project] [project]
name = "voxip-kiosk" name = "daynivo-kiosk"
dynamic = ["version"] dynamic = ["version"]
description = "Daynivo Kiosk OS — kiosk runtime and Daynivo Kiosk Manager" description = "Daynivo Kiosk OS — kiosk runtime and Daynivo Kiosk Manager"
requires-python = ">=3.11" requires-python = ">=3.11"
+2 -2
View File
@@ -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 Runs as user ``kiosk`` and steers Chromium through the DevTools Protocol on
127.0.0.1: 127.0.0.1:
@@ -33,7 +33,7 @@ from .config import admin_url, load_config
from .paths import Paths, load_paths from .paths import Paths, load_paths
from .validation import mask_url from .validation import mask_url
log = logging.getLogger("voxip-kiosk-agent") log = logging.getLogger("daynivo-kiosk-agent")
TICK_SECONDS = 5 TICK_SECONDS = 5
PROBE_MAX_AGE_LOADING = 10 PROBE_MAX_AGE_LOADING = 10
+6 -6
View File
@@ -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 server is up. Exit status tells systemd whether to restart: 1 when
``browser_restart`` is enabled (``Restart=on-failure`` restarts it and the ``browser_restart`` is enabled (``Restart=on-failure`` restarts it and the
start limit catches crash loops), 0 when it is disabled. 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 .paths import Paths, load_paths
from .validation import mask_url, parse_resolution from .validation import mask_url, parse_resolution
log = logging.getLogger("voxip-kiosk-browser") log = logging.getLogger("daynivo-kiosk-browser")
CDP_PORT = 9222 CDP_PORT = 9222
CHROMIUM_CANDIDATES = ("/usr/bin/chromium-browser", "/usr/bin/chromium") 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 = data.setdefault("profile", {})
profile["exit_type"] = "Normal" profile["exit_type"] = "Normal"
profile["exited_cleanly"] = True 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") tmp.write_text(json.dumps(data), encoding="utf-8")
os.replace(tmp, prefs) os.replace(tmp, prefs)
def profile_dirs(config: dict[str, Any]) -> tuple[Path, Path]: def profile_dirs(config: dict[str, Any]) -> tuple[Path, Path]:
runtime = Path(os.environ.get("RUNTIME_DIRECTORY", "/run/voxip-kiosk-browser")) runtime = Path(os.environ.get("RUNTIME_DIRECTORY", "/run/daynivo-kiosk-browser"))
state = Path(os.environ.get("STATE_DIRECTORY", "/var/lib/voxip-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" profile = state / "profile" if config.get("browser_profile") == "persistent" else runtime / "profile"
if config.get("browser_profile") != "persistent" and (state / "profile").exists(): if config.get("browser_profile") != "persistent" and (state / "profile").exists():
shutil.rmtree(state / "profile", ignore_errors=True) shutil.rmtree(state / "profile", ignore_errors=True)
+1 -1
View File
@@ -236,7 +236,7 @@ def save_config(path: Path, updates: dict[str, Any]) -> dict[str, Any]:
lock_path = path.with_name(".config.lock") lock_path = path.with_name(".config.lock")
with _thread_lock: with _thread_lock:
# Read-only is enough for flock and works for every writer (the web # 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) lock_fd = os.open(str(lock_path), os.O_RDONLY | os.O_CREAT, 0o640)
try: try:
fcntl.flock(lock_fd, fcntl.LOCK_EX) fcntl.flock(lock_fd, fcntl.LOCK_EX)
+3 -3
View File
@@ -48,7 +48,7 @@ def cmd_setup_code(_args) -> int:
return 1 return 1
code = setupcode.read(paths.setup_code_file) code = setupcode.read(paths.setup_code_file)
if not code: 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 return 1
print(code) print(code)
return 0 return 0
@@ -65,10 +65,10 @@ def cmd_reset_password(args) -> int:
code = setupcode.generate() code = setupcode.generate()
setupcode.write(paths.setup_code_file, code) setupcode.write(paths.setup_code_file, code)
try: 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: except KeyError:
pass 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(f"Wachtwoord verwijderd. Nieuwe setupcode: {code}")
print("Open de beheerinterface en stel een nieuw wachtwoord in; de code staat ook op het kioskscherm.") print("Open de beheerinterface en stel een nieuw wachtwoord in; de code staat ook op het kioskscherm.")
return 0 return 0
+3 -3
View File
@@ -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 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 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 .config import load_config
from .paths import Paths, load_paths 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) ALWAYS_ON = (services.AGENT_UNIT, services.MANAGER_UNIT)
DISPLAY_UNITS = (services.X_UNIT, services.BROWSER_UNIT) DISPLAY_UNITS = (services.X_UNIT, services.BROWSER_UNIT)
@@ -147,7 +147,7 @@ class HealthCheck:
def main(argv: list[str] | None = None) -> int: 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("--check-only", action="store_true", help="alleen rapporteren, niets herstellen")
parser.add_argument("--json", action="store_true", help="rapport als JSON") parser.add_argument("--json", action="store_true", help="rapport als JSON")
args = parser.parse_args(argv) args = parser.parse_args(argv)
+19 -19
View File
@@ -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 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 every argument itself, never invokes a shell and prints a single JSON
object on stdout. object on stdout.
Usage: voxip-kiosk-helper <verb> [args] (network-apply reads JSON on stdin) Usage: daynivo-kiosk-helper <verb> [args] (network-apply reads JSON on stdin)
""" """
from __future__ import annotations from __future__ import annotations
@@ -27,13 +27,13 @@ from . import netconfig, updater
from . import validation as v from . import validation as v
from .paths import Paths, default_paths from .paths import Paths, default_paths
HELPER_PATH = "/usr/lib/voxip-kiosk/voxip-kiosk-helper" HELPER_PATH = "/usr/lib/daynivo-kiosk/daynivo-kiosk-helper"
ROLLBACK_UNIT = "voxip-network-rollback" ROLLBACK_UNIT = "daynivo-network-rollback"
UPDATE_UNIT = "voxip-kiosk-update-now" UPDATE_UNIT = "daynivo-kiosk-update-now"
UPDATER_PATH = "/usr/lib/voxip-kiosk/voxip-kiosk-updater" UPDATER_PATH = "/usr/lib/daynivo-kiosk/daynivo-kiosk-updater"
ACTIVATE_UNIT = "voxip-network-activate" ACTIVATE_UNIT = "daynivo-network-activate"
BOOT_DIRS = (Path("/boot/firmware"), Path("/boot")) 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. # Daynivo and keep working, so existing SD cards and instructions stay valid.
RESET_TRIGGERS = ("daynivo-network-reset", "voxip-network-reset") RESET_TRIGGERS = ("daynivo-network-reset", "voxip-network-reset")
IMPORT_CONFIGS = ("voxip-config.json", "daynivo-config.json") # applied in this order: the Daynivo name wins IMPORT_CONFIGS = ("voxip-config.json", "daynivo-config.json") # applied in this order: the Daynivo name wins
@@ -83,24 +83,24 @@ class Helper:
# -- power & browser ------------------------------------------------- # -- power & browser -------------------------------------------------
def reboot(self) -> dict[str, Any]: 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") log(syslog.LOG_NOTICE, "Herstart aangevraagd via beheerinterface")
return {"message": "De Raspberry Pi wordt over enkele seconden herstart."} return {"message": "De Raspberry Pi wordt over enkele seconden herstart."}
def poweroff(self) -> dict[str, Any]: 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") log(syslog.LOG_NOTICE, "Uitschakelen aangevraagd via beheerinterface")
return {"message": "De Raspberry Pi wordt over enkele seconden uitgeschakeld."} return {"message": "De Raspberry Pi wordt over enkele seconden uitgeschakeld."}
def restart_browser(self) -> dict[str, Any]: 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", "reset-failed", "daynivo-kiosk-browser.service", "daynivo-kiosk-x.service"], check=False)
self.run(["systemctl", "restart", "--no-block", "voxip-kiosk-browser.service"]) self.run(["systemctl", "restart", "--no-block", "daynivo-kiosk-browser.service"])
log(syslog.LOG_NOTICE, "Chromium wordt herstart") log(syslog.LOG_NOTICE, "Chromium wordt herstart")
return {"message": "Chromium wordt herstart."} return {"message": "Chromium wordt herstart."}
def restart_manager(self) -> dict[str, Any]: def restart_manager(self) -> dict[str, Any]:
# Delayed so the web interface can still answer the request that asked for it. # 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") log(syslog.LOG_NOTICE, "Beheerinterface wordt herstart")
return {"message": "De beheerinterface wordt herstart."} return {"message": "De beheerinterface wordt herstart."}
@@ -326,7 +326,7 @@ class Helper:
def _chown_config(self, path: Path) -> None: def _chown_config(self, path: Path) -> None:
try: try:
uid = pwd.getpwnam("voxip").pw_uid uid = pwd.getpwnam("daynivo").pw_uid
gid = grp.getgrnam("kiosk").gr_gid gid = grp.getgrnam("kiosk").gr_gid
except KeyError: except KeyError:
return return
@@ -392,7 +392,7 @@ class Helper:
os.chown(ssh_dir, user.pw_uid, user.pw_gid) os.chown(ssh_dir, user.pw_uid, user.pw_gid)
sshd_dir = self.etc / "ssh" / "sshd_config.d" sshd_dir = self.etc / "ssh" / "sshd_config.d"
sshd_dir.mkdir(parents=True, exist_ok=True) 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" "# Beheerd door Daynivo Kiosk OS: alleen inloggen met SSH-sleutels.\n"
"PasswordAuthentication no\nKbdInteractiveAuthentication no\nPermitRootLogin no\n", "PasswordAuthentication no\nKbdInteractiveAuthentication no\nPermitRootLogin no\n",
encoding="utf-8", 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: 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 argv = sys.argv[1:] if argv is None else argv
environ = os.environ if environ is None else environ 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: if not argv:
print(json.dumps({"ok": False, "error": "Gebruik: voxip-kiosk-helper <opdracht> [argumenten]"})) print(json.dumps({"ok": False, "error": "Gebruik: daynivo-kiosk-helper <opdracht> [argumenten]"}))
return 2 return 2
verb, args = argv[0], argv[1:] verb, args = argv[0], argv[1:]
caller = environ.get("SUDO_USER") 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"})) print(json.dumps({"ok": False, "error": "Opdracht niet toegestaan"}))
return 1 return 1
if helper is None and os.geteuid() != 0: 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 return 1
helper = helper or Helper() helper = helper or Helper()
stdin = sys.stdin.read(16385) if verb == "network-apply" else "" stdin = sys.stdin.read(16385) if verb == "network-apply" else ""
+3 -3
View File
@@ -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 Reads port and HTTPS settings from the kiosk configuration, creates a
self-signed certificate when HTTPS is enabled and none exists yet, then 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 .config import load_config
from .paths import Paths, load_paths from .paths import Paths, load_paths
log = logging.getLogger("voxip-kiosk-manager") log = logging.getLogger("daynivo-kiosk-manager")
PYTHON_LIB = "/usr/lib/voxip-kiosk/python" PYTHON_LIB = "/usr/lib/daynivo-kiosk/python"
def ensure_certificate(paths: Paths) -> tuple[Path, Path]: def ensure_certificate(paths: Paths) -> tuple[Path, Path]:
+1 -1
View File
@@ -15,7 +15,7 @@ from typing import Any
from . import validation as v from . import validation as v
INTERFACES = {"eth0": "ethernet", "wlan0": "wifi"} INTERFACES = {"eth0": "ethernet", "wlan0": "wifi"}
PROFILE_PREFIX = "voxip-" PROFILE_PREFIX = "daynivo-"
ROLLBACK_SECONDS = 180 ROLLBACK_SECONDS = 180
+19 -19
View File
@@ -1,7 +1,7 @@
"""Filesystem locations used by every Daynivo Kiosk component. """Filesystem locations used by every Daynivo Kiosk component.
The defaults match the installed layout. Unprivileged components may 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 suite and for local development). The root helper always uses
:func:`default_paths` and never reads the environment. :func:`default_paths` and never reads the environment.
""" """
@@ -15,15 +15,15 @@ from pathlib import Path
@dataclass(frozen=True) @dataclass(frozen=True)
class Paths: class Paths:
config_dir: Path = Path("/etc/voxip-kiosk") config_dir: Path = Path("/etc/daynivo-kiosk")
state_dir: Path = Path("/var/lib/voxip-kiosk") state_dir: Path = Path("/var/lib/daynivo-kiosk")
network_state_dir: Path = Path("/var/lib/voxip-kiosk-network") network_state_dir: Path = Path("/var/lib/daynivo-kiosk-network")
agent_run_dir: Path = Path("/run/voxip-kiosk-agent") agent_run_dir: Path = Path("/run/daynivo-kiosk-agent")
browser_run_dir: Path = Path("/run/voxip-kiosk-browser") browser_run_dir: Path = Path("/run/daynivo-kiosk-browser")
health_run_dir: Path = Path("/run/voxip-kiosk-health") health_run_dir: Path = Path("/run/daynivo-kiosk-health")
share_dir: Path = Path("/usr/share/voxip-kiosk") share_dir: Path = Path("/usr/share/daynivo-kiosk")
log_dir: Path = Path("/var/log/voxip-kiosk") log_dir: Path = Path("/var/log/daynivo-kiosk")
helper: Path = Path("/usr/lib/voxip-kiosk/voxip-kiosk-helper") helper: Path = Path("/usr/lib/daynivo-kiosk/daynivo-kiosk-helper")
nm_connections_dir: Path = Path("/etc/NetworkManager/system-connections") nm_connections_dir: Path = Path("/etc/NetworkManager/system-connections")
@property @property
@@ -90,15 +90,15 @@ def default_paths() -> Paths:
_ENV = { _ENV = {
"config_dir": "VOXIP_CONFIG_DIR", "config_dir": "DAYNIVO_CONFIG_DIR",
"state_dir": "VOXIP_STATE_DIR", "state_dir": "DAYNIVO_STATE_DIR",
"network_state_dir": "VOXIP_NETWORK_STATE_DIR", "network_state_dir": "DAYNIVO_NETWORK_STATE_DIR",
"agent_run_dir": "VOXIP_AGENT_RUN_DIR", "agent_run_dir": "DAYNIVO_AGENT_RUN_DIR",
"browser_run_dir": "VOXIP_BROWSER_RUN_DIR", "browser_run_dir": "DAYNIVO_BROWSER_RUN_DIR",
"health_run_dir": "VOXIP_HEALTH_RUN_DIR", "health_run_dir": "DAYNIVO_HEALTH_RUN_DIR",
"share_dir": "VOXIP_SHARE_DIR", "share_dir": "DAYNIVO_SHARE_DIR",
"log_dir": "VOXIP_LOG_DIR", "log_dir": "DAYNIVO_LOG_DIR",
"helper": "VOXIP_HELPER", "helper": "DAYNIVO_HELPER",
} }
+6 -6
View File
@@ -5,11 +5,11 @@ from __future__ import annotations
import subprocess import subprocess
from typing import Any from typing import Any
BROWSER_UNIT = "voxip-kiosk-browser.service" BROWSER_UNIT = "daynivo-kiosk-browser.service"
X_UNIT = "voxip-kiosk-x.service" X_UNIT = "daynivo-kiosk-x.service"
AGENT_UNIT = "voxip-kiosk-agent.service" AGENT_UNIT = "daynivo-kiosk-agent.service"
MANAGER_UNIT = "voxip-kiosk-manager.service" MANAGER_UNIT = "daynivo-kiosk-manager.service"
HEALTH_UNIT = "voxip-kiosk-healthcheck.service" HEALTH_UNIT = "daynivo-kiosk-healthcheck.service"
# Units whose logs the web interface may show (label → journalctl -u args). # Units whose logs the web interface may show (label → journalctl -u args).
LOG_SOURCES: dict[str, tuple[str, list[str]]] = { 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]), "agent": ("Kiosk-agent", [AGENT_UNIT]),
"health": ("Healthcheck", [HEALTH_UNIT]), "health": ("Healthcheck", [HEALTH_UNIT]),
"manager": ("Beheerinterface", [MANAGER_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", []), "system": ("Volledig systeem", []),
} }
LOG_LINES = (50, 100, 200, 500) LOG_LINES = (50, 100, 200, 500)
+7 -7
View File
@@ -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: 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 ``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:: It never installs an older or equal version. Usage::
voxip-kiosk-updater --check # only check daynivo-kiosk-updater --check # only check
voxip-kiosk-updater --auto # check; install when auto_update is on (daily timer) daynivo-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 --install # check and install when newer (button in the web interface)
""" """
from __future__ import annotations from __future__ import annotations
@@ -39,12 +39,12 @@ from . import logutil
from .config import atomic_write_json, load_config from .config import atomic_write_json, load_config
from .paths import Paths, default_paths, read_version 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" RELEASE_API = "https://git.rothman.nl/api/v1/repos/rothman/daynivo-kiosk-os/releases/latest"
ASSET_PREFIX = "daynivo-kiosk-os-" ASSET_PREFIX = "daynivo-kiosk-os-"
RELEASE_DIR = Path("/opt/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 KEEP_RELEASES = 2
MAX_DOWNLOAD = 64 * 1024 * 1024 MAX_DOWNLOAD = 64 * 1024 * 1024
USER_AGENT = "Daynivo-Kiosk-OS/updater" USER_AGENT = "Daynivo-Kiosk-OS/updater"
@@ -219,7 +219,7 @@ class Updater:
def main(argv: list[str] | None = None, updater: Updater | None = None) -> int: 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 = parser.add_mutually_exclusive_group(required=True)
mode.add_argument("--check", action="store_true", help="alleen controleren") 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") mode.add_argument("--auto", action="store_true", help="controleren en bijwerken als automatisch bijwerken aan staat")
+2 -2
View File
@@ -48,7 +48,7 @@ def create_app(paths: Paths | None = None, *, helper: Any = None, cdp: Any = Non
app = Flask(__name__) app = Flask(__name__)
app.secret_key = _secret_key(paths) app.secret_key = _secret_key(paths)
app.config.update( app.config.update(
SESSION_COOKIE_NAME="voxip_session", SESSION_COOKIE_NAME="daynivo_session",
SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Strict", SESSION_COOKIE_SAMESITE="Strict",
SESSION_COOKIE_SECURE=config["admin_https"], 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 = CredentialStore(paths.admin_file, paths.setup_code_file)
credentials.ensure_setup_code() credentials.ensure_setup_code()
app.extensions["voxip"] = Services( app.extensions["daynivo"] = Services(
paths=paths, paths=paths,
credentials=credentials, credentials=credentials,
throttle=LoginThrottle(), throttle=LoginThrottle(),
+1 -1
View File
@@ -21,7 +21,7 @@ HASHER = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=2, hash_len=
MIN_LENGTH = 10 MIN_LENGTH = 10
MAX_LENGTH = 128 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: def password_problem(password: str, confirm: str | None = None) -> str | None:
+2 -2
View File
@@ -22,14 +22,14 @@ from . import security
from .auth import password_problem from .auth import password_problem
bp = Blueprint("ui", __name__) bp = Blueprint("ui", __name__)
audit_log = logging.getLogger("voxip-kiosk-audit") audit_log = logging.getLogger("daynivo-kiosk-audit")
IDLE_TIMEOUT = 3600 IDLE_TIMEOUT = 3600
PUBLIC_ENDPOINTS = {"ui.login", "ui.setup", "static"} PUBLIC_ENDPOINTS = {"ui.login", "ui.setup", "static"}
def svc(): def svc():
return current_app.extensions["voxip"] return current_app.extensions["daynivo"]
def cfg() -> dict[str, Any]: def cfg() -> dict[str, Any]:
@@ -1,8 +1,8 @@
[Unit] [Unit]
Description=Daynivo configuratie en SSH-sleutels importeren vanaf de bootpartitie 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 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-config.json
ConditionPathExistsGlob=|/boot/firmware/daynivo-authorized_keys ConditionPathExistsGlob=|/boot/firmware/daynivo-authorized_keys
ConditionPathExistsGlob=|/boot/daynivo-config.json ConditionPathExistsGlob=|/boot/daynivo-config.json
@@ -15,7 +15,7 @@ ConditionPathExistsGlob=|/boot/voxip-authorized_keys
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-helper boot-import ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-helper boot-import
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -1,18 +1,18 @@
[Unit] [Unit]
Description=Daynivo Kiosk agent (navigatie, offlinepagina, verversen) Description=Daynivo Kiosk agent (navigatie, offlinepagina, verversen)
Documentation=file:///usr/share/doc/voxip-kiosk/README.md Documentation=file:///usr/share/doc/daynivo-kiosk/README.md
After=voxip-kiosk-browser.service After=daynivo-kiosk-browser.service
[Service] [Service]
Type=simple Type=simple
User=kiosk User=kiosk
Group=kiosk Group=kiosk
RuntimeDirectory=voxip-kiosk-agent RuntimeDirectory=daynivo-kiosk-agent
RuntimeDirectoryMode=0755 RuntimeDirectoryMode=0755
ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-agent ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-agent
Restart=always Restart=always
RestartSec=5 RestartSec=5
SyslogIdentifier=voxip-kiosk-agent SyslogIdentifier=daynivo-kiosk-agent
NoNewPrivileges=yes NoNewPrivileges=yes
ProtectSystem=strict ProtectSystem=strict
ProtectHome=yes ProtectHome=yes
+36
View File
@@ -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
+11
View File
@@ -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
@@ -1,27 +1,27 @@
[Unit] [Unit]
Description=Daynivo Kiosk Manager (webbeheer) Description=Daynivo Kiosk Manager (webbeheer)
Documentation=file:///usr/share/doc/voxip-kiosk/README.md Documentation=file:///usr/share/doc/daynivo-kiosk/README.md
After=network.target voxip-boot-import.service After=network.target daynivo-boot-import.service
StartLimitIntervalSec=300 StartLimitIntervalSec=300
StartLimitBurst=10 StartLimitBurst=10
[Service] [Service]
Type=simple Type=simple
User=voxip User=daynivo
Group=voxip Group=daynivo
# systemd-journal: read logs; video: vcgencmd (voltage/throttling) # systemd-journal: read logs; video: vcgencmd (voltage/throttling)
SupplementaryGroups=systemd-journal video SupplementaryGroups=systemd-journal video
ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-manager ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-manager
Restart=always Restart=always
RestartSec=3 RestartSec=3
UMask=0027 UMask=0027
LogsDirectory=voxip-kiosk LogsDirectory=daynivo-kiosk
LogsDirectoryMode=0750 LogsDirectoryMode=0750
SyslogIdentifier=voxip-kiosk-manager SyslogIdentifier=daynivo-kiosk-manager
# No NoNewPrivileges/ProtectSystem/ProtectHome: the helper started through # 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 # 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, # Also no ProtectKernelTunables/ProtectKernelModules/LockPersonality,
# RestrictSUIDSGID, SystemCall*, ...: for a non-root unit those imply # RestrictSUIDSGID, SystemCall*, ...: for a non-root unit those imply
# NoNewPrivileges, and sudo then refuses to run (tests/test_units.py). # NoNewPrivileges, and sudo then refuses to run (tests/test_units.py).
@@ -1,11 +1,11 @@
[Unit] [Unit]
Description=Daynivo Kiosk OS: controleren op updates (en installeren als dat aan staat) 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 Wants=network-online.target
After=network-online.target After=network-online.target
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-updater --auto ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-updater --auto
TimeoutStartSec=1h TimeoutStartSec=1h
SyslogIdentifier=voxip-kiosk-updater SyslogIdentifier=daynivo-kiosk-updater
File renamed without changes.
@@ -1,6 +1,6 @@
[Unit] [Unit]
Description=Daynivo Kiosk X-server (vt7) 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 After=systemd-user-sessions.service systemd-logind.service
Conflicts=getty@tty7.service Conflicts=getty@tty7.service
StartLimitIntervalSec=600 StartLimitIntervalSec=600
@@ -20,10 +20,10 @@ StandardOutput=journal
StandardError=journal StandardError=journal
UtmpIdentifier=tty7 UtmpIdentifier=tty7
UtmpMode=user UtmpMode=user
RuntimeDirectory=voxip-kiosk-x RuntimeDirectory=daynivo-kiosk-x
RuntimeDirectoryMode=0700 RuntimeDirectoryMode=0700
ExecStartPre=+/usr/bin/chvt 7 ExecStartPre=+/usr/bin/chvt 7
ExecStart=/usr/lib/voxip-kiosk/voxip-kiosk-x ExecStart=/usr/lib/daynivo-kiosk/daynivo-kiosk-x
Restart=always Restart=always
RestartSec=3 RestartSec=3
@@ -1,6 +1,6 @@
[Unit] [Unit]
Description=Daynivo netwerkherstel bij opstarten (rollback en noodreset) 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 DefaultDependencies=no
After=local-fs.target After=local-fs.target
Before=NetworkManager.service network-pre.target shutdown.target Before=NetworkManager.service network-pre.target shutdown.target
@@ -10,7 +10,7 @@ Conflicts=shutdown.target
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes 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] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
-36
View File
@@ -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
-11
View File
@@ -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
+2 -2
View File
@@ -96,7 +96,7 @@ def quiet_system(monkeypatch):
"available": True, "wifi_country": "NL", "available": True, "wifi_country": "NL",
"devices": { "devices": {
iface: {"interface": iface, "kind": kind, "present": True, "state": "connected", "state_label": "Verbonden", 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", "dns": ["192.168.10.1"], "hwaddr": "B8:27:EB:00:00:01",
"profile": {"exists": True, "method": "dhcp", "address": "", "gateway": "", "dns": "", "ssid": "Kantoor", "hidden": False}} "profile": {"exists": True, "method": "dhcp", "address": "", "gateway": "", "dns": "", "ssid": "Kantoor", "hidden": False}}
for iface, kind in (("eth0", "ethernet"), ("wlan0", "wifi")) for iface, kind in (("eth0", "ethernet"), ("wlan0", "wifi"))
@@ -130,7 +130,7 @@ PASSWORD = "Correct-Paard-Batterij-42"
@pytest.fixture @pytest.fixture
def logged_in(app, client, paths): def logged_in(app, client, paths):
"""A client with a configured admin password and an active session.""" """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") page = client.get("/login")
token = csrf_from(page) token = csrf_from(page)
resp = client.post("/login", data={"password": PASSWORD, "csrf_token": token}) resp = client.post("/login", data={"password": PASSWORD, "csrf_token": token})
+18 -18
View File
@@ -35,7 +35,7 @@ def helper(paths, tmp_path, boot):
etc.mkdir() etc.mkdir()
(etc / "hosts").write_text("127.0.0.1\tlocalhost\n127.0.1.1\tkiosk\n") (etc / "hosts").write_text("127.0.0.1\tlocalhost\n127.0.1.1\tkiosk\n")
run = Recorder({"nmcli -t -f": "aaaa-1111\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): 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): 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 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 code == 1
assert helper.run.commands == [] assert helper.run.commands == []
def test_public_verb_via_sudo(helper, capsys): 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 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): 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): 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") (paths.nm_connections_dir / "Wired connection 1.nmconnection").write_text("[connection]\nid=Wired connection 1\n")
result = helper.network_apply(ETH_STATIC) 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 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 "address1=192.168.5.10/24,192.168.5.1" in keyfile.read_text()
assert (paths.network_backup_dir / "Wired connection 1.nmconnection").exists() 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 pending["deadline"] - pending["created"] == 180
assert result["pending"]["interface"] == "eth0" assert result["pending"]["interface"] == "eth0"
runs = [c for c in helper.run.commands if c[0] == "systemd-run"] 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[0][1:3] == ["--unit=daynivo-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[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): def test_second_apply_refused_while_pending(helper):
@@ -123,8 +123,8 @@ def test_confirm_clears_pending(helper, paths):
helper.network_confirm() helper.network_confirm()
assert not paths.network_pending_file.exists() assert not paths.network_pending_file.exists()
assert not paths.network_backup_dir.exists() assert not paths.network_backup_dir.exists()
assert (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists() assert (paths.nm_connections_dir / "daynivo-eth0.nmconnection").exists()
assert helper.run.ran("systemctl", "stop", "voxip-network-rollback.timer") assert helper.run.ran("systemctl", "stop", "daynivo-network-rollback.timer")
def test_restore_puts_old_profiles_back(helper, paths): def test_restore_puts_old_profiles_back(helper, paths):
@@ -134,7 +134,7 @@ def test_restore_puts_old_profiles_back(helper, paths):
old.unlink() old.unlink()
helper.network_restore() helper.network_restore()
assert old.exists() 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 not paths.network_pending_file.exists()
assert helper.run.ran("nmcli", "--wait", "30", "connection", "up", "uuid", "aaaa-1111") 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_confirm()
helper.network_apply({"interface": "wlan0", "method": "static", "address": "10.0.0.9/24", "gateway": "10.0.0.1", "dns": "10.0.0.1", 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": ""}}) "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() helper.network_confirm()
with pytest.raises(h.HelperError, match="wachtwoord"): with pytest.raises(h.HelperError, match="wachtwoord"):
helper.network_apply({"interface": "wlan0", "method": "dhcp", "wifi": {"ssid": "Ander", "psk": ""}}) 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() helper.run.commands.clear()
result = helper.network_boot_guard() result = helper.network_boot_guard()
assert result == {"rolled_back": True} 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" 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("") (boot / "daynivo-network-reset").write_text("")
assert helper.network_boot_guard() == {"reset": True} 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 not (boot / "daynivo-network-reset").exists()
assert old.exists() assert old.exists()
def test_boot_guard_still_honours_the_old_reset_name(helper, paths, boot): 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("") (boot / "voxip-network-reset").write_text("")
assert helper.network_boot_guard() == {"reset": True} 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() 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 test_update_install_reports_a_running_update(helper):
def busy(args, timeout=30, check=True, input=None): 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 helper.run = busy
with pytest.raises(h.HelperError, match="al een update"): with pytest.raises(h.HelperError, match="al een update"):
+1 -1
View File
@@ -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"]}) 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") text = n.build_keyfile(req, uuid="11111111-2222-3333-4444-555555555555")
kf = n.read_keyfile(text) 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", "type") == "ethernet"
assert kf.get("connection", "autoconnect-priority") == "100" assert kf.get("connection", "autoconnect-priority") == "100"
assert kf.get("ipv4", "method") == "manual" assert kf.get("ipv4", "method") == "manual"
+2 -2
View File
@@ -22,8 +22,8 @@ def settings(unit):
def test_manager_can_use_sudo_for_the_helper(): def test_manager_can_use_sudo_for_the_helper():
unit = settings("voxip-kiosk-manager.service") unit = settings("daynivo-kiosk-manager.service")
assert unit["User"] == "voxip" assert unit["User"] == "daynivo"
for key in IMPLY_NO_NEW_PRIVILEGES: for key in IMPLY_NO_NEW_PRIVILEGES:
assert unit.get(key, "no") in ("no", "false", ""), key assert unit.get(key, "no") in ("no", "false", ""), key
for key in ("ProtectSystem", "ProtectHome", "PrivateTmp"): for key in ("ProtectSystem", "ProtectHome", "PrivateTmp"):
+4 -4
View File
@@ -52,7 +52,7 @@ def test_setup_without_csrf_is_rejected(client, paths):
# --- login & session ------------------------------------------------------------- # --- login & session -------------------------------------------------------------
def test_login_logout(app, client): 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 assert client.get("/").status_code == 302
tok = csrf_from(client.get("/login")) tok = csrf_from(client.get("/login"))
assert "Onjuist" in client.post("/login", data={"csrf_token": tok, "password": "fout-wachtwoord"}).get_data(as_text=True) 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): 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")) tok = csrf_from(client.get("/login"))
resp = client.post("/login", data={"csrf_token": tok, "password": PASSWORD}) resp = client.post("/login", data={"csrf_token": tok, "password": PASSWORD})
cookie = resp.headers["Set-Cookie"] cookie = resp.headers["Set-Cookie"]
@@ -71,7 +71,7 @@ def test_session_cookie_flags(app, client):
def test_login_throttling(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")) tok = csrf_from(client.get("/login"))
for _ in range(5): for _ in range(5):
client.post("/login", data={"csrf_token": tok, "password": "verkeerd-wachtwoord"}) 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): 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") resp = client.get("/api/status")
assert resp.status_code == 401 and resp.json["error"] assert resp.status_code == 401 and resp.json["error"]
+31 -26
View File
@@ -15,16 +15,16 @@ PURGE=0
[[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { sed -n '3,10p' "$0" | sed 's/^# \{0,1\}//'; exit 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; } [[ $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 UNITS=(daynivo-kiosk-healthcheck.timer daynivo-kiosk-healthcheck.service daynivo-kiosk-agent.service
voxip-kiosk-browser.service voxip-kiosk-x.service voxip-kiosk-manager.service daynivo-kiosk-browser.service daynivo-kiosk-x.service daynivo-kiosk-manager.service
voxip-network-guard.service voxip-boot-import.service voxip-kiosk-update.timer voxip-kiosk-update.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_TARGET="$(cat /var/lib/daynivo-kiosk/previous-default-target 2>/dev/null || true)"
PREVIOUS_SPLASH="$(cat /var/lib/voxip-kiosk/previous-plymouth-theme 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/voxip-kiosk/disabled-display-managers 2>/dev/null) mapfile -t DISABLED_DMS < <(cat /var/lib/daynivo-kiosk/disabled-display-managers 2>/dev/null)
echo "==> Services stoppen en verwijderen" 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 for unit in "${UNITS[@]}"; do
systemctl disable --now "$unit" 2>/dev/null || true systemctl disable --now "$unit" 2>/dev/null || true
rm -f "/etc/systemd/system/$unit" rm -f "/etc/systemd/system/$unit"
@@ -32,42 +32,47 @@ done
systemctl daemon-reload systemctl daemon-reload
echo "==> Bestanden verwijderen" 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 /usr/local/sbin/daynivo-kiosk-ctl /usr/local/sbin/voxip-kiosk-ctl
rm -f /etc/sudoers.d/voxip-kiosk # Symlinks left by the move from the VoxIP names
rm -f /etc/systemd/journald.conf.d/voxip-kiosk.conf /etc/systemd/system.conf.d/voxip-watchdog.conf for link in /etc/voxip-kiosk /var/lib/voxip-kiosk /var/lib/voxip-kiosk-network /var/lib/voxip-kiosk-browser \
rm -f /etc/logrotate.d/voxip-kiosk /etc/avahi/services/voxip-kiosk.service /var/log/voxip-kiosk /var/cache/voxip-kiosk; do
rm -f /etc/chromium/policies/managed/voxip-kiosk.json /etc/chromium-browser/policies/managed/voxip-kiosk.json 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/systemd/zram-generator.conf
rm -f /etc/ssh/sshd_config.d/voxip-kiosk.conf rm -f /etc/ssh/sshd_config.d/daynivo-kiosk.conf
if [[ -f /etc/X11/Xwrapper.config.voxip-orig ]]; then if [[ -f /etc/X11/Xwrapper.config.daynivo-orig ]]; then
mv /etc/X11/Xwrapper.config.voxip-orig /etc/X11/Xwrapper.config mv /etc/X11/Xwrapper.config.daynivo-orig /etc/X11/Xwrapper.config
else else
rm -f /etc/X11/Xwrapper.config rm -f /etc/X11/Xwrapper.config
fi 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})" 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 plymouth-set-default-theme -R "${PREVIOUS_SPLASH:-text}" >/dev/null 2>&1 || true
fi fi
if [[ -f /etc/systemd/system/display-kiosk.service.voxip-disabled ]]; then if [[ -f /etc/systemd/system/display-kiosk.service.daynivo-disabled ]]; then
echo " (de eerdere Daynivo-kioskservice staat nog als display-kiosk.service.voxip-disabled)" echo " (de eerdere Daynivo-kioskservice staat nog als display-kiosk.service.daynivo-disabled)"
fi fi
if [[ $PURGE -eq 1 ]]; then if [[ $PURGE -eq 1 ]]; then
echo "==> Configuratie, status, logs en gebruikers verwijderen" 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. # 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 -rf /opt/daynivo-kiosk-os /var/cache/daynivo-kiosk
rm -f /etc/NetworkManager/system-connections/voxip-eth0.nmconnection /etc/NetworkManager/system-connections/voxip-wlan0.nmconnection rm -f /etc/NetworkManager/system-connections/daynivo-eth0.nmconnection /etc/NetworkManager/system-connections/daynivo-wlan0.nmconnection
nmcli connection reload 2>/dev/null || true nmcli connection reload 2>/dev/null || true
userdel -r kiosk 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 kiosk 2>/dev/null || true
groupdel voxip 2>/dev/null || true groupdel daynivo 2>/dev/null || true
else else
echo " Configuratie bewaard in /etc/voxip-kiosk (verwijderen met --purge)." echo " Configuratie bewaard in /etc/daynivo-kiosk (verwijderen met --purge)."
echo " Daynivo-netwerkprofielen (voxip-eth0/voxip-wlan0) blijven actief." echo " Daynivo-netwerkprofielen (daynivo-eth0/daynivo-wlan0) blijven actief."
fi fi
if [[ -n $PREVIOUS_TARGET ]]; then systemctl set-default "$PREVIOUS_TARGET" >/dev/null 2>&1 || true; fi if [[ -n $PREVIOUS_TARGET ]]; then systemctl set-default "$PREVIOUS_TARGET" >/dev/null 2>&1 || true; fi
+10 -7
View File
@@ -5,7 +5,7 @@
# sudo ./update.sh # git pull --ff-only, back up config, install --upgrade # 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 # 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 set -euo pipefail
@@ -15,7 +15,7 @@ PULL=1
[[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { sed -n '3,9p' "$0" | sed 's/^# \{0,1\}//'; exit 0; } [[ ${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; } [[ $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 if [[ $PULL -eq 1 && -d "$SRC/.git" ]]; then
echo "==> Laatste versie ophalen" 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 sudo -u "$OWNER" git -C "$SRC" pull --ff-only
fi fi
if [[ -d /etc/voxip-kiosk ]]; then # Before the rename to Daynivo (up to 1.2.x) the configuration lived in /etc/voxip-kiosk.
BACKUP="/var/backups/voxip-kiosk-$(date +%Y%m%d-%H%M%S).tar.gz" 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" echo "==> Configuratie back-uppen naar $BACKUP"
install -d -m 0700 /var/backups install -d -m 0700 /var/backups
tar -C /etc -czf "$BACKUP" voxip-kiosk tar -C /etc -czf "$BACKUP" "$CONF_DIR"
chmod 0600 "$BACKUP" chmod 0600 "$BACKUP"
# keep the five most recent backups # 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 fi
"$SRC/install.sh" --upgrade "$SRC/install.sh" --upgrade
echo "==> Bijgewerkt: $BEFORE → $(cat /usr/share/voxip-kiosk/VERSION)" echo "==> Bijgewerkt: $BEFORE → $(cat /usr/share/daynivo-kiosk/VERSION)"