diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..849ddff --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8de2519..7482b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,61 @@ Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/). Die Erweiterungsversion (`manifest.json`) ist unabhängig von der OpenNIT-Serverversion. +## [Unreleased] + +## [2.5.0] - 2026-07-31 + +### Hinzugefügt +- **Einträge bearbeiten und löschen:** In der Detailansicht gibt es jetzt „Bearbeiten" und „Löschen". + Beim Bearbeiten bleibt das Passwortfeld leer – wer es leer lässt, behält das gespeicherte Passwort; + 2FA-Secret und Ordner bleiben unangetastet. Für Team-Einträge greift das Schreibrecht des Teams. +- **Passwort-Generator einstellbar:** Länge (12–48) und Sonderzeichen lassen sich beim Anlegen wählen – + hilfreich bei Seiten, die Sonderzeichen ablehnen. +- **2FA-Code wird für den nächsten Schritt bereitgelegt:** Nach dem Ausfüllen eines Eintrags mit 2FA + landet beim nächsten 2FA-Feld automatisch ein **frischer** Code in der Zwischenablage – auch dann, + wenn die Abfrage erst auf einer Folgeseite kommt (z. B. Microsoft-Anmeldung). Einfügen genügt mit + Strg + V; der bisherige Inhalt der Zwischenablage wird dabei überschrieben und der Code nach 30 + Sekunden wieder entfernt. Abschaltbar unter „Sicherheit → 2FA-Code beim Anmelden bereitlegen". + +### Sicherheit +- **Passwort für mehrstufige Logins nicht mehr auf der Festplatte:** Verteilt eine Anmeldung Benutzername + und Passwort auf zwei Schritte, wurde das Passwort bisher im lokalen Speicher der Erweiterung abgelegt – + und blieb dort liegen, wenn der zweite Schritt nie erreicht wurde. Es wird jetzt nur noch im Arbeits- + speicher gehalten, an den jeweiligen Tab gebunden und nach 30 Sekunden bzw. beim Sperren verworfen. +- **Warnung bei fremder Domain greift zuverlässiger:** Ein Eintrag für `vpn.firma.de` galt auf `firma.de` + fälschlich als passend, sodass die Warnung ausblieb. Zuordnung und Warnung nutzen jetzt dieselbe Regel: + nur die hinterlegte Adresse selbst und deren Unteradressen gelten als passend. +- **Weniger Berechtigungen:** `scripting` und `activeTab` werden nicht mehr angefordert – beide wurden + nicht benötigt. +- **Passwort-Generator:** Der Zufall für die Mischreihenfolge wird jetzt getrennt von der Zeichenauswahl + gezogen, und die Zeichenwahl ist gleichverteilt. +- Notizen werden beim Kopieren wie andere Geheimnisse behandelt und nach 30 Sekunden aus der + Zwischenablage entfernt. + +### Geändert +- **Benutzername immer sichtbar:** Das Auge zum Ausblenden des Benutzernamens in der Detailansicht ist + entfallen – ein Benutzername ist kein Geheimnis. Das Passwort bleibt weiterhin maskiert. +- **Vorschläge weichen der Seite:** Sobald in ein Feld getippt wird, verschwindet die Vault-Liste – + darunter erscheint typischerweise die Suche der Seite selbst. Bei Feldern, die erkennbar eine eigene + Auswahlliste öffnen (etwa Benutzer-Auswahlfelder), erscheinen gar keine Vault-Vorschläge mehr. + Ausdrücklich als Anmeldefeld ausgezeichnete Felder sind davon ausgenommen. +- **Anmeldung nur noch per SSO:** Das Feld für den manuell erzeugten API-Token samt „Verbindung testen" + ist aus den Einstellungen entfernt. Die Verbindung entsteht ausschließlich über „Mit OpenNIT anmelden". + Ein aus einer früheren Version übernommener Token wird beim Update aus dem lokalen Speicher gelöscht; + wer bisher nur damit verbunden war, meldet sich einmal per SSO an. + +### Behoben +- **Restlaufzeit des 2FA-Codes wird wieder korrekt angezeigt:** Der Countdown blieb am Ende eines + Zeitfensters stehen und lief mit der Zeit aus dem Takt. Er rechnet nun gegen den tatsächlichen + Ablaufzeitpunkt und holt den neuen Code beim Wechsel genau einmal nach. Lässt sich kein neuer Code + laden (Tresor gesperrt oder Verbindung weg), zeigt die Anzeige das an, statt auf einem abgelaufenen + Wert stehen zu bleiben. +- **Neuen Eintrag anlegen funktioniert wieder nach SSO-Anmeldung:** Das Speichern eines im Popup + erzeugten Passworts brach bisher mit „Nicht konfiguriert." ab, wenn die Erweiterung über + „Mit OpenNIT anmelden" verbunden war – es wurde ausschließlich der manuelle Token akzeptiert. + Das Anlegen nutzt nun denselben Zugang wie alle übrigen Aufrufe (inkl. automatischer + Token-Erneuerung). Ist der Tresor gesperrt, erscheint die PIN-Abfrage statt einer Fehlermeldung. + ## [2.4.0] - 2026-07-01 ### Hinzugefügt diff --git a/PRIVACY.md b/PRIVACY.md index 825b1e8..31a5a69 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -17,7 +17,7 @@ technisches Client-Werkzeug ohne eigenen Server. | Datum | Zweck | Speicherort | |-------|-------|-------------| | **Server-URL** | Adresse deiner OpenNIT-Instanz | lokal (`chrome.storage.local`) | -| **API-Token** | Authentifizierung gegenüber deiner Instanz | lokal (`chrome.storage.local`) | +| **Sitzungstoken** | Authentifizierung gegenüber deiner Instanz (per SSO ausgestellt) | lokal (`chrome.storage.local`) | | **Einstellungen** (PIN-Sperrdauer, Zwischenablage-Option) | Verhalten der Erweiterung | lokal (`chrome.storage.local`) | | **Entsperr-Status** | Merkt, ob die PIN-Sperre entsperrt ist | Sitzungsspeicher (`chrome.storage.session`, wird beim Schließen des Browsers gelöscht) | | **Tresor-Einträge** (Titel, Benutzername, URL, Notizen, ob 2FA vorhanden) | Anzeige & Suche | flüchtig im Arbeitsspeicher (max. 5 Min zwischengespeichert) | @@ -30,7 +30,7 @@ Die Erweiterung erstellt **keine** Nutzungsprofile und protokolliert **kein** Su - Es werden Daten **ausschließlich** an die von dir eingetragene **OpenNIT-Server-URL** übertragen (verschlüsselt via HTTPS, sofern deine Instanz HTTPS nutzt). -- Übertragen werden: der API-Token (zur Authentifizierung), die aktuelle Seiten-Adresse (zum Finden +- Übertragen werden: der Sitzungstoken (zur Authentifizierung), die aktuelle Seiten-Adresse (zum Finden passender Einträge), sowie beim Anlegen neuer Einträge die von dir eingegebenen Felder. - Es erfolgt **keine** Übermittlung an Anthropic, Google (außer der Chrome-Sync deines eigenen Browsers, falls du ihn aktiviert hast) oder sonstige Dritte. @@ -42,7 +42,7 @@ Siehe [`docs/PERMISSIONS.md`](docs/PERMISSIONS.md). Kurz: - **Zugriff auf alle Websites** (`host_permissions: `): nötig, um Login-Felder auf beliebigen Seiten zu erkennen und auf Wunsch auszufüllen. Es werden **keine** Seiteninhalte gelesen oder übertragen, außer den zum Ausfüllen nötigen Formularfeldern – und diese verlassen den Browser nicht. -- **storage**: lokale Speicherung von URL, Token und Einstellungen. +- **storage**: lokale Speicherung von URL, Sitzungstoken und Einstellungen. - **scripting / activeTab**: Einfügen der Zugangsdaten in das aktive Tab-Formular. - **alarms / offscreen**: automatisches Leeren der Zwischenablage nach dem Kopieren. @@ -53,7 +53,7 @@ Zwischenablage entfernt. ## 6. Speicherdauer -- Server-URL, Token und Einstellungen bleiben lokal gespeichert, bis du sie änderst oder die Erweiterung +- Server-URL, Sitzungstoken und Einstellungen bleiben lokal gespeichert, bis du sie änderst oder die Erweiterung entfernst. - Zwischengespeicherte Einträge werden spätestens nach 5 Minuten bzw. beim Sperren verworfen. - Passwörter/2FA-Codes werden nicht dauerhaft gespeichert. @@ -62,7 +62,7 @@ Zwischenablage entfernt. Da die eigentliche Datenverarbeitung in deiner OpenNIT-Instanz stattfindet, richten sich Auskunfts-, Lösch- und Berichtigungsrechte an deren Betreiber. Lokale Daten der Erweiterung entfernst du durch -Deinstallieren der Erweiterung oder Löschen des Tokens in den Einstellungen. +Deinstallieren der Erweiterung oder „Abmelden" in den Einstellungen. ## 8. Kontakt @@ -78,7 +78,7 @@ eine erreichbare Kontaktadresse ergänzen. **Controller.** The operator of the OpenNIT instance you connect to. The extension itself has no server. -**Data processed.** Server URL, API token and settings (stored locally); unlock state (session storage, +**Data processed.** Server URL, session tokens and settings (stored locally); unlock state (session storage, cleared when the browser closes); vault entry metadata (title, username, URL, notes, whether 2FA exists – cached in memory for up to 5 minutes); passwords/2FA codes (fetched **only** at the moment of use, never stored permanently); the active tab URL (to find matching entries). @@ -96,4 +96,4 @@ browser. See [`docs/PERMISSIONS.md`](docs/PERMISSIONS.md). within 5 minutes; secrets are never stored persistently. **Your rights.** Because processing happens in your OpenNIT instance, direct data-subject requests to its -operator. Remove local extension data by uninstalling the extension or clearing the token. +operator. Remove local extension data by uninstalling the extension or signing out in the settings. diff --git a/README.md b/README.md index a0a531c..f88f24d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,10 @@ deiner selbst gehosteten OpenNIT-Instanz und bietet: - 👁️ **Detailansicht** mit Anzeigen/Kopieren von Zugangsdaten und 2FA-Code mit Countdown - ➕ **Neue Einträge anlegen** inkl. **Passwort-Generator** - 🔒 **PIN-Sperre** mit demselben PIN wie der Web-Tresor (Dauer frei wählbar, bis „bis Browser schließt") +- ✏️ **Anlegen, Bearbeiten und Löschen** von Einträgen direkt im Popup - 🧹 **Zwischenablage-Auto-Clear** nach dem Kopieren von Geheimnissen +- 📋 **2FA-Code bereitgelegt:** nach dem Ausfüllen landet beim nächsten 2FA-Feld – auch auf einer + Folgeseite – automatisch ein frischer Code in der Zwischenablage (Strg + V genügt) - 🖼️ **Favicons** der hinterlegten Seiten (serverseitig gecacht – keine externen Aufrufe) - 🌙 **Heller & dunkler Modus** (folgt dem System) @@ -37,19 +40,18 @@ Die Erweiterung ist ein reiner **Client** zu deiner OpenNIT-Instanz. Sie enthäl und **keinen** Remote-Code – alle Skripte sind im Paket enthalten. Kommuniziert wird ausschließlich mit dem von dir konfigurierten OpenNIT-Server über dessen REST-API (`/api/vault/extension/...`) per **Bearer-Token**. -- Die Anmeldung erfolgt per **SSO** („Mit OpenNIT anmelden"). Die Erweiterung erhält dabei automatisch - ein kurzlebiges, rotierendes Zugriffstoken – ein manuelles Erzeugen von Tokens im Web-Tresor entfällt. +- Die Anmeldung erfolgt ausschließlich per **SSO** („Mit OpenNIT anmelden"). Die Erweiterung erhält dabei + ein kurzlebiges, rotierendes Zugriffstoken – ein manuelles Erzeugen von Tokens entfällt. - Passwörter werden **serverseitig** ver-/entschlüsselt; die Erweiterung fordert das Klartext-Passwort eines Eintrags erst **im Moment des Ausfüllens/Kopierens** an – nicht beim Laden der Liste. - Es findet **keine** Ende-zu-Ende-Entschlüsselung im Browser statt; die Erweiterung speichert keine - Passwörter dauerhaft (nur Server-URL, Token und Einstellungen in `chrome.storage`). + Passwörter dauerhaft (nur Server-URL, Sitzungstoken und Einstellungen in `chrome.storage`). Details: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) · Berechtigungen: [`docs/PERMISSIONS.md`](docs/PERMISSIONS.md) -> **Anmeldung per SSO (Standard):** „Mit OpenNIT anmelden" (OAuth 2.0 + PKCE) – Anmeldung wie an OpenNIT -> (lokal + 2FA / M365 / Keycloak), automatische Token-Erneuerung mit Rotation. Ein manuell erzeugter Token -> ist nur noch als „Erweitert"-Fallback in den Erweiterungs-Einstellungen vorgesehen; OpenNIT bietet dafür -> im Frontend keine Token-Erzeugung mehr an. Konzept/Details: [`docs/SSO-PLAN.md`](docs/SSO-PLAN.md). +> **Anmeldung per SSO:** „Mit OpenNIT anmelden" (OAuth 2.0 + PKCE) – Anmeldung wie an OpenNIT +> (lokal + 2FA / M365 / Keycloak), automatische Token-Erneuerung mit Rotation. Einen manuell eingetragenen +> API-Token unterstützt die Erweiterung nicht mehr. ## Installation @@ -80,9 +82,10 @@ Repository gedacht. | Einstellung | Beschreibung | |--------------------|--------------| | **Server-URL** | Adresse deiner OpenNIT-Instanz, ohne abschließenden Slash (`https://…`). | -| **Anmeldung** | Per **SSO** („Mit OpenNIT anmelden"). Ein manueller API-Token ist nur als „Erweitert"-Fallback vorgesehen. | +| **Anmeldung** | Ausschließlich per **SSO** („Mit OpenNIT anmelden"). | | **PIN-Sperre** | Aus / 5 Min / 15 Min / 1 Std / bis der Browser geschlossen wird. Nutzt den **Tresor-PIN**. | | **Zwischenablage** | Nach 30 s automatisch leeren (Standard: an). | +| **2FA bereitlegen** | Frischen 2FA-Code beim nächsten 2FA-Feld in die Zwischenablage legen (Standard: an). | ## Build / Paketierung diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d2f2bfc..1b05bf7 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -16,7 +16,7 @@ Die Erweiterung ist ein **Manifest-V3-Client** ohne eigenen Server. Sie besteht └───────────────┘ └──────────┬───────────┘ │ CLIP_WRITE ┌────────▼─────────┐ - │ offscreen.html │ (Zwischenablage leeren) + │ offscreen.html │ (Zwischenablage schreiben/leeren) └──────────────────┘ ``` @@ -27,8 +27,9 @@ Die Erweiterung ist ein **Manifest-V3-Client** ohne eigenen Server. Sie besteht | `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, Token, PIN-Sperrdauer, Zwischenablage. | -| `offscreen.html` / `offscreen.js` | Minimaldokument, das ausschließlich die Zwischenablage leert (MV3-konform). | +| `options.html` / `options.js` | Einstellungen: Server-URL, SSO-Anmeldung, PIN-Sperrdauer, Zwischenablage. | +| `offscreen.html` / `offscreen.js` | Minimaldokument, das ausschließlich die Zwischenablage beschreibt bzw. leert (MV3-konform). | +| `urlmatch.js` | Gemeinsame Zuordnung Eintrag ↔ Seite (`VaultUrl`), geladen in allen drei Kontexten – damit Vorschlagsliste und Sicherheitswarnung dieselbe Regel anwenden. | ## Nachrichten (Auszug) @@ -38,9 +39,12 @@ Die Erweiterung ist ein **Manifest-V3-Client** ohne eigenen Server. Sie besteht | `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` / `UPDATE_ENTRY` / `DELETE_ENTRY` | popup → bg | Eintrag anlegen / ändern / löschen | +| `SET_PENDING_FILL` / `TAKE_PENDING_FILL` | content → bg | Passwort für den zweiten Login-Schritt hinterlegen bzw. abholen (nur im Speicher, je Tab) | | `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 | +| `CLIP_WRITE` | content → bg | In die Zwischenablage schreiben, wenn die Seite selbst keinen Zugriff bekommt | ## Server-API (in OpenNIT) @@ -51,6 +55,8 @@ Alle Endpunkte unter `/api/vault/extension/` mit `Authorization: Bearer ` - `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 +- `POST /entries/{id}` – Eintrag ändern (leeres Passwortfeld = unverändert) +- `POST /entries/{id}/delete` – Eintrag löschen - `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) @@ -74,5 +80,7 @@ Fensterdauer fest; „Bis der Browser geschlossen wird" nutzt ein langes Serverf - **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, Token, Einstellungen in `chrome.storage`. +- **Kein persistentes Secret** – nur URL, Sitzungstoken, Einstellungen in `chrome.storage`. Das Passwort + für einen mehrstufigen Login liegt ausschließlich im Speicher des Service Workers (je Tab, 30 s), + nie in `chrome.storage`, das auf die Festplatte geschrieben würde. - **Server-seitige Krypto** – Ver-/Entschlüsselung im OpenNIT-Server, nicht im Browser. diff --git a/docs/PERMISSIONS.md b/docs/PERMISSIONS.md index 1114260..1262ee6 100644 --- a/docs/PERMISSIONS.md +++ b/docs/PERMISSIONS.md @@ -16,15 +16,6 @@ Browser nicht. Es findet kein Tracking und keine Analyse statt. **Warum:** Das In-Seite-Dropdown mit Vorschlägen und die Felderkennung laufen als Content-Script. Notwendig für Autofill und die 2FA-Erkennung (inkl. Shadow-DOM und mehrstufiger Logins). -## `scripting` - -**Warum:** Werte werden über den nativen Value-Setter gesetzt und Events ausgelöst, damit auch -React/Vue/Angular-Formulare die Eingaben übernehmen. - -## `activeTab` - -**Warum:** Zugriff auf den aktiven Tab beim Ausfüllen aus dem Popup („Auf dieser Seite ausfüllen"). - ## `storage` **Warum:** Lokale Speicherung von Server-URL, Zugriffstoken (per SSO) und Einstellungen; Entsperr-Status in @@ -38,7 +29,8 @@ Einträge-Caches (5 Min). ## `offscreen` **Warum:** In Manifest V3 hat der Service Worker keinen DOM-Zugriff. Zum programmatischen Leeren der -Zwischenablage wird ein kurzlebiges Offscreen-Dokument (Reason `CLIPBOARD`) genutzt. +Zwischenablage wird ein kurzlebiges Offscreen-Dokument (Reason `CLIPBOARD`) genutzt – sowohl zum +Bereitlegen eines 2FA-Codes als auch zum anschließenden Leeren. ## `identity` @@ -48,6 +40,10 @@ OpenNIT-Login-Seite und empfängt die Weiterleitung an `https://.c ## Bewusst NICHT angefordert +- **`scripting` / `activeTab`** – nicht nötig: Das Content-Script wird über `content_scripts` geladen, + das Ausfüllen aus dem Popup läuft über eine Nachricht an das bereits laufende Script. Der Zugriff auf + den aktiven Tab ist bereits durch `host_permissions` abgedeckt. + - **`tabs`** – entfällt: Die aktive Tab-Adresse ist bereits über `host_permissions` verfügbar. Dadurch erscheint **keine** „Browserverlauf lesen"-Warnung. - Keine `cookies`, `history`, `webRequest`, `downloads`, `notifications` o. Ä. diff --git a/extension/LICENSE.txt b/extension/LICENSE.txt new file mode 100644 index 0000000..c382718 --- /dev/null +++ b/extension/LICENSE.txt @@ -0,0 +1,17 @@ +OpenNIT Vault – Browser-Erweiterung +Copyright (C) 2025 Friederich Loheide + +Dieses Programm ist freie Software: Sie koennen es unter den Bedingungen +der GNU Affero General Public License, Version 3, weitergeben und/oder +veraendern. + +Die Veroeffentlichung erfolgt in der Hoffnung, dass es nuetzlich ist, +jedoch OHNE JEDE GEWAEHRLEISTUNG - sogar ohne die implizite Gewaehr- +leistung der Marktreife oder der Eignung fuer einen bestimmten Zweck. +Einzelheiten regelt die GNU Affero General Public License. + +Lizenztext: https://www.gnu.org/licenses/agpl-3.0.html +Quelltext: https://opennit.de + +Der vollstaendige Lizenztext liegt der OpenNIT-Installation als Datei +LICENSE bei und kann ueber die oben genannte Adresse bezogen werden. diff --git a/extension/manifest.json b/extension/manifest.json index cae0877..8b25f90 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -3,6 +3,7 @@ "name": "OpenNIT Vault", "version": "2.4.1", "description": "OpenNIT Vault – Passwort-Manager mit Autofill für Benutzer-, Passwort- und 2FA-Felder direkt im Browser.", + "homepage_url": "https://opennit.de", "permissions": [ "storage", "activeTab", diff --git a/extension/urlmatch.js b/extension/urlmatch.js new file mode 100644 index 0000000..c835b08 --- /dev/null +++ b/extension/urlmatch.js @@ -0,0 +1,63 @@ +'use strict'; + +/* + * Gemeinsame Zuordnung Eintrag ↔ Seite. + * + * Wird in allen drei Kontexten geladen (Service Worker via importScripts, + * Popup via