Commit Graph
12 Commits
Author SHA1 Message Date
patrickandClaude Sonnet 5 3184cd352f feat: Ed25519-Request-Signing statt Bearer-Token (Security-Audit-Fix)
Security-Audit 2026-09-10 ergab: der Bearer-Token-Modus war ohne TLS im
Klartext mitschneidbar und unbegrenzt gültig/firmenweit einlösbar – ein
LAN-Sniffer hätte damit vollen Lese-/Schreibzugriff auf Mitarbeiterliste
und Zeitdaten gehabt (Finding B-1, CRITICAL). Ersetzt durch dasselbe
Ed25519-Request-Signing-Schema wie bei den Browser-PC-Terminals.

- Neuer KioskCryptoService: erzeugt/lädt Ed25519-Schlüsselpaar (Seed in
  Secure Storage, privater Schlüssel verlässt nie das Gerät), exportiert
  Public Key im OpenSSH-Format, signiert Requests (Method+Path+Timestamp+
  Nonce+Body-SHA256), passend zu backend/app/core/kiosk_security.py.
- ApiClient: Interceptor signiert jetzt jeden Request statt Bearer-Header
  zu setzen. Body wird einmalig zu exakten Bytes serialisiert (Hash und
  gesendeter Body müssen bitidentisch sein).
- EnrollmentScreen: zeigt den öffentlichen Schlüssel zum Einfügen im Portal
  ("PC-Terminal (Ed25519)"), Eingabefelder jetzt Server-URL + Geräte-ID
  statt Bearer-Token. QR-Scan-Format geändert auf {url, device_id}.
- Alte Bearer-Enrollments sind inkompatibel (anderer Secure-Storage-Key) –
  bewusst, erzwingt Re-Enrollment über den sicheren Weg. v0.2.0+13.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 15:34:40 +02:00
patrickandClaude Sonnet 5 d10b5d572d feat: QR-Login mit der Employee-App
Neuer 4. Login-Modus "QR" im LoginScreen: scannt den Token, den die
Employee-App unter "Am Kiosk anmelden" anzeigt (POST /kiosk/my-qr-token im
Haupt-Repo), meldet den Mitarbeiter per POST /kiosk/auth/qr an. Eigener
QrLoginScanScreen (rohe Token-String statt JSON wie beim Geräte-Enrollment-
QR). v0.1.11+12.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 14:53:54 +02:00
patrickandClaude Sonnet 5 5b8bfeb4b0 fix(qr-scan): R8/ProGuard zerstörte ML-Kit-Komponenten-Registrierung
Root Cause endlich gefunden (via adb-Logcat auf echtem T10-Pro-Tablet):
NICHT primär ein Hardware/CameraX-Problem, sondern R8-Minifizierung im
Release-Build ohne Keep-Regeln für ML Kit (mobile_scanner nutzt Reflection-
basierte Komponenten-Registrierung, ComponentDiscovery). Log zeigte
"NoSuchMethodException: ...BarcodeRegistrar.<init> []" → in Folge
NullPointerException beim eigentlichen Scan-Callback.

Fix: android/app/build.gradle.kts explizit isMinifyEnabled=true +
proguardFiles inkl. neuer android/app/proguard-rules.pro mit ML-Kit-Keep-
Regeln. Damit war auch der vorherige Downgrade auf mobile_scanner 5.2.3
unnötig – zurück auf ^6.0.2, funktioniert jetzt mit den Keep-Regeln
einwandfrei (auf echtem Gerät verifiziert).

Die vorherige cameraResolution/formats-Einschränkung (v0.1.8) war ein
Fehlschluss (Symptom sah nach Hardware-Inkompatibilität aus), bleibt aber
als sinnvolle Optimierung bestehen (weniger Codec-Last).

v0.1.10+11, deployed 137, release-signiert (gleicher Fingerprint).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 14:43:06 +02:00
patrickandClaude Sonnet 5 1e05f7b929 fix(qr-scan): feste Kamera-Auflösung + Retry gegen genericError auf günstiger Hardware
Auf T10-Pro-Tablet (und vermutlich ähnlicher Budget-Hardware) lieferte
CameraX bei Auto-Auflösung nur "MobileScannerErrorCode.genericError" ohne
brauchbare Details – die Kamera-HAL kommt mit der von CameraX gewählten
Default-Auflösung nicht klar. Fix: MobileScannerController jetzt mit fester
cameraResolution (1280x720) + formats: [qrCode] (weniger Codec-Last als
Auto-Erkennung aller Formate). Neuer "Mit niedrigerer Auflösung erneut
versuchen"-Button im Fehler-Screen (fällt auf 640x480 zurück) als
zusätzlicher Recovery-Pfad, falls 720p immer noch scheitert.

v0.1.8+9.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 14:15:34 +02:00
patrickandClaude Sonnet 5 7b0f0fe1fc feat: Info-Menüpunkt für Version + manuellen Update-Check
Neuer Info-Button im LoginScreen-AppBar öffnet Dialog: installierte
Version, "Jetzt prüfen"-Button ruft checkForNewerVersion() manuell auf
(nicht nur beim App-Start automatisch) und zeigt Ergebnis inline. Findet
er eine neuere Version, erscheint danach auch das normale Update-Banner.
v0.1.7+8.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 14:03:06 +02:00
patrickandClaude Sonnet 5 c5374efbd6 fix: QR-Scan-Fehler sichtbar machen (Diagnose für "An unexpected error occurred")
mobile_scanners Default-errorBuilder zeigt nur die generische Meldung ohne
Details. Eigener errorBuilder zeigt jetzt errorCode + errorDetails.message
an, damit sich das reale Problem auf dem Tablet überhaupt einordnen lässt
(z.B. Kamera-Berechtigung verweigert, Kamera nicht verfügbar, o.ä.).
Zusätzlich Fallback-Button "Zurück – manuell eintragen". v0.1.6+7.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 13:43:19 +02:00
patrickandClaude Sonnet 5 6f30e11e4e feat: In-App-Update (Download + Installer öffnen)
Portiert von timemaster-mobile v0.1.7+8: UpdateCheckService prüft
kiosk-version.txt, LoginScreen zeigt Update-Banner mit Fortschrittsbalken +
"Jetzt aktualisieren"-Button, öffnet Android-Paketinstaller direkt
(open_filex + FileProvider). Banner sitzt im LoginScreen statt StampScreen,
da das der Idle-/Ruhezustand des Kiosks ist – Stempel-Sessions sind nur
900s aktiv. REQUEST_INSTALL_PACKAGES-Permission ergänzt.

v0.1.5+6. Diese Version selbst muss noch einmal manuell installiert werden
(Feature existiert ja erst danach), ab hier sollte der Update-Button reichen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 13:39:16 +02:00
patrickandClaude Sonnet 5 be36786913 feat: QR-Code-Einrichtung (Kamera-Scan statt Token abtippen)
Neuer QrEnrollmentScanScreen (mobile_scanner) liest das JSON {url, token}
aus dem Portal-QR-Code (KioskDevicesPage → Bearer-Gerät anlegen) und füllt
EnrollmentScreen automatisch aus. Manuelle Eingabe bleibt als Fallback.
CAMERA-Permission ergänzt. v0.1.4+5, weiterhin release-signiert (gleicher
Fingerprint wie v0.1.3+4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 13:27:40 +02:00
patrickandClaude Sonnet 5 8044a90d12 feat: Wakelock + Release-Keystore-Signing
- Wakelock (wakelock_plus): Tablet-Display schläft nie ein, kein manuelles
  Entsperren vor jedem Stempeln nötig.
- Release-Build signiert jetzt mit eigenem Keystore statt Debug-Key.
  Keystore (release-keystore.jks) + key.properties liegen NUR auf dem
  Build-Rechner (236), nie im Git (siehe android/.gitignore). Fallback auf
  Debug-Signing falls key.properties fehlt (frischer Checkout ohne
  Keystore-Zugriff bricht Build nicht).
  Wichtig: storeFile-Pfad in build.gradle.kts über rootProject.file()
  aufgelöst, nicht file() – sonst relativ zum falschen Modul (app/ statt
  android/).

v0.1.3+4.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 12:16:01 +02:00
patrickandClaude Sonnet 5 cea8ba8f08 fix: Fehlerbehandlung + NFC-Session-Leak (flutter-expert-Review)
- NFC onDiscovered: try/finally um stopSession(), sonst bleibt die native
  NFC-Session bei einer Exception in _extractUid offen und jeder weitere
  Scan schlägt dauerhaft fehl (nur App-Neustart behebt es).
- Alle Login-/Stamp-Handler fangen jetzt auch generische Exceptions (nicht
  nur DioException) – sonst wirkt der Kiosk bei unerwarteter Serverantwort
  nur "eingefroren" ohne Hinweis.
- _runAction: expliziter Re-Entrancy-Guard gegen Doppel-Tap, Status-Refresh
  nach fehlgeschlagener Stempel-Aktion (kein veralteter Button-Zustand).
- ApiClient.init(): Secure-Storage-Reads einzeln try/catch, dio wird immer
  konstruiert auch wenn Keystore beim Kaltstart noch nicht bereit ist.
- main(): ApiClient.init() in try/catch – Fehler dort ließ die App vorher
  komplett schwarz bleiben (runApp() nie erreicht).

v0.1.2+3. Review von flutter-expert-Subagent, Diffs manuell gegengeprüft.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 11:55:02 +02:00
patrickandClaude Sonnet 5 7bee1c5644 fix: Build-Fehler beheben (compileSdk, nfc_manager 3.x→4.x API)
nfc_manager 3.5.1 verlangte compileSdk 31 in seinem eigenen Android-Modul,
kollidierte mit AndroidX-Transitivdeps die 33+ brauchen → Upgrade auf
nfc_manager 4.2.1 (compileSdk 36 im App-build.gradle.kts explizit gesetzt).
API hat sich geändert: isAvailable()→checkAvailability(), startSession
braucht jetzt pollingOptions, UID-Auslesen über NfcTagAndroid.from(tag).id
statt tag.data-Map. v0.1.1+2, erfolgreich auf 236 gebaut, deployed auf 137.

Nebenbefund: Gradle/Kotlin-Daemons mit -Xmx8G stapelten sich auf 236 (nur
10GB RAM) und blockierten sogar SSH – gradle.properties auf -Xmx2G gesenkt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 02:43:10 +02:00
patrickandClaude Sonnet 5 e42cae74f3 feat: TimeMaster Kiosk Grundgerüst (Login + Stempeln)
Android-Tablet-Kiosk-App, gedacht für Betrieb hinter WireGuard-VPN.
Bearer-Token-Geräte-Auth statt Ed25519-Request-Signing (siehe Backend-
Commit f4ff11a im Haupt-Repo). Ersteinrichtung (Server-URL+Token), PIN/
NFC/Listen-Login, Stempeln Ein/Aus/Pause, Heartbeat-Loop.

Bekannte Einschränkung: Android-NFC (13,56 MHz) ist inkompatibel zu den
125-kHz-EM4100-Karten der bestehenden PC-Terminals – separate Karten nötig,
siehe README.

Vollständiger Plan: /home/sysops/.claude/plans/staged-marinating-dove.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzdm3EWeNdYFUuXFRJryA1
2026-09-10 02:23:59 +02:00