Krisenvorrat Inventar-App – Android-App (Kotlin) zur Verwaltung eines Krisenvorrats-Inventars
Closes #96 ## App - E2EEKeyManager: Tink HPKE Schlüsselpaar generieren, privaten Key via EncryptedSharedPreferences sichern, Nachrichten verschlüsseln und entschlüsseln (X25519 + ChaCha20-Poly1305) - EnsureKeyPairUseCase: Keypair-Initialisierung beim App-Start; Public Key via HTTP PUT an Server übermitteln - MainActivity: EnsureKeyPairUseCase.execute() in onCreate - SettingsKey: E2EEPrivateKeyset + E2EEPublicKeyBase64 als SENSITIVE_KEYS - MessageRepositoryImpl: sendMessage verschlüsselt Body mit Empfänger- Public-Key; eingehende Nachrichten werden lokal entschlüsselt und als Klartext in Room gespeichert; Public-Key-Cache (in-memory) + key_updated Handler - WebSocketClient: KeyUpdated Event hinzugefügt - WebSocketClientImpl: key_updated Frame parsen; Exception-Logging - Tink 1.15.0 als neue Dependency ## Server - V4 Flyway Migration: ALTER TABLE users ADD COLUMN public_key TEXT - Tables.kt: publicKey Feld in Users-Objekt - UserRepository: getPublicKey() / setPublicKey() - UserRoutes: PUT /api/users/{id}/public-key (Auth + Owner-Check + Längenvalidierung ≤ 10.000 Zeichen) und GET /api/users/{id}/public-key - WebSocketManager: notifyKeyUpdated() Broadcast an alle anderen verbundenen Clients - MessageRepository: EncryptionService für message body bypassed – Server speichert E2EE-Ciphertext direkt (Zero-Knowledge) ## Tests - E2EEKeyManagerTest: 5 Tests (Roundtrip, Nonce-Uniqueness, Wrong-Key, hasKeyPair) - EnsureKeyPairUseCaseTest: 4 Tests (generate+upload, skip wenn vorhanden, kein Upload ohne UserId, kein Crash bei Server-Fehler) - MessageRepositoryImplTest: 5 neue E2EE-Tests ## Docs - docs/migration-guide.md: E2EE-Einschränkungen dokumentiert (Pending-Message Klartext in SQLite) ## Follow-up - #105: E2EE Private Key – AndroidKeysetManager statt CleartextKeysetHandle (Security Hardening) |
||
|---|---|---|
| .github | ||
| .vscode | ||
| Anforderungen | ||
| app | ||
| backup | ||
| docs | ||
| gradle | ||
| memories/repo | ||
| server | ||
| shared | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| build.gradle.kts | ||
| docker-compose.yml | ||
| Dockerfile | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| import-inventar.ps1 | ||
| import-inventar.py | ||
| inventar.md | ||
| README.md | ||
| run-integration-tests.ps1 | ||
| settings.gradle.kts | ||
| start-server.ps1 | ||
| start-server.sh | ||
Bollwerk
Android-App zur Verwaltung eines Bollwerks-Inventars mit lokaler Datenhaltung und Sync-Möglichkeit über einen LAN-Server.
Projektstruktur
| Modul | Beschreibung |
|---|---|
app |
Android-App (Kotlin, Jetpack Compose, Room) |
server |
Ktor REST-Server (H2-Datenbank, Fat-JAR) |
shared |
Gemeinsame DTOs (kotlinx.serialization) |
Voraussetzungen
- Android Studio oder IntelliJ IDEA
- JDK 21 (für Server) / JDK 11+ (für App)
- Android SDK (API Level 35)
App bauen
# Windows
.\gradlew assembleDebug
# Linux/Mac
./gradlew assembleDebug
Tests ausführen
# Alle Tests (App + Server)
./gradlew test
# Nur Server-Tests
./gradlew :server:test
# Nur App-Tests
./gradlew :app:test
Phase 2: Server-Setup (LAN-Sync)
Übersicht
Der Sync-Server empfängt das Inventar der App als JSON und gibt es an andere App-Instanzen im selben LAN weiter. Die Kommunikation läuft über einfaches HTTP mit API-Key-Authentifizierung.
┌──────────┐ PUT /api/inventory ┌──────────┐
│ App A │ ───────────────────────► │ Server │
│ (Upload) │ │ :8080 │
└──────────┘ └────┬─────┘
│
┌──────────┐ GET /api/inventory ┌────┴─────┐
│ App B │ ◄─────────────────────── │ Server │
│(Download)│ │ :8080 │
└──────────┘ └──────────┘
Schnellstart
Option A: Direkt starten (empfohlen für Entwicklung)
# Windows
.\start-server.ps1
# Linux/Mac
chmod +x start-server.sh
./start-server.sh
Das Skript baut automatisch das Fat-JAR und zeigt die LAN-IP an.
Option B: Manuell mit Gradle
./gradlew :server:run
Option C: Fat-JAR
# JAR bauen
./gradlew :server:buildFatJar
# Starten
java -jar server/build/libs/server.jar
Option D: Docker
# Image bauen
docker build -t bollwerk-server .
# Container starten
docker run -d \
--name bollwerk \
-p 8080:8080 \
-e BOLLWERK_API_KEY="mein-sicherer-api-key" \
-v bollwerk-data:/app/data \
bollwerk-server
LAN-Setup
-
Server-IP ermitteln:
- Windows:
ipconfig→ IPv4-Adresse des WLAN/LAN-Adapters - Linux/Mac:
ip addroderifconfig - Die Start-Skripte zeigen die IP automatisch an
- Windows:
-
Firewall-Regel: Port 8080 (TCP eingehend) muss freigeschaltet sein:
- Windows:
netsh advfirewall firewall add rule name="Bollwerk" dir=in action=allow protocol=TCP localport=8080 - Linux:
sudo ufw allow 8080/tcp
- Windows:
-
App konfigurieren:
- Einstellungen → Server-URL:
http://<SERVER-IP>:8080 - Einstellungen → API-Key: den gleichen Key wie beim Server-Start
- Einstellungen → Server-URL:
API-Endpunkte
| Methode | Pfad | Auth | Beschreibung |
|---|---|---|---|
| GET | /api/health |
– | Health-Check, gibt "OK" zurück |
| GET | /api/inventory |
API-Key | Inventar vom Server laden (Pull) |
| PUT | /api/inventory |
API-Key | Inventar auf Server speichern (Push) |
Authentifizierung: API-Key als X-API-Key-Header oder Bearer-Token.
Umgebungsvariablen
| Variable | Standard | Beschreibung |
|---|---|---|
BOLLWERK_API_KEY |
change-me-to-a-secure-key-at-least-32-chars |
API-Key für Auth |
Sicherheitshinweise
- Der Dev-Server nutzt HTTP (kein HTTPS) – nur im vertrauenswürdigen LAN verwenden.
- Für Produktionseinsatz: HTTPS mit Reverse-Proxy (z.B. nginx/Caddy) konfigurieren.
- API-Key sollte mindestens 32 Zeichen lang sein.