All checks were successful
Deploy netdiag / deploy (push) Successful in 13s
Der Reiter stand auf jeder Kundenkarte; die Leiste dort traegt ueber 20 Eintraege, auf Prod gibt es 20 Protokolle bei 6 von 111 Kunden. Er erscheint jetzt nur bei Bestand, mit Anzahl. Am AUFTRAG bleibt er fest. Als Hook (class/actions_netdiag.class.php, completeTabsHead) statt festem Tab, Muster wie bei Mahnung und ElektroPlanung. Uebernimmt einen bereits vorhandenen Eintrag desselben Schluessels statt einen zweiten anzuhaengen — kein doppelter Reiter auch vor der Reaktivierung. Lokal verifiziert: Kunde mit 13 Protokollen zeigt 'Netzwerk-Diagnose 13' einmalig, Kunde ohne Protokoll zeigt den Reiter gar nicht. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
344 lines
19 KiB
Markdown
344 lines
19 KiB
Markdown
# Changelog NetDiag
|
||
|
||
## 1.3.1 — 2026-09-07
|
||
|
||
### Reiter am Kunden nur noch bei vorhandenen Protokollen
|
||
Der Reiter „Netzwerk-Diagnose" stand auf **jeder** Kundenkarte. Die Reiterleiste dort trägt
|
||
über 20 Einträge; auf Prod gibt es 20 Protokolle bei 6 von 111 Kunden — bei den übrigen 105
|
||
zeigte er eine leere Seite. Er erscheint jetzt nur bei Bestand, mit der Anzahl daneben.
|
||
**Am Auftrag bleibt er unverändert ein fester Tab.**
|
||
|
||
Technisch als Hook statt festem Tab (`class/actions_netdiag.class.php`, `completeTabsHead`),
|
||
weil die Bedingung eines Descriptor-Tabs keine Datenbankabfrage zulässt — Muster wie bei den
|
||
Modulen Mahnung und ElektroPlanung. **Nach dem Deploy Modul einmal reaktivieren**, sonst
|
||
steht der alte feste Reiter bis dahin als `MAIN_MODULE_NETDIAG_TABS_0` in der Datenbank; der
|
||
Hook übernimmt einen bereits vorhandenen Eintrag statt einen zweiten anzuhängen, doppelte
|
||
Reiter kann es also auch im Zwischenzustand nicht geben.
|
||
|
||
## 1.3.0 — 2026-08-19
|
||
|
||
### Neues Werkzeug: SIP-Erreichbarkeit (Telefonie)
|
||
|
||
Die App fragt Telefonanlage oder Provider mit einer OPTIONS-Anfrage (RFC 3261) —
|
||
ohne Anruf, ohne Zugangsdaten, ohne dass irgendwo ein Telefon klingelt. Modulseitig
|
||
kommt der PDF-Zweig dazu.
|
||
|
||
- `netdiagPdfSip()` in `lib/netdiag_pdf.lib.php`: Ziel, Port und Statuszeile in der
|
||
Kopfzeile, darunter der Befund im Klartext, dann eine Zeile je Transportweg.
|
||
**Warum ein eigener Zweig:** in einer flachen Schlüssel/Wert-Liste sieht „401
|
||
Unauthorized" wie ein Fehler aus. Tatsächlich ist es der Beweis, dass die Instanz
|
||
erreichbar ist und antwortet — sie will nur Zugangsdaten sehen. Diese Unterscheidung
|
||
ist im Kundendokument der Unterschied zwischen „Anlage tot" und „Zugangsdaten prüfen".
|
||
- Der Grenzhinweis steht mit im PDF: gemessen ist die **Erreichbarkeit**, NICHT die
|
||
Sprachqualität. RTP-Jitter ohne aufgebautes Gespräch zu behaupten wäre eine
|
||
Falschaussage.
|
||
- `netdiagToolName()`: `sipcheck` → „SIP-Erreichbarkeit".
|
||
- `netdiagKundenfelder()` um die Felder des Werkzeugs ergänzt (`befund`,
|
||
`statuszeile`, `antwortWeg`, `anmeldungNoetig`, `versuche`, `unterstuetzteMethoden`,
|
||
`zielIp`, `zielHerkunft`, `zielPort`, `laufzeitMs`).
|
||
**Achtung, dabei aufgefallen:** der naheliegende Schlüssel `port` war bereits vom
|
||
SNMP-Werkzeug als „Switch-Port" belegt. Ein SIP-Port unter diesem Namen stünde im
|
||
Kundendokument falsch beschriftet — deshalb `zielPort`.
|
||
|
||
### WLAN-Kanalanalyse: Warnungen werden nicht mehr abgeschnitten
|
||
|
||
`netdiagPdfWifiKanal()` kürzte jede Warnung nach 160 Zeichen (`dol_trunc`). Betroffen
|
||
war genau die Begründung: „… blockiert damit praktisch 2 der 3 störungsfreien Kanäle.
|
||
In dicht besiedelter Umgebung meist ein Fehle…". Eine Warnung ohne ihren Grund ist im
|
||
Kundendokument wertlos; MultiCell bricht ohnehin sauber um.
|
||
|
||
### Sicherheit: Token in der Adresszeile nur noch für den APK-Download
|
||
|
||
`netdiag_api_read_token()` nimmt `?jwt=` nicht mehr allgemein an, sondern nur noch,
|
||
wenn der Endpunkt es ausdrücklich erlaubt (`netdiag_api_authenticate($db, true)`).
|
||
Einzige Stelle: `update.php?download=1`.
|
||
|
||
Warum überhaupt: ein Token in der URL landet in Zugriffs- und Proxy-Logs und gilt
|
||
sieben Tage für die **gesamte** Kunden-API. Vorher hätte damit jeder, der ein Log
|
||
liest, Aufträge, Kunden und Protokolle abrufen können.
|
||
|
||
Warum die eine Ausnahme bleibt: die im Feld installierten App-Fassungen bauen die
|
||
Download-Adresse mit dem Token darin. Wird der Zweig sofort geschlossen, kommt kein
|
||
altes Gerät mehr an die neue APK — und die neue APK ist genau die, die den Zweig
|
||
überflüssig macht. **Zu entfernen, sobald der Rollout bestätigt ist** (Hinweis steht
|
||
im Code an beiden Stellen).
|
||
|
||
`pdf.php` nimmt ab sofort ausschließlich den `Authorization: Bearer`-Header.
|
||
|
||
|
||
## 1.2.0 — 2026-08-17
|
||
|
||
### Anmeldung nur noch über AWL-Auth — der eigene JWT-Pfad ist weg
|
||
|
||
**Achtung, das ist ein Schnitt:** Geräte mit einer App-Fassung, die noch ein
|
||
modul-eigenes netdiag-JWT benutzt, können sich nicht mehr anmelden und brauchen
|
||
die aktuelle APK. Eddy hat den Rollout am 17.08.2026 als abgeschlossen bestätigt.
|
||
|
||
Warum das mehr ist als Aufräumen: Der alte Pfad prüfte die Signatur eines selbst
|
||
ausgestellten Tokens und holte damit einen Benutzer aus der Datenbank — **an der
|
||
Sitzungsliste von awlauth vorbei**. „Gerät abmelden" hatte auf ein solches Token
|
||
keine Wirkung; ein verlorenes Handy blieb bis zum Ablauf der TTL angemeldet. Jetzt
|
||
gibt es genau eine Stelle, an der Sitzungen entstehen und enden.
|
||
|
||
- `api/auth.php`: der Rückfallweg (`checkLoginPassEntity` + eigenes JWT) ist
|
||
entfernt. Ohne aktives AWL-Auth antwortet die Anmeldung mit 503 und einer
|
||
klaren Meldung, statt auf einen zweiten Weg auszuweichen.
|
||
- `api/netdiag_api.lib.php`: `netdiag_api_authenticate()` prüft nur noch
|
||
`awlauth_verify_token()`. Die Hilfsfunktionen `netdiag_jwt_encode/decode`,
|
||
`netdiag_jwt_secret` und die Base64-URL-Helfer sind ersatzlos entfallen.
|
||
- **Konstanten `NETDIAG_API_JWT_SECRET` und `NETDIAG_API_TOKEN_TTL`** sind aus
|
||
dem Modul-Descriptor raus. Bestehende Werte in `llx_const` werden bewusst
|
||
NICHT gelöscht — sie schaden nicht, und ein Löschlauf beim Modul-Update ist
|
||
das größere Risiko.
|
||
- **TTL-Feld aus `admin/setup.php` entfernt.** Die Gültigkeit kommt jetzt allein
|
||
aus `AWLAUTH_TTL` (awlauth-Setup, Standard 7 Tage, dort 1–180 Tage
|
||
einstellbar). Zwei Stellschrauben für dieselbe Sache sind eine Fehlerquelle —
|
||
die hiesige hätte nach diesem Umbau still gar nichts mehr getan. An ihrer
|
||
Stelle steht jetzt ein Verweis.
|
||
- Sprachdateien de_DE und en_US nachgezogen, beide wieder deckungsgleich
|
||
(57 Schlüssel).
|
||
|
||
Geprüft gegen die lokale Testinstanz: Anmeldung mit falschem Passwort → sauberer
|
||
Fehler von awlauth; API mit ungültigem Token → 401 „Token ungültig oder
|
||
abgelaufen"; ohne Token → 401 „Kein Token übermittelt". Kein PHP-Fehler durch
|
||
die entfernten Funktionen.
|
||
|
||
## 1.1.7 — 2026-08-17
|
||
|
||
### PDF-Zweig und Feldtabelle für den Geräte-Vergleich
|
||
|
||
`netdiagPdfGeraeteDiff()` gibt die drei Listen getrennt aus: neu hinzugekommen,
|
||
nicht mehr erreichbar, mit neuer IP-Adresse — plus „Gleiche Adresse, andere
|
||
offene Ports". Beim Wiederholungstermin zählt, WELCHES Gerät neu ist, nicht nur
|
||
wie viele; als `|`-Kette in einer Zelle wäre das vorhanden, aber nicht lesbar.
|
||
|
||
An jeder Zeile steht, worüber das Gerät wiedererkannt wurde. „Erkannt über IP
|
||
und Portmuster" ist eine schwächere Aussage als „über Netzwerkname", und dieser
|
||
Unterschied gehört ins Dokument statt in eine Fußnote — die Wiedererkennung
|
||
läuft bewusst nicht über MAC-Adressen, die Android seit Version 10 nicht mehr
|
||
herausgibt.
|
||
|
||
Neu in der Whitelist: `verglichenMit`, `geraeteVorher`, `geraeteJetzt`,
|
||
`mitNeuerAdresse`, `andereOffenePorts`, `unveraendert`; Werkzeugname
|
||
`geraetediff` → „Geräte-Vergleich". `neu` und `nichtMehrErreichbar` standen
|
||
bereits drin (der IP-Scan nutzt dieselben Schlüssel).
|
||
|
||
Geprüft im Durchstich: in der App gegen echte Serverdaten gemessen
|
||
(Vergleich ND2026-0016 gegen ND2026-0006), synchronisiert, PDF erzeugt und
|
||
angesehen.
|
||
|
||
## 1.1.6 — 2026-08-17
|
||
|
||
### PDF-Zweig für die DNS-Prüfung
|
||
|
||
`netdiagPdfDns()` — je befragtem Server eine eigene Zeile statt einer
|
||
`|`-getrennten Kette. Bei zwei Servern ging die generische Darstellung noch,
|
||
bei den vier bis fünf Einträgen eines Firmennetzes wäre die eigentliche Aussage
|
||
— welcher Server antwortet und welcher nicht — nicht mehr auffindbar gewesen.
|
||
Damit hat jedes Werkzeug mit Listenergebnis einen eigenen Renderer: Dauertest,
|
||
WLAN-Kanal, Geräte-Monitor, Internet-Kette, DNS-Prüfung.
|
||
|
||
Geprüft im vollständigen Durchstich: in der App gemessen (Emulator gegen die
|
||
lokale Testinstanz), synchronisiert, PDF aus Protokoll ND2026-0016 erzeugt und
|
||
angesehen.
|
||
|
||
## 1.1.5 — 2026-08-16
|
||
|
||
### Feldtabelle für das neue Werkzeug „DNS-Prüfung"
|
||
|
||
Die App fragt jeden DNS-Server des Netzes einzeln und namentlich (eigener
|
||
UDP-Client auf Port 53). Damit die Aussage im Kundendokument ankommt, sind
|
||
`gefragteServer` und `antworten` in der Whitelist ergänzt und `dnscheck` in
|
||
der Werkzeugliste eingetragen — ohne diese drei Zeilen stünde dort nur die
|
||
Ampel. Die einzelnen Serverzeilen („192.168.1.1: antwortet, kennt den Namen
|
||
nicht") sind das eigentliche Ergebnis.
|
||
|
||
## 1.1.4 — 2026-08-16
|
||
|
||
### Drei Falschaussagen im Kundendokument, alle aus Altdaten
|
||
|
||
- **„0 DHCP-Server (!)" in Rot.** In der Produktionsdatenbank stehen drei
|
||
ausgelieferte Messungen des entfernten Werkzeugs `dhcpcheck` mit Ergebnis
|
||
`{"count":0,"server":[],"hinweis":""}` und Status 2. Bei einer Kabelverbindung
|
||
gibt Android die DHCP-Angaben aber grundsätzlich nicht heraus (nur `DhcpInfo`,
|
||
nur WLAN, deprecated) — gemessen wurde also nichts, „0 gefunden" war der
|
||
Rückgabewert für „nicht ermittelbar". `netdiagAltlastKorrektur()` zeigt diese
|
||
Messungen jetzt als „nicht messbar" mit Erklärung, in PDF **und**
|
||
Technikeransicht. Die gespeicherten Rohdaten bleiben unangetastet (Beleg);
|
||
korrigiert wird nur die Darstellung, und die wird bei jedem Abruf neu erzeugt.
|
||
Die Ergebniszahlen werden bei so korrigierten Messungen unterdrückt —
|
||
„Gefundene Geräte: 0" widerspräche der Aussage direkt darüber.
|
||
- **„Lease-Dauer: 864000 s s".** Ältere App-Fassungen haben die Einheit in den
|
||
Wert geschrieben, die Feldtabelle hängt sie erneut an. Nachgewiesen an
|
||
Prod-Messung #42. Die Einheit wird jetzt nur noch angehängt, wenn sie nicht
|
||
schon am Wert steht.
|
||
- **Adress- und Lease-Felder mit dem Wert 0** (`server`, `dhcpServer`,
|
||
`gateway`, `ipv4`, `lease` …) sind keine Messung, sondern das „nichts
|
||
ermittelt" der alten Android-API. Sie erscheinen jetzt als „nicht ermittelbar"
|
||
statt als „0".
|
||
|
||
Neues Feld in der Whitelist: `dhcpQuelle` — `system` (LinkProperties, ab
|
||
Android 11, gilt für jeden Anschlusstyp) oder `wlan` (alter Weg, nur WLAN, dafür
|
||
mit Lease-Dauer). Damit ist im Nachhinein klärbar, ob eine fehlende DHCP-Angabe
|
||
an der Leitung lag oder an der Android-Version.
|
||
|
||
## 1.1.3 — 2026-08-16
|
||
|
||
### Internet-Kette im PDF + ein Zeichenfehler, der jedes Protokoll betraf
|
||
|
||
- **`netdiagPdfKette()`** für das neue App-Werkzeug „Internet-Kette": Fehlerglied
|
||
als eigene hervorgehobene Zeile, darunter die vier geprüften Stufen einzeln,
|
||
dann Systemurteil und Hinweis. Ohne eigenen Zweig stünden die Stufen als
|
||
`|`-Kette in einer Zelle und das Fehlerglied — die eigentliche Aussage —
|
||
mittendrin.
|
||
- **`netdiagPdfText()`: Pfeile wurden als „?" gedruckt.** `pdf_getPDFFont()`
|
||
liefert hier Helvetica, einen Core-Font mit WinAnsi-Kodierung; alles außerhalb
|
||
dieses Zeichenvorrats setzt TCPDF wortlos als „?" (bekannt aus KB #1025).
|
||
Aufgefallen an „www.google.de → 142.250.185.67", das im Kundendokument als
|
||
„www.google.de ? 142.250.185.67" ankam — der Pfeil ist dort kein Schmuck,
|
||
er trennt Frage und Antwort. Die Ersetzung greift jetzt in **allen**
|
||
PDF-Zweigen, also auch für Altdaten und künftige Werkzeuge.
|
||
Bewusst keine Unicode-Schrift: `dejavusans` würde Schriftbild und Dateigröße
|
||
aller Protokolle ändern. Gedankenstrich, Mittelpunkt, Auslassungspunkte und
|
||
Anführungszeichen sind in WinAnsi enthalten und bleiben unangetastet
|
||
(im erzeugten Dokument nachgeprüft).
|
||
- Feld-Whitelist um `fehlerglied`, `stufen`, `systemUrteil`, `validated` und
|
||
`captivePortal` erweitert, Werkzeugname `internetkette` → „Internet-Kette".
|
||
`validated`/`captivePortal` kommen aus dem LinkInfo-Objekt und erscheinen
|
||
damit auch beim IP-Test an der Dose.
|
||
|
||
Geprüft an vier Fällen gegen die lokale Testinstanz, zwei davon sind die echten
|
||
Emulator-Messungen dieser Nacht (Gutfall und Flugmodus).
|
||
|
||
## 1.1.2 — 2026-08-16
|
||
|
||
### Geräte-Monitor bekommt einen eigenen PDF-Zweig
|
||
|
||
Die Dauerüberwachung lief bisher in den generischen `else`-Zweig von
|
||
`netdiag_pdf.lib.php` und wurde von `netdiagPdfFlattenResult()` zu **einer**
|
||
`|`-getrennten Zeile zusammengeschoben. Bei zehn überwachten Geräten standen
|
||
damit die zehn Geräte-Zeilen UND sämtliche Einzelausfälle in einer einzigen
|
||
Tabellenzelle — vollständig, aber beim Kunden nicht lesbar. Dauertest und
|
||
WLAN-Kanal hatten längst je einen Tabellen-Renderer, der Monitor nicht.
|
||
|
||
- **`netdiagPdfMonitor()`**: Kennzahlenzeile, Tabelle „Überwachte Geräte",
|
||
Tabelle „Einzelne Ausfälle" mit Uhrzeiten, Hinweis zum Messverfahren am Ende.
|
||
- **Die Falle dabei**, gegen die es einen Kommentar im Code gibt: beim Dauertest
|
||
führt ein gesetztes `hinweis` zum sofortigen Abbruch der Ausgabe. Der Monitor
|
||
legt aber IMMER einen Hinweis an (das Messverfahren gehört zur Aussage dazu) —
|
||
derselbe Aufbau hätte hier bei **jedem** Lauf alle Zahlen verschluckt. Nur
|
||
`fehler` bricht ab, der Hinweis steht am Schluss.
|
||
- Tabellenköpfe wiederholen sich nach einem Seitenumbruch („— Fortsetzung"),
|
||
wie in der Geräteliste.
|
||
- Obergrenze 200 Ausfallzeilen gegen den pathologischen Fall (ein im
|
||
Sekundentakt flappendes Gerät erzeugt über einen Arbeitstag vierstellig viele
|
||
Segmente). Gekürzt wird **sichtbar**: „… und N weitere Ausfälle" steht im
|
||
Dokument, sonst läse sich das Protokoll als vollständig.
|
||
- **`ausfallzeitSek` heißt jetzt „Ausfallzeit (schlechtestes Gerät)"** — der
|
||
Wert ist der des schlechtesten Geräts, nicht die Summe über alle. Bei zehn
|
||
überwachten Geräten las sich „Ausfallzeit: 8 min" wie eine Gesamtaussage.
|
||
Gleiche Korrektur in `app/src/lib/messfelder.ts`, damit App und PDF dasselbe
|
||
Feld gleich benennen.
|
||
|
||
Geprüft gegen die lokale Testinstanz mit vier konstruierten Fällen (10 Geräte
|
||
mit Aussetzern, ein durchgehend totes Gerät, 250 Einzelausfälle über sechs
|
||
Seiten, abgerissener Lauf) und gegen die echte Monitor-Messung aus ND2026-0016.
|
||
|
||
## 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)
|
||
|
||
NetDiag war die letzte AWL-App mit eigenem Login: eigenes JWT, eigener Schlüssel
|
||
(`NETDIAG_API_JWT_SECRET`), eigene Gültigkeitsdauer, keine Möglichkeit, ein verlorenes
|
||
Handy gezielt abzumelden. Ab sofort stellt awlauth das Token aus — dasselbe Token,
|
||
derselbe Schlüssel und dieselbe Sitzungs-Registry wie bei den sechs Browser-Apps.
|
||
|
||
- `api/auth.php` prüft das Passwort über `awlauth_login()`. Damit greifen dort auch die
|
||
**Brute-Force-Bremse** (5 Fehlversuche je IP in 15 min, 10 je Benutzername in 30 min)
|
||
und die einheitliche, nicht-verräterische Fehlermeldung. Das Token kommt aus
|
||
`awlauth_issue_bearer()` und legt eine Sitzungszeile an — das Gerät erscheint als
|
||
„NetDiag-App · Android" in der awlauth-Geräteliste und ist dort einzeln abmeldbar.
|
||
- `netdiag_api_authenticate()` prüft zuerst das awlauth-Token. Ein **abgelaufenes oder
|
||
widerrufenes** Token führt sofort zu 401, auch wenn die Signatur noch stimmt.
|
||
- **Übergangsweise** wird ein bereits ausgestelltes altes netdiag-JWT weiterhin akzeptiert,
|
||
damit die Umstellung niemanden mitten im Einsatz aussperrt. Dieser Pfad entfällt, sobald
|
||
alle Geräte einmal neu angemeldet sind.
|
||
- Ohne aktives awlauth-Modul läuft NetDiag unverändert mit dem eigenen JWT weiter.
|
||
|
||
**Die Antwortform von `auth.php` ist bewusst unverändert** (`{token, expiresIn, user}`).
|
||
Bereits installierte APKs laufen nach einer **einmaligen Neuanmeldung** ohne Update weiter.
|
||
|
||
### CORS enger gefasst
|
||
|
||
`Access-Control-Allow-Origin: *` ist raus. Die API liefert Kundendaten aus; ein Wildcard
|
||
erlaubt jeder beliebigen Webseite, die Antwort auszulesen, sobald sie an ein Token kommt.
|
||
Erlaubt sind jetzt nur die App-Origins (`https://localhost`, `capacitor://localhost`,
|
||
`http://localhost`, `ionic://localhost`) und der Vite-Dev-Server; dazu `Vary: Origin`.
|
||
Anfragen ohne Origin-Header (nativer HTTP-Client, der APK-Downloader im Kotlin-Plugin,
|
||
curl) bekommen wie bisher eine Antwort — dort greift die Same-Origin-Policy ohnehin nicht.
|
||
|
||
## 1.0.0
|
||
|
||
- Erstversion
|
||
- Datenmodell: Protokoll, Gerät, Messung
|
||
- JSON-API: auth, customers, orders, protocols (Sync), pdf
|
||
- Tab "Netzwerk-Diagnose" an Kunde und Auftrag
|
||
- PDF-Protokoll-Generator + ECM-Ablage
|
||
- Backend: Protokoll-Liste und Detailansicht
|
||
- Admin: Token-Einstellung, QR-Code zum App-Download
|