NetDiag — Netzwerk-Diagnose App (SvelteKit + Capacitor)
Find a file
Eduard Wisch ad5a102565
All checks were successful
Build APK / build-apk (push) Successful in 6m6s
Mit AWL-Konto anmelden: awlauth-Seite im Chrome-Tab statt Passwort in der App [apk]
Der Knopf oeffnet die awlauth-Anmeldeseite im Chrome-Tab (@capacitor/browser),
der die Anmeldung mit Chrome teilt - wer im Handy-Browser angemeldet ist, ist
ohne Eingabe zurueck in der App. Ruecksprung ueber das eigene Schema
de.data-it-solution.netdiag:/sso (Intent-Filter), abgesichert mit state und
PKCE; verarbeitet im Layout (appUrlOpen + getLaunchUrl). Passwort und
Fingerabdruck bleiben.

Mitgenommen: die bisher nicht committete README-Ergaenzung vom 19.08.
(Plugin-Dateien, "Was noch offen ist").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-01 11:23:28 +02:00
.forgejo/workflows android/ fest ins Repo aufgenommen — Build wie beim Adressmanager [apk] 2026-05-19 18:09:23 +02:00
android Mit AWL-Konto anmelden: awlauth-Seite im Chrome-Tab statt Passwort in der App [apk] 2026-10-01 11:23:28 +02:00
native-plugin Phase 0: doppelte Plugin-Quelle aufgeloest, falsche Doku-Zusagen korrigiert 2026-08-14 18:39:40 +02:00
src Mit AWL-Konto anmelden: awlauth-Seite im Chrome-Tab statt Passwort in der App [apk] 2026-10-01 11:23:28 +02:00
tools SIP-Erreichbarkeit, Fingerabdruck-Anmeldung, Token raus aus der Adresszeile [apk] 2026-08-19 21:40:27 +02:00
.gitignore WLAN-Diagramme lesbar gemacht: dBm-Achse, 5-GHz-Aufteilung, Farben je Netz 2026-08-15 17:24:59 +02:00
capacitor.config.ts Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
package.json Mit AWL-Konto anmelden: awlauth-Seite im Chrome-Tab statt Passwort in der App [apk] 2026-10-01 11:23:28 +02:00
README.md Mit AWL-Konto anmelden: awlauth-Seite im Chrome-Tab statt Passwort in der App [apk] 2026-10-01 11:23:28 +02:00
svelte.config.js Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
tsconfig.json Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
vite.config.ts Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00

NetDiag — Diagnose-App (Android)

Mobile Netzwerk-Diagnose-App. Erfasst vor Ort beim Kunden (Handy am WLAN oder USB-C→RJ45-Adapter) Geräte, Ports und Messungen und hängt die Protokolle ans Dolibarr-Modul netdiag an Kunde und Auftrag.

Stack

SvelteKit 2 · Svelte 5 · Tailwind 4 · Vite 7 · Capacitor 6 · SQLite-Offline

Entwicklung (Browser)

npm install
npm run dev          # http://localhost:5175

Im Browser liefert ein Mock (src/lib/scanner.ts) Beispiel-Scandaten — die Oberfläche lässt sich ohne Gerät entwickeln. API-Aufrufe gehen über den Vite-Proxy an den Dolibarr-Testserver (192.168.155.11, siehe vite.config.ts).

Android-Build

npm run build
npx cap add android        # einmalig
# android/ liegt komplett im Repo — cap sync kopiert nur die Web-Assets
npx cap sync android
npx cap open android

Release-APK über CI: Commit mit [apk] in der Message → Forgejo baut und lädt die APK in die Package Registry (netdiag-apk). Siehe .forgejo/workflows/build.yml.

Architektur

src/lib/
  api.ts            JSON-API-Client (JWT, 401-Refresh, Timeout)
  auth.svelte.ts    Anmelde-Status
  sso.ts            Anmeldung per AWL-Konto (Chrome-Tab, PKCE, Rücksprung)
  db.ts             Offline-Speicher (SQLite nativ / localStorage Browser)
  sync.svelte.ts    Sync-Queue -> Dolibarr (idempotent über clientUuid)
  scanner.ts        Brücke zum nativen Plugin (+ Browser-Mock)
  protocols.ts      Protokoll-Operationen (addMeasurement, upsertDevice, …)
  messfelder.ts     Beschriftung der Ergebnisfelder — Gegenstück zur
                    Whitelist im Dolibarr-Modul (siehe „Neues Tool")
  toolparams.ts     Gedächtnis der zuletzt benutzten Werkzeug-Parameter
  stresstest.ts     Auswertung des Dauertests (überlebt App-Wechsel)
  monitor.ts        Auswertung der Geräte-Überwachung -> Verfügbarkeit
  wifi/             Kanalgraph-Geometrie, Kanalempfehlung, Bewertung, Demodaten
  overlay.svelte.ts Overlay-Stapel für den Hardware-Zurück-Knopf
  toast.svelte.ts   kurze Rückmeldungen
  backButton.svelte.ts  Hardware-Back (Single-Instance, KB #480/#549)
  updater.ts        APK-Auto-Update-Prüfung (KB #363). Das Token geht als
                    Authorization-Header mit, nicht in der Adresse.
  tools/            erweiterbare Tool-Plattform
    index.ts        Registry — neues Tool hier eintragen
    netzwerk/       IP-Scan, Port, Ping, IP-Konflikt, SNMP, Traceroute, Stress
    internet/       Durchsatz-Test
    telefonie/      SIP-Erreichbarkeit über OPTIONS (sipcheck.ts) samt
                    Bewertung in sip-bewertung.ts. Jede Statuszeile beweist
                    eine antwortende Instanz — 401 heißt „erreichbar, will
                    Zugangsdaten", nicht „tot". RTP-Sprachqualität bewusst
                    NICHT: ohne aufgebautes Gespräch nicht ehrlich messbar.
src/routes/
  login/ auftraege/ kunden/ einstellungen/
  protokoll/[id]/           Hauptseite mit Werkzeugen, Geräten, Messungen
  protokoll/[id]/stresstest/ monitor/ iptest/ wifi/ wifikanal/
                            Werkzeuge mit Live-Anzeige — eigene Seite statt
                            Dialog, weil sie über Minuten/Stunden laufen
android/            natives Android-Projekt inkl. Kotlin-Plugin (einzige Quelle)
  NetDiagScannerPlugin.kt  alle Plugin-Methoden (Scan, Monitor, WLAN, SIP, Update,
                           Biometrie) — @PluginMethod-Namen = JS-Aufrufe
  Dns.kt / Snmp.kt / Sip.kt   eigene Protokoll-Clients (UDP/TCP), je ein
                           Ergebnistyp statt null — ein nicht erreichbarer Dienst
                           darf nie wie ein fehlerfreier aussehen
  Biometrie.kt        BiometricPrompt + Keystore (siehe „Anmeldung")
  MonitorService.kt   Foreground-Service für Dauertest und Geräte-Monitor
native-plugin/      nur noch Anleitung/Hinweise zum Plugin
tools/              Prüfwerkzeuge ohne Gerät (siehe unten)

Prüfwerkzeuge (tools/, laufen ohne Handy)

node tools/render-chart.mjs     # rendert die echten Diagramm-Komponenten
                                # nach .render/*.svg — ansehen, nicht annehmen
node tools/pruefe-monitor.mjs   # rechnet die Verfügbarkeits-Auswertung gegen
                                # konstruierte Fälle mit Handwerten durch
node tools/pruefe-kette.mjs           # Internet-Kette: Fehlerglied, Anmeldeseite
node tools/pruefe-dns.mjs             # DNS: NXDOMAIN ist KEIN Ausfall
node tools/pruefe-geraetediff.mjs     # Geräte-Vergleich, alle Fälle OHNE MAC
node tools/pruefe-geraeteaktionen.mjs # Sortierung nach Gerätetyp
node tools/pruefe-serveradresse.mjs   # http:// bei https-App abweisen
node tools/pruefe-sip.mjs             # SIP: 401/405 sind ERREICHBAR, kein Ausfall
node tools/test-recommend.mjs   # Kanalempfehlung

Warum es diese Prüfer gibt: Der Browser-Mock liefert bei Netzwerkwerkzeugen grundsätzlich den guten Fall — er gibt sogar jedem Gerät eine MAC-Adresse, die beim Kunden nie ankommt. Wer im Mock klickt, prüft den Mock. Deshalb liegt die Bewertungslogik jeweils in einer Datei ohne Laufzeit-Import (*-bewertung.ts, geraete-diff.ts, serveradresse.ts), die Node dank Type-Stripping direkt laden kann. Jeder dieser sechs Prüfer hat mindestens einen echten Fehler gefunden (Muster und Bilanz: KB #1091).

render-chart.mjs gibt es, weil die erste Fassung der WLAN-Diagramme unbemerkt unlesbar in den Einsatz ging: der Emulator hat keine WLAN-Hardware, also war nie ein gefülltes Diagramm zu sehen. SVGs mit rsvg-convert x.svg -o x.png in ein ansehbares Bild wandeln.

Neues Tool hinzufügen

  1. Datei unter src/lib/tools/<kategorie>/<id>.ts anlegen, Tool implementieren.
  2. In src/lib/tools/index.ts importieren und in TOOLS eintragen.
  3. quickRun: true setzen, wenn das Werkzeug ohne Eingabe sinnvoll startet (kurzer Tap startet dann sofort, langes Halten öffnet die Optionen). Ausdrücklich je Werkzeug entscheiden — es gibt kein required an den Parametern, die Pflicht steht allein im run()-Rumpf. portscan.ports hat keinen Vorgabewert und ist trotzdem optional, iperf.host hat ebenfalls keinen und ist Pflicht.
  4. Jeden neuen Ergebnis-Schlüssel in BEIDE Feldtabellen eintragen:
    • src/lib/messfelder.ts (App-Anzeige)
    • netdiagKundenfelder() in dolibarr-modul/netdiag/lib/netdiag.lib.php — das ist eine harte Whitelist: was dort fehlt, verschwindet im Kunden-PDF spurlos, übrig bleibt die nackte Ampel. Ebenso den Klarnamen des Werkzeugs in netdiagToolName(), sonst steht beim Kunden „[netzwerk] meintool".

Punkt 4 ist der Schritt, der hier schon zweimal vergessen bzw. geraten wurde. Beim ersten Mal wurde die Whitelist gegen selbst erfundene Testdaten gebaut, beim zweiten Mal stand 'typ' darin statt des real gelieferten 'type' — im Abnahmebeleg für eine Netzwerkdose fehlte dadurch die Angabe, ob per LAN oder WLAN gemessen wurde. Feldnamen immer aus dem erzeugenden Code ablesen, nie aus dem Kopf. (KB #1084)

Sync und Datenbank brauchen keinen Eingriff — das Ergebnis ist generisches JSON. Braucht das Tool eine neue native Messroutine: Methode im Kotlin-Plugin, Eintrag im Interface NetDiagScannerPlugin und ein Zweig im Browser-Mock (beides in src/lib/scanner.ts) — ohne Mock lässt sich nichts ohne Gerät prüfen, und ein Mock, der nur den Gutfall zeigt, bestätigt genau die Annahme, die im Feld nicht gilt (KB #1086).

Anmeldung

Die App hängt am zentralen Auth-Modul awlauth (7. AWL-App). Das Token kommt aus auth.php (Passwort) oder sso.php (AWL-Konto, siehe unten) und geht bei jeder Anfrage als Authorization: Bearer mit — auch beim APK-Download und beim PDF-Abruf. Nie in der Adresse: ein Token in der URL steht in jedem Zugriffs- und Proxy-Log und gilt sieben Tage für die gesamte Kunden-API. (Einzige, befristete Ausnahme: update.php?download=1 für App-Fassungen im Feld — siehe ChangeLog des Moduls 1.3.0.)

Mit AWL-Konto anmelden (seit Modul 1.4.0 / awlauth 1.6.0)

Knopf „Mit AWL-Konto anmelden" öffnet die awlauth-Anmeldeseite im Chrome-Tab (@capacitor/browser). Der Tab teilt sich die Anmeldung mit Chrome: wer im Handy-Browser schon angemeldet ist (PWA, ERP), ist ohne Eingabe zurück in der App. Sonst Passwort oder Fingerabdruck auf der awlauth-Seite, danach „Zurück zu NetDiag".

  • Rücksprung über das eigene Schema de.data-it-solution.netdiag:/sso?code=…&state=… — Intent-Filter im AndroidManifest.xml, Konstante SSO_REDIRECT in src/lib/sso.ts. Beide müssen übereinstimmen, und awlauth vergleicht die Adresse Zeichen für Zeichen.
  • PKCE (S256) + state: Geheimnis und state liegen bis zum Rücksprung in den Preferences (Android darf die App beenden, während der Chrome-Tab vorne ist), gelten einmal und höchstens zehn Minuten.
  • Der Rücksprung wird im Layout verarbeitet (appUrlOpen + getLaunchUrl), nicht auf der Login-Seite.
  • Fragt sso.php (GET) available:false zurück (awlauth zu alt, App dort abgeschaltet), zeigt die App den Grund; das Passwortfeld bleibt immer.

Fingerabdruck statt Passwort

Einschaltbar unter Einstellungen → Konto. Was dabei passiert:

  1. Das Sitzungs-Token wird mit einem AES-256/GCM-Schlüssel aus dem Android-Keystore verschlüsselt (setUserAuthenticationRequired), Chiffrat und IV liegen in shared_prefs/netdiag_biometrie.xml.
  2. Die Klartextfassung wird entfernt (Preferences.remove('token')). Genau das ist der Sicherheitsgewinn: vorher stand das Token offen in CapacitorStorage.xml und war auf einem entsperrten Gerät ohne Weiteres lesbar.
  3. Beim nächsten Start zeigt die Login-Maske „Mit Fingerabdruck anmelden". Der Finger entschlüsselt das Token; es bleibt danach nur im Arbeitsspeicher.

Kein zweiter Faktor — der Finger ersetzt das Passwort (Vorgabe von Eddy). Die Gültigkeit bestimmt weiterhin AWLAUTH_TTL, und „Gerät abmelden" in der awlauth-Geräteliste wirkt unverändert: hinterlegt ist dasselbe Token. Wird es serverseitig ungültig (401 mit Token), räumt die App die Hinterlegung selbst weg. Ein 401 ohne Token ist dagegen nur „noch nicht angemeldet" und lässt sie stehen — diese Unterscheidung ist nicht theoretisch: ohne sie löschte der erste Startaufruf die gerade eingerichtete Anmeldung wieder.

Wird dem Gerät ein weiterer Fingerabdruck hinzugefügt, macht Android den Schlüssel ungültig (setInvalidatedByBiometricEnrollment) — die App sagt das im Klartext und verlangt einmal das Passwort. Gewollt: sonst könnte jemand mit dem entsperrten Gerät einfach seinen eigenen Finger anlernen.

WebAuthn wie in den PWAs geht hier nicht — im Capacitor-WebView ist es nicht verlässlich verfügbar (KB #855).

Bedienung

  1. Anmelden — „Mit AWL-Konto anmelden" oder Dolibarr-Zugang (auf dem Gerät zusätzlich Server-URL).
  2. Aufträge — aktive direkt sichtbar, abgeschlossene per Checkbox, Suche. Alternativ über Kunden suchen.
  3. Auftrag/Kunde antippen → Diagnose-Protokoll öffnet sich.
  4. Werkzeuge ausführen (IP-Scan füllt die Geräteliste, je Gerät weitere Tools). Bei den meisten Karten steht „Tippen startet · Halten für Optionen": kurzer Tap startet sofort mit den zuletzt benutzten Werten, langes Halten öffnet den Parameterdialog. Nach der Messung springt die Ansicht zum frischen Ergebnis.
  5. Abschließen & synchronisieren — Protokoll geht ans Dolibarr, PDF landet im ECM. Offline bleibt es lokal und synct automatisch bei Verbindung.

Selten gebrauchte Aktionen (Protokoll löschen) liegen hinter den drei Punkten in der Kopfzeile — bewusst nicht neben dem grünen Abschließen-Knopf.

Was noch offen ist

Die Arbeitsdateien ROADMAP.md / ROADMAP_UMSETZUNG.md sind abgearbeitet und entfernt (19.08.2026). Was aus ihnen nicht erledigt war, steht hier — damit es nicht mit den Dateien verschwindet:

  • WLAN-Kanalanalyse auf echtem Empfang gegenprüfen. Der Emulator hat keine WLAN-Hardware und liefert grundsätzlich 0 Netze; alle Diagramme sind bisher nur mit Demodaten geprüft. Auf dem Handy nachfahren: Kanal am Router wechseln, zwei Momentaufnahmen vergleichen, Zeitverlauf ansehen.
  • Ortung-aus-Zweig (Android < 13). Auf einem API-33-AVD nicht erreichbar, deshalb nur per Codereview geprüft — die Meldung „Ortung ausschalten verhindert den WLAN-Scan" samt Sprung in die Systemeinstellung ist am echten Altgerät noch nie gelaufen.
  • Vorschlags-Chips im ToolDialog. Im Kopfbereich erledigt (inputmode), die Chips für häufige Werte (Gateway, letzte Ziele) fehlen weiterhin.

Dazu einer, der beim Modul liegt: die befristete ?jwt=-Ausnahme in update.php fällt, sobald die APK-Fassung ≥ 20260819-2141 überall installiert ist (Hinweis steht dort im Code und im ChangeLog 1.3.0).

Ohne Gerät prüfen

  • Browser (npm run dev): Mock-Scanner liefert Beispieldaten.
  • WLAN-Demomodus (Einstellungen → WLAN-Demodaten): 18 erfundene Netze mit allen Grenzfällen — Mesh, Co-Channel, 40 MHz im 2,4-GHz-Band, DFS, 160 MHz, Bandrand. Nötig, weil der Emulator keine WLAN-Hardware hat und jeder Scan null Netze liefert. Gespeicherte Momentaufnahmen werden als Demo gekennzeichnet.
  • Diagramme: tools/render-chart.mjs (siehe oben).