From 9f07896b05f570379a1b1bed0ae8ac1e0abb3161 Mon Sep 17 00:00:00 2001 From: Eduard Wisch Date: Sun, 16 Aug 2026 19:56:10 +0200 Subject: [PATCH] Doku + Version 1.1.1: die Whitelist-Falle steht jetzt im README [deploy] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version auf 1.1.1 gezogen — auf Prod lief sonst eine 1.1.0, die nicht der 1.1.0 im Repo entspricht (die vier Bugfixes gingen ohne Versionssprung raus). ChangeLog 1.1.1 mit allen vier Fehlern, der Rechtelücke im GET-Zweig und den neuen Monitor-Feldern. README: - Neuer Abschnitt "Neue Messart aus der App aufnehmen" mit den DREI Stellen in netdiag.lib.php und der Spalte "wenn vergessen". Das ist die Falle, in die hier schon zweimal getappt wurde - einmal mit erfundenen Testdaten, einmal mit 'typ' statt 'type'. Feldnamen immer aus dem erzeugenden App-Code ablesen. - Anmeldung laeuft ueber awlauth (stand noch "JWT-Auth") - Rechteprüfung je Endpunkt dokumentiert, inkl. der Begruendung, warum der GET-Zweig auch 'write' akzeptiert - Hinweis, dass '?jwt=' nur fuer den PDF-Download existiert und in Logs landet --- ChangeLog.md | 56 +++++++++++++++++++++++++++++++ README.md | 36 +++++++++++++++++++- core/modules/modNetDiag.class.php | 2 +- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 54dabb8..7610276 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,61 @@ # Changelog NetDiag +## 1.1.1 — 2026-08-16 + +### Vier stille Fehler im Kundendokument und im Sync + +Alle vier waren bereits ausgeliefert und fielen nicht auf, weil das PDF ja +weiterhin erzeugt wurde — nur ohne die betroffene Zeile. Gefunden durch einen +systematischen Abgleich der Whitelist gegen den erzeugenden App-Code. + +- **`'typ'` war ein toter Schlüssel.** Kein Werkzeug erzeugt ihn; die App reicht + ein `LinkInfo`-Objekt durch, dort heißt das Feld `'type'`. Folge: im + Abnahmebeleg für eine Netzwerkdose fehlte die Angabe, **ob per LAN oder WLAN + gemessen wurde**. Zusätzlich `'rssi'` aufgenommen — bei einer WLAN-Dose ist + der Empfangspegel der eigentliche Messwert und wurde bisher verworfen. + Die Rohwerte sind englisch; `netdiagKundentext()` bildet sie jetzt ab + (`ethernet` → „LAN (Kabel)"), sonst stünde „Anschlussart: ethernet" im + Abnahmeprotokoll eines deutschen Handwerksbetriebs. +- **Leeres Array druckte „Offene Ports: " ohne Wert.** Die Leerprüfung ist ein + `elseif` hinter dem Array-Zweig und wurde nie erreicht. Betraf ausgerechnet + die *guten* Ergebnisse: Portscan ohne offenen Port, IP-Konflikt ohne Konflikt, + IP-Scan ohne Veränderung. Jetzt „keine" — Weglassen wäre schlechter, weil der + Kunde sonst nicht unterscheiden kann, ob nichts gefunden oder nichts geprüft + wurde. +- **`'error'` fehlte in der Whitelist.** Der IP-Konflikt gibt im Abbruchfall + `{ error: … }` mit roter Ampel zurück — im Kundendokument stand eine rote + Ampel ohne einen Buchstaben Erklärung. Die App vereinheitlicht künftig auf + `'fehler'`, aber Altdaten lassen sich nicht ändern. +- **`tool`/`category`/`label` wurden beim Sync nicht auf die Spaltenlänge + gekürzt** (varchar 64/32/255). Bei striktem SQL-Modus kippt **ein** zu langes + Label den gesamten Sync per `rollback()` — der Techniker steht beim Kunden mit + einem Protokoll da, das sich nicht abschließen lässt, weil eine Beschriftung + zu lang war. Die App setzt Labels durch Verketten zusammen, 255 Zeichen sind + erreichbar. `found_via` wurde 20 Zeilen darüber längst gekappt. + +### Rechteprüfung im GET-Zweig der Protokoll-API + +Bisher prüfte der GET-Zweig **gar nichts**: jeder angemeldete Benutzer konnte +mit einer geratenen ID ein fremdes Protokoll samt Geräteliste, IP-Adressen und +offenen Ports abrufen (der POST-Zweig verlangte seit jeher `write`). Das ist +beim Kunden erhobene Netzstruktur und gehört hinter ein Recht. + +`write` wird bewusst mit akzeptiert: die Rechte sind in Dolibarr einzeln +vergebbar, und ein Techniker mit Schreib- ohne ausdrückliches Leserecht dürfte +nicht ausgesperrt werden — das wäre erst beim Kunden aufgefallen. + +### Geräte-Monitor erscheint jetzt im Kundendokument + +Die App liefert ab dieser Version eine Auswertung der Dauerüberwachung als +richtige Messung (Verfügbarkeit, Ausfallzeit, Aussetzer je Gerät). Die sechs +neuen Schlüssel sind in der Whitelist ergänzt — ohne sie stünde im PDF nur die +Ampel. + +### Kleinigkeit + +`netdiagDauerLesbar()`: „1 Tage 0 Std" → „1 Tag". `floor()` liefert in PHP einen +Float, und `1.0 === 1` ist false — die Einzahl hatte deshalb nie gegriffen. + ## 1.1.0 — 2026-08-14 ### Anmeldung läuft über das zentrale Auth-Modul (awlauth) diff --git a/README.md b/README.md index 4f03e83..7cb4f6c 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,13 @@ Messungen und hängt die Protokolle dauerhaft an **Kunde** und **Auftrag**. - Datenmodell: Protokoll → Geräte → Messungen (`llx_netdiag_*`) - Tab **Netzwerk-Diagnose** an Kunde (thirdparty) und Auftrag (commande) -- JSON-API unter `/custom/netdiag/api/` für die mobile App (JWT-Auth) +- JSON-API unter `/custom/netdiag/api/` für die mobile App. Anmeldung seit + v1.1.0 über das zentrale Auth-Modul **awlauth** (Brute-Force-Bremse, + gemeinsame Sitzungsliste, „Gerät abmelden"); der alte modul-eigene JWT-Pfad + bleibt als Rückfall, bis alle Geräte die neue APK haben - PDF-Protokoll, wird im Dokumentenarchiv (ECM) abgelegt +- **Zwei Sichten auf dieselben Messdaten:** die Technikeransicht zeigt alles, + das Kunden-PDF nur eine Whitelist (siehe „Neue Messart" unten) - Rechtesystem: `netdiag → protocol → read/write/delete` - Mehrsprachig (de_DE, en_US) - QR-Code zum App-Download in der Modul-Einrichtung @@ -40,6 +45,35 @@ Alle unter `https:///custom/netdiag/api/`: | `pdf.php` | GET `?id=&jwt=` | Protokoll-PDF streamen | Authentifizierung per `Authorization: Bearer ` oder `?jwt=`. +Jeder Endpunkt prüft ein Recht — `protocols.php` im GET-Zweig `protocol read` +**oder** `write`: die Rechte sind in Dolibarr einzeln vergebbar, und ein +Techniker mit Schreib- ohne ausdrückliches Leserecht darf nicht ausgesperrt +werden (das fiele erst beim Kunden auf). + +> `?jwt=` in der URL ist nur für den PDF-Download da (der Browser kann dort +> keinen Header setzen). Langzeit-Token in URLs landen in Zugriffs- und +> Proxy-Logs — Ablösung steht in `ROADMAP_UMSETZUNG.md`, Phase L5. + +## Neue Messart aus der App aufnehmen + +Die App schickt Messergebnisse als freies JSON. Damit ein Feld beim Kunden +ankommt, sind **drei** Stellen in `lib/netdiag.lib.php` zu pflegen: + +| Funktion | Zweck | Wenn vergessen | +|----------|-------|----------------| +| `netdiagKundenfelder()` | Whitelist + Beschriftung + Einheit | Feld verschwindet im Kunden-PDF spurlos, übrig bleibt die Ampel | +| `netdiagToolName()` | Klarname des Werkzeugs | beim Kunden steht „[netzwerk] meintool" | +| `netdiagKundentext()` | Rohwerte übersetzen/entschärfen | englische API-Werte im deutschen Abnahmedokument | + +Spiegelbildlich dazu `app/src/lib/messfelder.ts` in der App. + +**Feldnamen immer aus dem erzeugenden Code der App ablesen** (`types.ts`, die +`run()`-Rümpfe der Werkzeuge), nie aus dem Kopf und nie aus selbst +geschriebenen Testdaten — das ist hier schon zweimal schiefgegangen (KB #1084). +Braucht die Messart eine eigene Tabellendarstellung im PDF, einen Zweig in +`lib/netdiag_pdf.lib.php` ergänzen (Vorbilder: `netdiagPdfStressTest`, +`netdiagPdfWifiKanal`) — sonst wird das Ergebnis zu einer `|`-getrennten Zeile +zusammengeschoben. ## Einrichtung diff --git a/core/modules/modNetDiag.class.php b/core/modules/modNetDiag.class.php index 395e3b9..3efc43a 100644 --- a/core/modules/modNetDiag.class.php +++ b/core/modules/modNetDiag.class.php @@ -67,7 +67,7 @@ class modNetDiag extends DolibarrModules $this->editor_url = ''; $this->editor_squarred_logo = ''; - $this->version = '1.1.0'; + $this->version = '1.1.1'; // Konstanten-Name in llx_const für Modul-Status $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);