Files
Kontrollverlust/notes/android.md
T

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.ts ruft fest /api… auf. Das wird konfigurierbar (z. B. import.meta.env.VITE_API_BASE), weil die App unter https://localhost lä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: createBrowserRouter funktioniert 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 schickt Authorization: Bearer …, getSession akzeptiert beides. Die Web-Version bleibt beim Cookie.
  • CORS: Middleware für Access-Control-Allow-Origin mit 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:
    1. Im Keystore liegt ein hardwaregestützter AES-Schlüssel, optional an Biometrie/PIN gebunden.
    2. Mit ihm wird der PGP-Private-Key verschlüsselt.
    3. 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)

  1. Backend: Bearer-Token, CORS, checkOrigin
  2. Frontend: API-Basis-URL, absolute URLs
  3. Capacitor-Projekt, APK-Build, App Links
  4. Kamera
  5. Push (FCM, Device-Tokens)
  6. PGP: Schlüsseltabelle/Signaturfeld im Backend, OpenPGP.js, Keystore-gestützte Ablage
  7. optional OpenKeychain-Plugin