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
79 lines
5.3 KiB
Markdown
79 lines
5.3 KiB
Markdown
# 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`](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.
|