OpenNIT-Vault-Extension/docs/ARCHITECTURE.md
Claude 18f68d68ea
2FA-Restlaufzeit korrigiert, manuellen API-Token entfernt
Countdown des 2FA-Codes: Die Anzeige zaehlte blind im Sekundentakt
herunter und lief dadurch aus dem Takt. Am Ende eines Zeitfensters wurde
zwar ein neuer Code angefordert, der Zaehler aber nicht angehalten - bei
langsamer oder fehlschlagender Antwort lief er ins Negative und stiess
jede Sekunde eine weitere Anfrage an (inkl. Audit-Eintrag je Abruf),
waehrend die Anzeige auf dem alten Wert stehenblieb.

Die Restlaufzeit wird jetzt aus einem festen Ablaufzeitpunkt berechnet,
sodass gedrosselte oder ausgefallene Ticks sie nicht verschieben. Pro
Ablauf wird genau einmal nachgeladen; liefert der Server keinen Code
mehr (gesperrt/offline), stoppt der Timer und die Anzeige wird geleert.
Dieselbe Rechnung gilt fuer die Benachrichtigung im Seiteninhalt; die
Periode steckt dort wie im Popup in einer Konstanten statt als 30 im
Ausdruck.

Manueller API-Token: Eingabefeld, "Token speichern" und "Verbindung
testen" sind aus den Optionen entfernt; die Server-URL laesst sich
weiterhin separat speichern. getAccessToken() kennt nur noch den
SSO-Weg, und ein aus einer frueheren Version uebernommener Token wird
bei onInstalled aus chrome.storage.local geloescht. Doku und
Store-Listing entsprechend angepasst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G12DRMpe4UjYDwuRU1sjy1
2026-07-31 12:53:34 +00:00

5.3 KiB
Raw Blame History

Architektur

Überblick

Die Erweiterung ist ein Manifest-V3-Client ohne eigenen Server. Sie besteht aus vier Kontexten, die über chrome.runtime-Nachrichten kommunizieren:

┌───────────────┐   Messages    ┌──────────────────────┐   HTTPS/Bearer   ┌──────────────────┐
│  popup.html   │ ───────────▶  │  background.js       │ ───────────────▶ │  OpenNIT-Server  │
│  popup.js     │ ◀───────────  │  (Service Worker)    │ ◀─────────────── │  /api/vault/...  │
└───────────────┘               │  - Cache (5 Min)     │                  └──────────────────┘
┌───────────────┐   Messages    │  - Lock-Gate         │
│  content.js   │ ───────────▶  │  - Favicon-Cache     │
│ (jede Seite)  │ ◀───────────  │  - Clipboard-Timer   │
└───────────────┘               └──────────┬───────────┘
                                           │ CLIP_WRITE
                                  ┌────────▼─────────┐
                                  │  offscreen.html  │  (Zwischenablage leeren)
                                  └──────────────────┘

Komponenten

Datei Rolle
background.js Zentrale Logik: API-Aufrufe, 5-Minuten-Cache, Lock-Gate, Favicon-Cache (Data-URLs), Zwischenablage-Timer. Alle Secrets fließen hier durch.
content.js Wird auf jeder Seite ausgeführt. Erkennt Benutzer-/Passwort-/OTP-Felder (inkl. Shadow-DOM, mehrstufige Logins, segmentierte OTP-Felder), zeigt das Vorschlags-Dropdown und füllt Felder framework-kompatibel (React/Vue/Angular).
popup.html / popup.js Toolbar-Popup: Liste, Suche, Detailansicht, Anlegen + Generator, PIN-Schirm.
options.html / options.js Einstellungen: Server-URL, SSO-Anmeldung, PIN-Sperrdauer, Zwischenablage.
offscreen.html / offscreen.js Minimaldokument, das ausschließlich die Zwischenablage leert (MV3-konform).

Nachrichten (Auszug)

Typ Von → Nach Zweck
CHECK_STATUS popup/content → bg Token prüfen, App-Name/User, pin_enabled
GET_LOCK / DO_UNLOCK / LOCK_NOW popup → bg PIN-Sperre abfragen/entsperren/sperren
GET_ENTRIES / GET_MATCHING_ENTRIES popup/content → bg Einträge (alle / passend zur URL)
GET_PASSWORD / GET_TOTP popup/content → bg Secret on demand
CREATE_ENTRY popup → bg Neuen Eintrag anlegen
GET_FAVICON popup/content → bg Favicon als Data-URL (serverseitig gecacht)
VAULT_FILL popup → content Aktives Tab-Formular ausfüllen
SCHEDULE_CLIP_CLEAR popup/content → bg Zwischenablage-Leerung planen

Server-API (in OpenNIT)

Alle Endpunkte unter /api/vault/extension/ mit Authorization: Bearer <token>:

  • GET /entries Liste (Titel, Benutzer, URL, Notizen, has_totp, favicon_domain, has_favicon)
  • GET /entries/{id}/password Passwort (protokolliert im Audit-Log)
  • GET /entries/{id}/totp aktueller TOTP-Code + Restsekunden
  • GET /entries/{id}/favicon?fetch=1 gecachtes Favicon (bei Bedarf serverseitig geholt)
  • POST /entries neuen Eintrag anlegen
  • GET /status Token gültig? + pin_enabled / pin_lock_secs
  • POST /unlock Tresor-PIN verifizieren + serverseitiges Entsperr-Fenster für den Token setzen
  • POST /lock Token sofort wieder sperren (Entsperr-Fenster zurücksetzen)
  • GET /oauth/authorize · POST /oauth/authorize SSO-Anmeldung/Zustimmung (Session, PKCE)
  • POST /oauth/token Authorization-Code- bzw. Refresh-Grant (öffentlich, PKCE) → Access/Refresh
  • POST /oauth/revoke Refresh-Kette widerrufen (Logout)

Details zum SSO-Flow: SSO-PLAN.md. Die Erweiterung nutzt SSO über chrome.identity; Access-Tokens werden im Hintergrund still per Refresh (mit Rotation) erneuert.

Lock-Gate (serverseitig erzwungen)

Ist für den Nutzer ein Tresor-PIN aktiv, liefern die Server-Endpunkte für Einträge/Passwort/TOTP erst nach frischer PIN-Entsperrung Daten (unlocked_until pro Token) und antworten sonst mit HTTP 423. Der Client spiegelt den Zustand nur (PIN-Schirm) die eigentliche Durchsetzung liegt im Server, damit ein gestohlener Token allein wertlos ist. Der Client hält seinen Entsperr-Status zusätzlich in chrome.storage.session (verfällt beim Schließen des Browsers). Die Einstellung „PIN-Sperre" legt nur die Fensterdauer fest; „Bis der Browser geschlossen wird" nutzt ein langes Serverfenster + Client-Sitzungsende.

Sicherheitsprinzipien

  • Kein Remote-Code alle Skripte im Paket (MV3-CSP-konform, keine Inline-Skripte).
  • Secrets on demand Passwörter/TOTP erst bei Nutzung, nie in der Liste.
  • Kein persistentes Secret nur URL, Sitzungstoken, Einstellungen in chrome.storage.
  • Server-seitige Krypto Ver-/Entschlüsselung im OpenNIT-Server, nicht im Browser.