Daynivo names for the files on the SD card and the command line tool
- daynivo-config.json, daynivo-authorized_keys and daynivo-network-reset on the boot partition; errors go to daynivo-config.error.txt. - daynivo-kiosk-ctl, with voxip-kiosk-ctl as a symlink to it. - The voxip-* names keep working, so existing SD cards and instructions stay valid; when both config files are present the Daynivo one is applied last. - Internal names (services, /etc/voxip-kiosk, user voxip) are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
348644a48a
commit
b0840d240e
17 files changed
+108
-76
No files matched your search
@@ -31,7 +31,7 @@ hardware staat in [`docs/HARDWARE-TEST.md`](docs/HARDWARE-TEST.md).
|
||||
3. Optioneel, in Raspberry Pi Imager → *OS-aanpassingen*: wifi, gebruiker
|
||||
met wachtwoord en/of SSH-sleutel, tijdzone. Zonder aanpassingen heeft de
|
||||
image **geen** bruikbaar wachtwoord en staat SSH uit.
|
||||
4. Optioneel: zet een `voxip-config.json` op de bootpartitie (zie
|
||||
4. Optioneel: zet een `daynivo-config.json` op de bootpartitie (zie
|
||||
[Uitrol bij meerdere klanten](#uitrol-bij-meerdere-klanten)).
|
||||
5. Start de Pi. Bij de eerste boot wordt de rootpartitie automatisch
|
||||
vergroot tot de hele SD-kaart. Daarna verschijnt een setupscherm met de
|
||||
@@ -191,14 +191,14 @@ browser blijft draaien. *Chromium herstarten* herstart alleen de browser.
|
||||
### Commandoregel (via SSH)
|
||||
|
||||
```bash
|
||||
sudo voxip-kiosk-ctl status # overzicht
|
||||
sudo voxip-kiosk-ctl setup-code # setupcode voor de eerste configuratie
|
||||
sudo voxip-kiosk-ctl reset-password # wachtwoord vergeten: nieuwe setupcode
|
||||
sudo voxip-kiosk-ctl set-url https://… # URL wijzigen
|
||||
sudo voxip-kiosk-ctl reload # pagina herladen
|
||||
sudo voxip-kiosk-ctl restart-browser # Chromium herstarten
|
||||
sudo voxip-kiosk-ctl health # healthcheck-rapport
|
||||
sudo voxip-kiosk-ctl maintenance on|off # healthcheck tijdelijk niets laten herstellen
|
||||
sudo daynivo-kiosk-ctl status # overzicht
|
||||
sudo daynivo-kiosk-ctl setup-code # setupcode voor de eerste configuratie
|
||||
sudo daynivo-kiosk-ctl reset-password # wachtwoord vergeten: nieuwe setupcode
|
||||
sudo daynivo-kiosk-ctl set-url https://… # URL wijzigen
|
||||
sudo daynivo-kiosk-ctl reload # pagina herladen
|
||||
sudo daynivo-kiosk-ctl restart-browser # Chromium herstarten
|
||||
sudo daynivo-kiosk-ctl health # healthcheck-rapport
|
||||
sudo daynivo-kiosk-ctl maintenance on|off # healthcheck tijdelijk niets laten herstellen
|
||||
journalctl -u voxip-kiosk-browser -u voxip-kiosk-agent -f
|
||||
```
|
||||
|
||||
@@ -221,7 +221,7 @@ journalctl -u voxip-kiosk-browser -u voxip-kiosk-agent -f
|
||||
| `admin_allow_public` | `false` | ook toegang vanaf publieke IP-adressen (afgeraden) |
|
||||
| `auto_update` | `false` | elke nacht een nieuwe release installeren |
|
||||
|
||||
Wijzigingen via de webinterface of `voxip-kiosk-ctl` worden atomair
|
||||
Wijzigingen via de webinterface of `daynivo-kiosk-ctl` worden atomair
|
||||
opgeslagen, met een `.bak` van de vorige versie. Een URL-wijziging gaat in
|
||||
zonder dat Chromium herstart. Scherminstellingen gelden na een herstart van
|
||||
Chromium (een vinkje in de webinterface doet dat direct).
|
||||
@@ -231,15 +231,15 @@ Chromium (een vinkje in de webinterface doet dat direct).
|
||||
Eén image voor alle klanten. Per apparaat zet je na het flashen op de
|
||||
bootpartitie (`bootfs`, zichtbaar op Windows en macOS):
|
||||
|
||||
- **`voxip-config.json`**: instellingen voor deze kiosk, plus optioneel
|
||||
- **`daynivo-config.json`**: instellingen voor deze kiosk, plus optioneel
|
||||
`hostname` en `wifi_country`. Een voorbeeld staat als
|
||||
`voxip-config.example.json` op de bootpartitie.
|
||||
- **`voxip-authorized_keys`**: openbare SSH-sleutels. SSH gaat dan aan, alleen
|
||||
`daynivo-config.example.json` op de bootpartitie.
|
||||
- **`daynivo-authorized_keys`**: openbare SSH-sleutels. SSH gaat dan aan, alleen
|
||||
met sleutel-login.
|
||||
- Wifi en een eigen gebruiker stel je in via Raspberry Pi Imager.
|
||||
|
||||
De bestanden worden bij het opstarten verwerkt en hernoemd naar
|
||||
`*.applied`, of naar `*.rejected` met de reden in `voxip-config.error.txt`.
|
||||
`*.applied`, of naar `*.rejected` met de reden in `daynivo-config.error.txt`.
|
||||
|
||||
### Daynivo-schermen
|
||||
|
||||
@@ -270,8 +270,8 @@ make dev # http://127.0.0.1:8080 met tijdelijke mappen in .dev/
|
||||
|
||||
| Symptoom | Oplossing |
|
||||
|---|---|
|
||||
| Zwart scherm na opstarten | `sudo voxip-kiosk-ctl status`. Kijk in de journal van `voxip-kiosk-x`/`voxip-kiosk-browser`. Staat de monitor aan vóór de Pi? |
|
||||
| Beheerinterface onbereikbaar na netwerkwijziging | Wacht 3 minuten (automatische rollback) of zet `voxip-network-reset` op de bootpartitie en herstart. |
|
||||
| Wachtwoord vergeten | `sudo voxip-kiosk-ctl reset-password` via SSH, of verwijder `/etc/voxip-kiosk/admin.json` met de SD-kaart in een Linux-pc. |
|
||||
| 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? |
|
||||
| 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. |
|
||||
| `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. |
|
||||
File renamed without changes.
@@ -12,7 +12,7 @@ samenwerken en waarom bepaalde keuzes zijn gemaakt.
|
||||
- Lokale webbeheerinterface (*Daynivo Kiosk Manager*) op poort 8080.
|
||||
- Geen klantspecifieke code: alles wat per klant verschilt staat in
|
||||
`/etc/voxip-kiosk/config.json` en kan bij uitrol via de bootpartitie
|
||||
worden meegegeven (`voxip-config.json`).
|
||||
worden meegegeven (`daynivo-config.json`).
|
||||
|
||||
## Overzicht
|
||||
|
||||
@@ -104,7 +104,7 @@ Zolang er geen beheerderswachtwoord is:
|
||||
adressen van de beheerinterface;
|
||||
3. kan een wachtwoord alleen ingesteld worden met die code.
|
||||
|
||||
Wie fysiek bij het scherm staat (of via SSH `voxip-kiosk-ctl setup-code`
|
||||
Wie fysiek bij het scherm staat (of via SSH `daynivo-kiosk-ctl setup-code`
|
||||
draait) kan het apparaat dus claimen, iemand anders op het netwerk niet.
|
||||
|
||||
### Netwerkwijzigingen met rollback
|
||||
@@ -119,7 +119,7 @@ draait) kan het apparaat dus claimen, iemand anders op het netwerk niet.
|
||||
5. Valt de stroom uit tijdens die periode, dan zet
|
||||
`voxip-network-guard.service` de snapshot terug bij het opstarten, nog
|
||||
vóór NetworkManager start.
|
||||
6. Noodherstel: een leeg bestand `voxip-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
|
||||
DHCP).
|
||||
|
||||
@@ -165,7 +165,7 @@ draait) kan het apparaat dus claimen, iemand anders op het netwerk niet.
|
||||
(toegestaan: privé, link-local, loopback, CGNAT/VPN 100.64.0.0/10).
|
||||
- Optioneel HTTPS (zelfondertekend certificaat, automatisch aangemaakt).
|
||||
- SSH staat in de image standaard uit en wordt alleen ingeschakeld met
|
||||
credentials uit Raspberry Pi Imager of `voxip-authorized_keys` op de
|
||||
credentials uit Raspberry Pi Imager of `daynivo-authorized_keys` op de
|
||||
bootpartitie (dan alleen sleutel-login).
|
||||
- Strikte security-headers en CSP (`default-src 'self'`).
|
||||
|
||||
@@ -192,7 +192,7 @@ daynivo-kiosk-os/
|
||||
│ ├── netinfo.py netwerkstatus (zonder rechten)
|
||||
│ ├── sysinfo.py CPU, temperatuur, geheugen, opslag, IP
|
||||
│ ├── services.py systemd- en journal-status
|
||||
│ ├── ctl.py CLI voor SSH-beheer (voxip-kiosk-ctl)
|
||||
│ ├── ctl.py CLI voor SSH-beheer (daynivo-kiosk-ctl)
|
||||
│ └── web/ Flask-app, templates, statische bestanden
|
||||
├── www/ lokale kioskpagina's (start, offline, setup)
|
||||
├── systemd/ unit-bestanden
|
||||
|
||||
@@ -47,14 +47,14 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
|
||||
(zie Logboek → Kiosk-agent).
|
||||
- [ ] Screenshot op de Kiosk-pagina toont wat er op het scherm staat.
|
||||
- [ ] Daynivo-URL met `?token=`: het token is overal gemaskeerd
|
||||
(dashboard, `voxip-kiosk-ctl status`, `journalctl -u voxip-kiosk-agent`).
|
||||
(dashboard, `daynivo-kiosk-ctl status`, `journalctl -u voxip-kiosk-agent`).
|
||||
|
||||
## 4. Herstel
|
||||
|
||||
- [ ] `sudo pkill -9 chromium`: binnen 15 s is de pagina terug. Het logboek
|
||||
toont de herstart.
|
||||
- [ ] `sudo pkill -9 Xorg`: X en Chromium komen binnen 20 s terug.
|
||||
- [ ] Crashloop: `sudo voxip-kiosk-ctl set-url https://localhost:1/` en
|
||||
- [ ] Crashloop: `sudo daynivo-kiosk-ctl set-url https://localhost:1/` en
|
||||
daarna 7× `sudo pkill -9 chromium` binnen 2 minuten. De service komt
|
||||
in de fouttoestand (start-limit). De healthcheck logt een fout en start
|
||||
hem na ongeveer 5 minuten opnieuw. Er is geen eindeloze stille lus.
|
||||
@@ -82,7 +82,7 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
|
||||
- [ ] **Rollback na stroomuitval:** herhaal, trek binnen 3 minuten de stroom
|
||||
eruit. Na het opstarten zijn de oude instellingen actief.
|
||||
- [ ] **Noodreset:** stel iets onbereikbaars in en bevestig het. Zet
|
||||
`voxip-network-reset` op de bootpartitie en start: weer DHCP.
|
||||
`daynivo-network-reset` op de bootpartitie en start: weer DHCP.
|
||||
|
||||
## 6. Systeem
|
||||
|
||||
@@ -104,7 +104,7 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
|
||||
zonder ingrijpen terug in de kiosk, zonder "herstellen"-melding.
|
||||
- [ ] 72 uur continu draaien met verversinterval 5 min. Daarna: geheugen
|
||||
< 80% (dashboard), geen onderspanning, `journalctl -p err -b` zonder
|
||||
terugkerende fouten, `voxip-kiosk-ctl status` alles *Actief*.
|
||||
terugkerende fouten, `daynivo-kiosk-ctl status` alles *Actief*.
|
||||
- [ ] SD-kaartschrijfacties: `cat /proc/diskstats | grep mmcblk0` op t=0 en
|
||||
na 1 uur stationair. Het verschil in geschreven sectoren (kolom 10) is
|
||||
minder dan 50 MB per uur.
|
||||
@@ -112,11 +112,11 @@ Noteer per stap: ✅ / ❌ + opmerking, de imageversie en het schermtype.
|
||||
|
||||
## 8. Uitrol en updates
|
||||
|
||||
- [ ] Nieuwe kaart met `voxip-config.json` (url, device_name, hostname,
|
||||
rotation) en `voxip-authorized_keys` op de bootpartitie: bij de eerste
|
||||
- [ ] Nieuwe kaart met `daynivo-config.json` (url, device_name, hostname,
|
||||
rotation) en `daynivo-authorized_keys` op de bootpartitie: bij de eerste
|
||||
boot toegepast, hernoemd naar `.applied`, SSH alleen met sleutel.
|
||||
- [ ] Ongeldige `voxip-config.json` (http-URL): `.rejected` en
|
||||
`voxip-config.error.txt` met de reden. De kiosk start met de standaardconfiguratie.
|
||||
- [ ] Ongeldige `daynivo-config.json` (http-URL): `.rejected` en
|
||||
`daynivo-config.error.txt` met de reden. De kiosk start met de standaardconfiguratie.
|
||||
- [ ] `sudo ./update.sh` vanuit een nieuwere checkout: versie in het dashboard
|
||||
verhoogd, configuratie en wachtwoord ongewijzigd, back-up in `/var/backups`.
|
||||
- [ ] Systeem → Software-updates → *Nu controleren* met een nieuwere release
|
||||
|
||||
@@ -4,10 +4,10 @@ Daynivo Kiosk OS — bestanden op deze bootpartitie
|
||||
Je kunt een kiosk vooraf instellen door vóór de eerste start bestanden op
|
||||
deze partitie te zetten (bijvoorbeeld direct na het flashen). Ze worden bij
|
||||
het opstarten verwerkt en daarna hernoemd naar *.applied (of *.rejected bij
|
||||
een fout; de reden staat dan in voxip-config.error.txt).
|
||||
een fout; de reden staat dan in daynivo-config.error.txt).
|
||||
|
||||
voxip-config.json
|
||||
Instellingen voor deze kiosk. Zie voxip-config.example.json. Toegestaan:
|
||||
daynivo-config.json
|
||||
Instellingen voor deze kiosk. Zie daynivo-config.example.json. Toegestaan:
|
||||
alle sleutels uit /etc/voxip-kiosk/config.json plus "hostname" en
|
||||
"wifi_country". Voorbeeld:
|
||||
|
||||
@@ -18,12 +18,12 @@ voxip-config.json
|
||||
"rotation": 90
|
||||
}
|
||||
|
||||
voxip-authorized_keys
|
||||
daynivo-authorized_keys
|
||||
Openbare SSH-sleutels (één per regel). SSH wordt dan ingeschakeld, alleen
|
||||
met sleutel-login, voor de beheerder (voxipadmin of de gebruiker die je
|
||||
in Raspberry Pi Imager hebt aangemaakt).
|
||||
|
||||
voxip-network-reset
|
||||
daynivo-network-reset
|
||||
Leeg bestand. Verwijdert bij de volgende start alle via de
|
||||
beheerinterface ingestelde netwerkprofielen (terug naar DHCP). Gebruik
|
||||
dit als de kiosk na een netwerkwijziging onbereikbaar is.
|
||||
|
||||
File renamed without changes.
@@ -20,4 +20,4 @@ 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/voxip-config.example.json "${ROOTFS_DIR}/boot/firmware/voxip-config.example.json"
|
||||
install -m 0644 files/voxip-kiosk/image/daynivo-config.example.json "${ROOTFS_DIR}/boot/firmware/daynivo-config.example.json"
|
||||
+4
-2
@@ -138,7 +138,9 @@ 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
|
||||
install -m 0755 -o root -g root "$SRC/bin/$bin" "$LIB/$bin"
|
||||
done
|
||||
install -m 0755 -o root -g root "$SRC/bin/voxip-kiosk-ctl" /usr/local/sbin/voxip-kiosk-ctl
|
||||
install -m 0755 -o root -g root "$SRC/bin/daynivo-kiosk-ctl" /usr/local/sbin/daynivo-kiosk-ctl
|
||||
# The name from before the rename to Daynivo keeps working.
|
||||
ln -sfn daynivo-kiosk-ctl /usr/local/sbin/voxip-kiosk-ctl
|
||||
|
||||
rm -rf "$SHARE/www"
|
||||
install -d -m 0755 "$SHARE/www"
|
||||
@@ -340,4 +342,4 @@ if [[ ! -f $ETC/admin.json ]]; then
|
||||
echo " Setupcode: $(cat "$ETC/setup-code") (staat ook op het scherm)"
|
||||
fi
|
||||
fi
|
||||
echo " Status: sudo voxip-kiosk-ctl status"
|
||||
echo " Status: sudo daynivo-kiosk-ctl status"
|
||||
@@ -1,4 +1,4 @@
|
||||
"""voxip-kiosk-ctl — command-line management over SSH (run with sudo)."""
|
||||
"""daynivo-kiosk-ctl — command-line management over SSH (run with sudo)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -33,7 +33,7 @@ def cmd_status(args) -> int:
|
||||
print(f"Apparaat: {config['device_name']}")
|
||||
print(f"URL: {config['url'] if args.show_secrets else mask_url(config['url'])}")
|
||||
print(f"Beheer: {'https' if config['admin_https'] else 'http'}://{os.uname().nodename}.local:{config['admin_port']}")
|
||||
print(f"Wachtwoord: {'ingesteld' if paths.admin_file.exists() else 'NOG NIET INGESTELD (setupcode: sudo voxip-kiosk-ctl setup-code)'}")
|
||||
print(f"Wachtwoord: {'ingesteld' if paths.admin_file.exists() else 'NOG NIET INGESTELD (setupcode: sudo daynivo-kiosk-ctl setup-code)'}")
|
||||
for key, info in services.summary().items():
|
||||
print(f"{info['unit']:<34} {info['label']} (herstarts: {info['restarts']})")
|
||||
if agent:
|
||||
@@ -138,7 +138,7 @@ def cmd_version(_args) -> int:
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(prog="voxip-kiosk-ctl", description="Beheer van Daynivo Kiosk OS vanaf de commandoregel.")
|
||||
parser = argparse.ArgumentParser(prog="daynivo-kiosk-ctl", description="Beheer van Daynivo Kiosk OS vanaf de commandoregel.")
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
p = sub.add_parser("status", help="toon de status")
|
||||
p.add_argument("--show-secrets", action="store_true", help="toon de volledige URL inclusief token")
|
||||
|
||||
+28
-21
@@ -33,9 +33,11 @@ UPDATE_UNIT = "voxip-kiosk-update-now"
|
||||
UPDATER_PATH = "/usr/lib/voxip-kiosk/voxip-kiosk-updater"
|
||||
ACTIVATE_UNIT = "voxip-network-activate"
|
||||
BOOT_DIRS = (Path("/boot/firmware"), Path("/boot"))
|
||||
RESET_TRIGGER = "voxip-network-reset"
|
||||
IMPORT_CONFIG = "voxip-config.json"
|
||||
IMPORT_KEYS = "voxip-authorized_keys"
|
||||
# Files on the boot partition. The voxip-* names are from before the rename to
|
||||
# Daynivo and keep working, so existing SD cards and instructions stay valid.
|
||||
RESET_TRIGGERS = ("daynivo-network-reset", "voxip-network-reset")
|
||||
IMPORT_CONFIGS = ("voxip-config.json", "daynivo-config.json") # applied in this order: the Daynivo name wins
|
||||
IMPORT_KEYS = ("voxip-authorized_keys", "daynivo-authorized_keys")
|
||||
SSH_KEY_TYPES = ("ssh-ed25519", "ssh-rsa", "ecdsa-sha2-", "sk-ssh-ed25519@openssh.com", "sk-ecdsa-sha2-")
|
||||
|
||||
# Verbs the web interface may call through sudo. Everything else is only
|
||||
@@ -306,15 +308,16 @@ class Helper:
|
||||
self.network_restore(boot=True)
|
||||
result["rolled_back"] = True
|
||||
boot = self._boot_dir()
|
||||
trigger = boot / RESET_TRIGGER if boot else None
|
||||
if trigger and trigger.exists():
|
||||
triggers = [boot / name for name in RESET_TRIGGERS if (boot / name).exists()] if boot else []
|
||||
if triggers:
|
||||
stash = self.paths.network_state_dir / f"disabled-{int(time.time())}"
|
||||
stash.mkdir(parents=True, mode=0o700)
|
||||
for iface in netconfig.INTERFACES:
|
||||
src = self._keyfile_path(iface)
|
||||
if src.exists():
|
||||
shutil.move(str(src), str(stash / src.name))
|
||||
trigger.unlink()
|
||||
for trigger in triggers:
|
||||
trigger.unlink()
|
||||
log(syslog.LOG_WARNING, f"Netwerk-reset uitgevoerd; Daynivo-profielen verplaatst naar {stash}")
|
||||
result["reset"] = True
|
||||
return result
|
||||
@@ -335,12 +338,14 @@ class Helper:
|
||||
if boot is None:
|
||||
return {"imported": []}
|
||||
imported = []
|
||||
conf = boot / IMPORT_CONFIG
|
||||
if conf.exists():
|
||||
for name in IMPORT_CONFIGS:
|
||||
conf = boot / name
|
||||
if not conf.exists():
|
||||
continue
|
||||
try:
|
||||
data = json.loads(conf.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(data, dict):
|
||||
raise HelperError("voxip-config.json moet een JSON-object zijn")
|
||||
raise HelperError(f"{name} moet een JSON-object zijn")
|
||||
data = dict(data)
|
||||
host = data.pop("hostname", None)
|
||||
country = data.pop("wifi_country", None)
|
||||
@@ -351,22 +356,24 @@ class Helper:
|
||||
self.set_hostname(str(host))
|
||||
if country:
|
||||
self.set_wifi_country(str(country))
|
||||
conf.rename(conf.with_name(IMPORT_CONFIG + ".applied"))
|
||||
imported.append(IMPORT_CONFIG)
|
||||
log(syslog.LOG_NOTICE, "Configuratie geïmporteerd vanaf de bootpartitie")
|
||||
conf.rename(conf.with_name(name + ".applied"))
|
||||
imported.append(name)
|
||||
log(syslog.LOG_NOTICE, f"Configuratie geïmporteerd vanaf de bootpartitie ({name})")
|
||||
except (HelperError, cfg.ConfigError, v.ValidationError, ValueError, OSError) as exc:
|
||||
(boot / "voxip-config.error.txt").write_text(f"{exc}\n", encoding="utf-8")
|
||||
conf.rename(conf.with_name(IMPORT_CONFIG + ".rejected"))
|
||||
log(syslog.LOG_ERR, f"voxip-config.json geweigerd: {exc}")
|
||||
keys = boot / IMPORT_KEYS
|
||||
if keys.exists():
|
||||
(boot / name.replace(".json", ".error.txt")).write_text(f"{exc}\n", encoding="utf-8")
|
||||
conf.rename(conf.with_name(name + ".rejected"))
|
||||
log(syslog.LOG_ERR, f"{name} geweigerd: {exc}")
|
||||
for name in IMPORT_KEYS:
|
||||
keys = boot / name
|
||||
if not keys.exists():
|
||||
continue
|
||||
try:
|
||||
self._import_ssh_keys(keys.read_text(encoding="utf-8-sig"))
|
||||
keys.rename(keys.with_name(IMPORT_KEYS + ".applied"))
|
||||
imported.append(IMPORT_KEYS)
|
||||
keys.rename(keys.with_name(name + ".applied"))
|
||||
imported.append(name)
|
||||
except (HelperError, OSError) as exc:
|
||||
keys.rename(keys.with_name(IMPORT_KEYS + ".rejected"))
|
||||
log(syslog.LOG_ERR, f"SSH-sleutels geweigerd: {exc}")
|
||||
keys.rename(keys.with_name(name + ".rejected"))
|
||||
log(syslog.LOG_ERR, f"SSH-sleutels geweigerd ({name}): {exc}")
|
||||
return {"imported": imported}
|
||||
|
||||
def _import_ssh_keys(self, text: str) -> None:
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary btn-block">Inloggen</button>
|
||||
</form>
|
||||
<p class="muted small">Wachtwoord vergeten? Log via SSH in en voer <code>sudo voxip-kiosk-ctl reset-password</code> uit.</p>
|
||||
<p class="muted small">Wachtwoord vergeten? Log via SSH in en voer <code>sudo daynivo-kiosk-ctl reset-password</code> uit.</p>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -94,7 +94,7 @@
|
||||
<h2>Herstel bij een onbereikbare kiosk</h2>
|
||||
<ul class="plain">
|
||||
<li>Iedere wijziging wordt na {{ rollback_seconds // 60 }} minuten automatisch teruggedraaid als je hem niet bevestigt, ook als de stroom tussendoor uitvalt.</li>
|
||||
<li>Noodherstel: zet een leeg bestand <code>voxip-network-reset</code> op de bootpartitie van de SD-kaart en start de Pi. Alle Daynivo-netwerkprofielen worden dan verwijderd (terug naar DHCP).</li>
|
||||
<li>Noodherstel: zet een leeg bestand <code>daynivo-network-reset</code> op de bootpartitie van de SD-kaart en start de Pi. Alle Daynivo-netwerkprofielen worden dan verwijderd (terug naar DHCP).</li>
|
||||
</ul>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -4,7 +4,7 @@
|
||||
<section class="card card-narrow">
|
||||
<h1>Welkom bij Daynivo Kiosk Manager</h1>
|
||||
<p>Stel eerst een uniek beheerderswachtwoord in. Je hebt daarvoor de <strong>setupcode</strong> nodig die op het
|
||||
scherm van de kiosk staat (of via SSH: <code>sudo voxip-kiosk-ctl setup-code</code>).</p>
|
||||
scherm van de kiosk staat (of via SSH: <code>sudo daynivo-kiosk-ctl setup-code</code>).</p>
|
||||
{% if error %}<div class="alert alert-error" role="alert">{{ error }}</div>{% endif %}
|
||||
<form method="post" class="form">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -3,6 +3,10 @@ Description=Daynivo configuratie en SSH-sleutels importeren vanaf de bootpartiti
|
||||
Documentation=file:///usr/share/doc/voxip-kiosk/README.md
|
||||
After=local-fs.target
|
||||
Before=voxip-kiosk-manager.service voxip-kiosk-browser.service ssh.service
|
||||
ConditionPathExistsGlob=|/boot/firmware/daynivo-config.json
|
||||
ConditionPathExistsGlob=|/boot/firmware/daynivo-authorized_keys
|
||||
ConditionPathExistsGlob=|/boot/daynivo-config.json
|
||||
ConditionPathExistsGlob=|/boot/daynivo-authorized_keys
|
||||
ConditionPathExistsGlob=|/boot/firmware/voxip-config.json
|
||||
ConditionPathExistsGlob=|/boot/firmware/voxip-authorized_keys
|
||||
ConditionPathExistsGlob=|/boot/voxip-config.json
|
||||
|
||||
+28
-9
@@ -169,35 +169,54 @@ def test_boot_guard_rolls_back_and_honours_reset(helper, paths, 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")
|
||||
(boot / "voxip-network-reset").write_text("")
|
||||
(boot / "daynivo-network-reset").write_text("")
|
||||
assert helper.network_boot_guard() == {"reset": True}
|
||||
assert not (paths.nm_connections_dir / "voxip-wlan0.nmconnection").exists()
|
||||
assert not (boot / "voxip-network-reset").exists()
|
||||
assert not (boot / "daynivo-network-reset").exists()
|
||||
assert old.exists()
|
||||
|
||||
|
||||
def test_boot_guard_still_honours_the_old_reset_name(helper, paths, boot):
|
||||
(paths.nm_connections_dir / "voxip-eth0.nmconnection").write_text("x")
|
||||
(boot / "voxip-network-reset").write_text("")
|
||||
assert helper.network_boot_guard() == {"reset": True}
|
||||
assert not (paths.nm_connections_dir / "voxip-eth0.nmconnection").exists()
|
||||
assert not (boot / "voxip-network-reset").exists()
|
||||
|
||||
|
||||
def test_boot_import_applies_config(helper, paths, boot):
|
||||
(boot / "voxip-config.json").write_text(json.dumps({"device_name": "Hal", "url": "https://klant.example.nl/display/hal?token=x",
|
||||
"hostname": "hal", "rotation": 90}))
|
||||
assert helper.boot_import() == {"imported": ["voxip-config.json"]}
|
||||
(boot / "daynivo-config.json").write_text(json.dumps({"device_name": "Hal", "url": "https://klant.example.nl/display/hal?token=x",
|
||||
"hostname": "hal", "rotation": 90}))
|
||||
assert helper.boot_import() == {"imported": ["daynivo-config.json"]}
|
||||
conf = load_config(paths.config_file)
|
||||
assert conf["device_name"] == "Hal" and conf["rotation"] == 90 and conf["url"].startswith("https://klant")
|
||||
assert (helper.etc / "hostname").read_text() == "hal\n"
|
||||
assert (boot / "daynivo-config.json.applied").exists()
|
||||
|
||||
|
||||
def test_boot_import_still_accepts_the_old_names(helper, paths, boot):
|
||||
(boot / "voxip-config.json").write_text(json.dumps({"device_name": "Oud", "rotation": 180}))
|
||||
(boot / "daynivo-config.json").write_text(json.dumps({"device_name": "Nieuw"}))
|
||||
assert helper.boot_import() == {"imported": ["voxip-config.json", "daynivo-config.json"]}
|
||||
conf = load_config(paths.config_file)
|
||||
assert conf["device_name"] == "Nieuw" and conf["rotation"] == 180 # the Daynivo file is applied last
|
||||
assert (boot / "voxip-config.json.applied").exists()
|
||||
|
||||
|
||||
def test_boot_import_rejects_invalid_config(helper, paths, boot):
|
||||
before = paths.config_file.read_text()
|
||||
(boot / "voxip-config.json").write_text(json.dumps({"url": "http://onveilig.example"}))
|
||||
(boot / "daynivo-config.json").write_text(json.dumps({"url": "http://onveilig.example"}))
|
||||
helper.boot_import()
|
||||
assert paths.config_file.read_text() == before
|
||||
assert (boot / "voxip-config.json.rejected").exists()
|
||||
assert "HTTPS" in (boot / "voxip-config.error.txt").read_text()
|
||||
assert (boot / "daynivo-config.json.rejected").exists()
|
||||
assert "HTTPS" in (boot / "daynivo-config.error.txt").read_text()
|
||||
|
||||
|
||||
def test_boot_import_rejects_non_key_lines(helper, boot):
|
||||
(boot / "voxip-authorized_keys").write_text("dit is geen sleutel\n")
|
||||
(boot / "daynivo-authorized_keys").write_text("dit is geen sleutel\n")
|
||||
(boot / "voxip-authorized_keys").write_text("ook geen sleutel\n")
|
||||
helper.boot_import()
|
||||
assert (boot / "daynivo-authorized_keys.rejected").exists()
|
||||
assert (boot / "voxip-authorized_keys.rejected").exists()
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ systemctl daemon-reload
|
||||
|
||||
echo "==> Bestanden verwijderen"
|
||||
rm -rf /usr/lib/voxip-kiosk /usr/share/voxip-kiosk /usr/share/doc/voxip-kiosk
|
||||
rm -f /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
|
||||
rm -f /etc/systemd/journald.conf.d/voxip-kiosk.conf /etc/systemd/system.conf.d/voxip-watchdog.conf
|
||||
rm -f /etc/logrotate.d/voxip-kiosk /etc/avahi/services/voxip-kiosk.service
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@
|
||||
li.textContent = u;
|
||||
list.appendChild(li);
|
||||
});
|
||||
document.getElementById("code").textContent = params.get("code") || "zie: sudo voxip-kiosk-ctl setup-code";
|
||||
document.getElementById("code").textContent = params.get("code") || "zie: sudo daynivo-kiosk-ctl setup-code";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user