Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
4.4 KiB
Android-App (Plan, zurückgestellt)
Stand 2026-10-02. Noch nichts davon ist umgesetzt; das hier ist die Entscheidungsgrundlage für später.
Anforderungen
- PGP clientseitig: signieren, verifizieren, ver-/entschlüsseln
- private Schlüssel lokal auf dem Gerät speichern
- Push-Benachrichtigungen
- Kamera-Zugriff
Entscheidung: Capacitor
Der bestehende React-Code wird mit Capacitor als APK gebündelt. Eine native Kotlin-App ist nicht nötig; nativer Code beschränkt sich auf (fertige oder kleine eigene) Plugins.
Verworfen: PWA / Trusted Web Activity
Wäre fast ohne Umbau machbar (Manifest, Service Worker,
/.well-known/assetlinks.json, Bubblewrap), scheitert aber am PGP-Ziel:
Bei TWA/PWA liefert der Server den Code bei jedem Start neu aus. Wer den
Server kontrolliert (Angreifer, kompromittiertes PROD, Anordnung), kann
JavaScript nachschieben, das den privaten Schlüssel ausliest. Clientseitige
Kryptographie soll gerade das Vertrauen in den Server überflüssig machen.
Mit Capacitor steckt der Code signiert im APK; Updates laufen über den App-Signaturschlüssel, nicht über einen PROD-Deploy.
Verworfen: native App (Kotlin/Compose)
Kompletter Neubau des Frontends ohne Mehrwert für die Anforderungen; passt außerdem schlecht zum bewusst rohen Design, das in der Web-Version schon existiert.
Umbau Frontend
- API-Basis-URL:
frontend/src/api.tsruft fest/api…auf. Das wird konfigurierbar (z. B.import.meta.env.VITE_API_BASE), weil die App unterhttps://localhostläuft, nicht auf der Domain. - Absolute URLs: Bild-URLs aus der API und geteilte Links
(
/entry/123) müssen die Domain enthalten. - Deep Links: Android App Links für
https://<domain>/entry/…. - Routing:
createBrowserRouterfunktioniert unter Capacitor weiter.
Umbau Backend
- Bearer-Token: Der Session-Cookie (
auth.go,HttpOnly,SameSite=Lax) kommt im WebView cross-origin nicht zuverlässig an. Zweiter Login-Modus: Token im JSON-Body zurückgeben, Client schicktAuthorization: Bearer …,getSessionakzeptiert beides. Die Web-Version bleibt beim Cookie. - CORS: Middleware für
Access-Control-Allow-Originmit den App-Origins (https://localhost,capacitor://localhost) inkl. Preflight. checkOrigin(main.go): App-Origins zulassen bzw. Requests mit Bearer-Token ausnehmen. Ohne Cookie gibt es dort kein CSRF-Risiko.
PGP
- Bibliothek: OpenPGP.js im Bundle, kein nativer Code. Kommt mit der
CSP
default-src 'self'aus. - Web-Version: Derselbe Code kann dort laufen, aber mit der schwächeren Garantie (servergelieferter Code, siehe oben). Sollte in der UI kenntlich sein.
- Schlüsselablage: Der Android Keystore kann PGP-Schlüssel nicht direkt
halten (keine Curve25519/PGP-Formate, gibt Schlüssel nie heraus). Daher:
- Im Keystore liegt ein hardwaregestützter AES-Schlüssel, optional an Biometrie/PIN gebunden.
- Mit ihm wird der PGP-Private-Key verschlüsselt.
- Das Ergebnis liegt im App-Speicher. Dafür gibt es Capacitor-Plugins (Secure Storage, Biometrie); notfalls ein eigenes Plugin, ca. 100 Zeilen Kotlin. IndexedDB allein ist die schwächere Alternative (nicht hardwaregebunden, XSS-lesbar).
- Optional OpenKeychain: Über dessen OpenPGP-API (Intents) kann die App Signieren/Entschlüsseln delegieren und hält selbst nie einen Schlüssel. Eigenes Capacitor-Plugin; nur als Zusatzoption, nicht als einziger Weg.
Vorab klären (betrifft das Backend)
Signiert der Client Beiträge, muss der Server das abbilden:
- Tabelle mit öffentlichen Schlüsseln pro Account (Upload, Wechsel, Widerruf)
- Signaturfeld an
entry - API liefert Signatur und Schlüssel mit, damit andere Clients verifizieren können
Kann unabhängig von der App vorbereitet werden.
Push
- Firebase Cloud Messaging über das Capacitor-Push-Plugin.
- Backend: Tabelle für Device-Tokens pro Account, FCM-Sender.
- Inhalt nur „es gibt etwas Neues“ oder PGP-verschlüsselt, sonst liest Google mit.
Kamera
Capacitor-Kamera-Plugin; alternativ reicht <input type="file" capture>
ganz ohne Plugin.
Reihenfolge (Vorschlag)
- Backend: Bearer-Token, CORS,
checkOrigin - Frontend: API-Basis-URL, absolute URLs
- Capacitor-Projekt, APK-Build, App Links
- Kamera
- Push (FCM, Device-Tokens)
- PGP: Schlüsseltabelle/Signaturfeld im Backend, OpenPGP.js, Keystore-gestützte Ablage
- optional OpenKeychain-Plugin