first commit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
# Swyx Tab Bridge — Firefox-Add-on
|
||||
|
||||
Verwaltet Firefox-Tabs über die WebSocket-Verbindung zu SwyxTray: Tabs auslesen, öffnen
|
||||
und schließen.
|
||||
|
||||
## Rollenverteilung
|
||||
|
||||
Ein Browser-Add-on kann **keinen** WebSocket-Server betreiben — es kann nur Client sein.
|
||||
Das Add-on **verbindet sich** daher zu SwyxTray (Default `ws://127.0.0.1:17655`) und
|
||||
beantwortet die dort eintreffenden Aufträge.
|
||||
|
||||
```
|
||||
[ SwyxTray, Port 17655 ] <--- verbindet sich --- [ Firefox-Add-on: WS-Client ]
|
||||
| {"type":"tab","id":1,"action":"list"} ->
|
||||
<- {"cmd":"tabresult","id":1,"ok":true,"tabs":[…]}
|
||||
```
|
||||
|
||||
Zuständig ist das Add-on **ausschließlich für Tab-Nachrichten** (`"type":"tab"`).
|
||||
Alles andere auf der Verbindung — Telefonie-Kommandos, Events, Nachrichten an andere
|
||||
Komponenten — wird ignoriert: keine Antwort, kein Fehler.
|
||||
|
||||
## Protokoll
|
||||
|
||||
Alle Nachrichten sind JSON-Textframes. Die `id` der Anfrage wird unverändert in die
|
||||
Antwort gespiegelt; die Antwort trägt immer `"cmd":"tabresult"`.
|
||||
|
||||
### 1. Offene Tabs auslesen (`list`)
|
||||
|
||||
```json
|
||||
→ {"type":"tab","id":1,"action":"list"}
|
||||
← {"cmd":"tabresult","id":1,"ok":true,
|
||||
"tabs":[{"id":42,"title":"Kundenakte Muster GmbH","url":"https://crm.example.local/kunden/4711","active":false},
|
||||
{"id":43,"title":"Posteingang","url":"https://mail.example.local/","active":true}]}
|
||||
```
|
||||
|
||||
Optionale Felder zum Einschränken: `currentWindowOnly` (bool), `windowId` (number),
|
||||
`url` / `title` (Match-Pattern, z.B. `"*://*.example.local/*"`).
|
||||
|
||||
### 2. Tab mit mitgegebener URL öffnen (`open`)
|
||||
|
||||
```json
|
||||
→ {"type":"tab","id":2,"action":"open","url":"https://crm.example.local/kunden/4711"}
|
||||
← {"cmd":"tabresult","id":2,"ok":true,"tabId":44}
|
||||
```
|
||||
|
||||
Optionale Felder:
|
||||
|
||||
| Feld | Typ | Default | Beschreibung |
|
||||
|-------------|---------|---------|-----------------------------------------------------------------|
|
||||
| `active` | boolean | `true` | `false` = im Hintergrund öffnen |
|
||||
| `reuse` | boolean | `false` | ist die URL schon offen, wird der Tab aktiviert statt neu geöffnet (Antwort enthält dann `"reused":true`) |
|
||||
| `newWindow` | boolean | `false` | in neuem Fenster öffnen |
|
||||
| `windowId` | number | – | Zielfenster |
|
||||
| `index` | number | – | Position in der Tableiste |
|
||||
| `pinned` | boolean | `false` | angeheftet öffnen |
|
||||
|
||||
Erlaubt sind `http`, `https`, `ftp`, `file`; `javascript:`, `data:` u.ä. werden abgewiesen.
|
||||
|
||||
### 3. Tab löschen (`close`)
|
||||
|
||||
```json
|
||||
→ {"type":"tab","id":3,"action":"close","tabId":42}
|
||||
← {"cmd":"tabresult","id":3,"ok":true}
|
||||
```
|
||||
|
||||
`tabId` darf auch ein Array sein (`[42,43]`); die Antwort enthält dann `"closed":[42,43]`.
|
||||
|
||||
### Anmeldung (`hello`)
|
||||
|
||||
Direkt nach dem Verbindungsaufbau meldet sich das Add-on einmal an — immer, nicht
|
||||
nur mit Token:
|
||||
|
||||
```json
|
||||
← {"cmd":"hello","client":"swyx-tab-bridge","version":"1.0.0",
|
||||
"actions":["list","open","close","activate","focus"]}
|
||||
```
|
||||
|
||||
Ist unter *Einstellungen* ein Token gesetzt, kommt es als Feld `token` mit. Eine
|
||||
Antwort wird nicht erwartet. SwyxTray kann die Gegenstelle erst dadurch
|
||||
identifizieren und den Verbindungsaufbau protokollieren; ohne `hello` ist auf der
|
||||
Leitung nicht unterscheidbar, wer sich verbunden hat.
|
||||
|
||||
### Fehler
|
||||
|
||||
```json
|
||||
← {"cmd":"tabresult","id":5,"ok":false,"error":"Feld 'url' fehlt."}
|
||||
```
|
||||
|
||||
`error` ist ein zusätzliches Klartextfeld zur Diagnose — maßgeblich ist `"ok":false`.
|
||||
Fehlerfälle: fehlendes/ungültiges `url` bzw. `tabId`, unerlaubtes URL-Protokoll,
|
||||
unbekannte `action`, nicht existierender Tab.
|
||||
|
||||
SwyxTray wertet einen Auftrag nach 5 s ohne Antwort als gescheitert. Das Add-on bricht
|
||||
deshalb jede Aktion nach 4 s ab (`ACTION_TIMEOUT_MS` in [`background.js`](background.js))
|
||||
und antwortet dann mit `"ok":false` — es bleibt also nie stumm.
|
||||
|
||||
### Zusätzliche Aktionen
|
||||
|
||||
Über die drei SwyxTray-Aktionen hinaus versteht das Add-on:
|
||||
|
||||
```json
|
||||
→ {"type":"tab","id":4,"action":"activate","tabId":42}
|
||||
← {"cmd":"tabresult","id":4,"ok":true,"tabId":42}
|
||||
|
||||
→ {"type":"tab","id":5,"action":"focus","url":"https://crm.example.local/kunden/4711"}
|
||||
← {"cmd":"tabresult","id":5,"ok":true,"focused":true,"opened":false,"tabId":42}
|
||||
```
|
||||
|
||||
- `activate` holt einen bekannten Tab per `tabId` in den Vordergrund (inkl. Fenster).
|
||||
- `focus` sucht die passende Seite und aktiviert sie; ist sie nicht offen, wird sie
|
||||
geöffnet (`focused:false, opened:true`). Optional: `match` (`prefix` | `exact` |
|
||||
`origin`, Default `prefix`), `open:false` (nicht öffnen), `activate:false`,
|
||||
oder Suche per `title` statt `url`. Fragment (`#…`) und abschließende Slashes werden
|
||||
beim Vergleich ignoriert.
|
||||
|
||||
### Ignorierte Nachrichten
|
||||
|
||||
| Nachricht | Verhalten |
|
||||
|----------------------------------------------------|--------------------|
|
||||
| alles ohne `"type":"tab"` (z.B. `{"cmd":"call",…}`) | wird ignoriert |
|
||||
| ungültiges JSON | wird ignoriert |
|
||||
|
||||
## Installation (temporär, zum Entwickeln)
|
||||
|
||||
1. `about:debugging#/runtime/this-firefox` öffnen
|
||||
2. **„Temporäres Add-on laden…”** → `manifest.json` in diesem Ordner auswählen
|
||||
3. Server-Adresse ggf. unter *Einstellungen* im Popup anpassen (Default `ws://127.0.0.1:17655`)
|
||||
|
||||
Temporär geladene Add-ons verschwinden beim Firefox-Neustart. Für den Dauerbetrieb muss
|
||||
das Add-on signiert werden (`web-ext sign`, AMO-Account) oder es wird Firefox ESR /
|
||||
Developer Edition mit `xpinstall.signatures.required = false` verwendet.
|
||||
|
||||
Paket bauen:
|
||||
|
||||
```bash
|
||||
npx web-ext lint
|
||||
npx web-ext build # erzeugt web-ext-artifacts/*.zip -> signieren bzw. in .xpi umbenennen
|
||||
```
|
||||
|
||||
## Signierung und Datenerhebung
|
||||
|
||||
Seit dem 3. November 2025 müssen neue Erweiterungen auf AMO Mozillas eingebautes
|
||||
Einwilligungssystem bedienen. Im Manifest steht deshalb:
|
||||
|
||||
```json
|
||||
"data_collection_permissions": { "required": ["browsingActivity"] }
|
||||
```
|
||||
|
||||
Mozilla definiert Übermittlung als Daten, die *außerhalb des Add-ons oder des
|
||||
lokalen Browsers* verarbeitet werden. Das Add-on gibt Tab-Titel und URLs an
|
||||
SwyxTray weiter — also aus dem Browser heraus, wenn auch nur an eine lokale
|
||||
Anwendung auf demselben Rechner und nicht ins Netz. `"none"` wäre eine
|
||||
Untertreibung, `browsingActivity` beschreibt genau das (besuchte Seiten, URLs).
|
||||
|
||||
`strict_min_version` bleibt bewusst bei `115.0`, obwohl der Schlüssel erst ab
|
||||
Firefox 140 ausgewertet wird. Ältere Versionen ignorieren ihn folgenlos; ein
|
||||
Anheben auf `140.0` würde ESR 115 und ESR 128 ausschließen. `web-ext lint` meldet
|
||||
dafür zwei Warnungen — die blockieren die Signierung nicht.
|
||||
|
||||
## Installation auf Windows (per SSH)
|
||||
|
||||
`deploy/deploy-windows.sh` zählt die Version hoch, baut das `.xpi`, überträgt es per
|
||||
`scp` und führt `deploy/Install-SwyxTabBridge.ps1` auf dem Zielrechner aus:
|
||||
|
||||
```bash
|
||||
./deploy/deploy-windows.sh # Testrechner, ohne Parameter
|
||||
./deploy/deploy-windows.sh --keep-firefox # laufenden Firefox nicht beenden
|
||||
./deploy/deploy-windows.sh --uninstall # rückgängig machen
|
||||
```
|
||||
|
||||
Der nackte Aufruf erledigt alles: Version hochzählen, bei AMO signieren, übertragen,
|
||||
Policy schreiben und den laufenden Firefox beenden (nur den aus dem Zielverzeichnis —
|
||||
eine zweite Installation daneben bleibt offen). Ziel ist die Release-Installation, die
|
||||
ausschließlich signierte Add-ons annimmt; jeder Lauf wird deshalb signiert. Ziel-Rechner,
|
||||
Firefox-Verzeichnis sowie Signatur- und Neustart-Verhalten sind als Konstanten oben im
|
||||
Skript voreingestellt.
|
||||
|
||||
Standardmäßig wird eine Enterprise-Policy (`force_installed`) geschrieben, sodass das
|
||||
Add-on beim nächsten Firefox-Start ohne Rückfrage für alle Profile installiert wird.
|
||||
Details, Signierung und Optionen: [deploy/README.md](deploy/README.md).
|
||||
|
||||
## Tests
|
||||
|
||||
Selbsttest der Kommandoverarbeitung ohne Firefox — `background.js` läuft mit gestubbten
|
||||
`browser`-/`WebSocket`-APIs:
|
||||
|
||||
```bash
|
||||
node test-server/test-background.mjs
|
||||
```
|
||||
|
||||
Testserver, der SwyxTray simuliert (ohne Abhängigkeiten, nur Node):
|
||||
|
||||
```bash
|
||||
node test-server/server.js # lauscht auf ws://127.0.0.1:17655
|
||||
node test-server/server.js --log /pfad/x.log # anderes Protokoll
|
||||
node test-server/server.js --no-log # nur Konsole
|
||||
```
|
||||
|
||||
Der Server protokolliert Verbindungsaufbau, Anmeldung und Trennung mit Zeitstempel
|
||||
auf der Konsole **und** in `test-server/swyx-tray.log`:
|
||||
|
||||
```
|
||||
[2026-08-17 16:16:09.809] Verbindung geöffnet von 127.0.0.1.
|
||||
[2026-08-17 16:16:09.809] Angemeldet: swyx-tab-bridge v1.0.12 (Aktionen: list, open, close, activate, focus; ohne Token)
|
||||
[2026-08-17 16:16:12.314] Verbindung getrennt: swyx-tab-bridge v1.0.12 (Dauer 3 s).
|
||||
```
|
||||
|
||||
Meldet sich eine Gegenstelle binnen drei Sekunden nicht mit `hello` an, wird das
|
||||
als „unbekannte Gegenstelle" vermerkt. Das ist die Vorlage dafür, was SwyxTray
|
||||
mitschreiben sollte.
|
||||
|
||||
| Eingabe | gesendete Nachricht |
|
||||
|------------------------------------|--------------------------------------------------------|
|
||||
| `list` / `list current` | `{"type":"tab","action":"list"}` |
|
||||
| `open <url> [background]` | `{"type":"tab","action":"open","url":"…"}` |
|
||||
| `close <tabId>` | `{"type":"tab","action":"close","tabId":42}` |
|
||||
| `activate <tabId>` | `{"type":"tab","action":"activate","tabId":42}` |
|
||||
| `focus <url> [titel…]` | `{"type":"tab","action":"focus","url":"…"}` |
|
||||
| `raw {…}` | beliebiges JSON (ohne `type:"tab"` bleibt es unbeantwortet) |
|
||||
| `quit` | beenden |
|
||||
|
||||
## Einstellungen
|
||||
|
||||
Die Einstellungsseite zeigt oben, ob das Add-on mit der Tray-App verbunden ist —
|
||||
Zustand, Serveradresse, Zeitpunkt des Verbindungsaufbaus und der letzte Fehler,
|
||||
laufend aktualisiert. Dieselbe Anzeige gibt es kompakt im Popup.
|
||||
|
||||
Über das Symbol in der Symbolleiste → *Einstellungen*:
|
||||
|
||||
- **WebSocket-Server** — `ws://…` oder `wss://…` (Default `ws://127.0.0.1:17655`)
|
||||
- **Token** — optionales Shared Secret. Ist es gesetzt, geht es in der
|
||||
`hello`-Nachricht mit.
|
||||
- **Automatisch verbinden** — Auto-Reconnect mit exponentiellem Backoff (1 s → max. 30 s)
|
||||
|
||||
Das Symbol zeigt den Verbindungszustand: kein Badge = verbunden, `…` = Verbindungsaufbau,
|
||||
`!` = getrennt.
|
||||
|
||||
## Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|-----------------------------------|---------------------------------------------------|
|
||||
| `manifest.json` | Add-on-Manifest (MV2, persistenter Hintergrund) |
|
||||
| `background.js` | WebSocket-Client, Reconnect, Aktionen |
|
||||
| `popup.html/js` | Statusanzeige, Verbinden/Trennen |
|
||||
| `options.html/js` | Server-URL, Token, Auto-Connect |
|
||||
| `test-server/server.js` | Testserver (simuliert SwyxTray) |
|
||||
| `test-server/test-background.mjs` | Selbsttest der Kommandoverarbeitung |
|
||||
| `deploy/deploy-windows.sh` | Version hochzaehlen, bauen, per SSH ausrollen |
|
||||
| `deploy/Install-SwyxTabBridge.ps1`| Installation auf dem Windows-Rechner |
|
||||
|
||||
## Hinweise
|
||||
|
||||
- **Manifest V2** ist bewusst gewählt: Nur mit persistentem Hintergrundskript bleibt die
|
||||
WebSocket-Verbindung dauerhaft offen. Unter MV3 (nicht-persistente Event-Page) würde die
|
||||
Verbindung nach Leerlauf abgebaut. Firefox unterstützt MV2 weiterhin.
|
||||
- `ws://127.0.0.1` ist erlaubt (das Add-on läuft im `moz-extension:`-Kontext, keine
|
||||
Mixed-Content-Blockade). Für Verbindungen über das Netzwerk `wss://` verwenden.
|
||||
- SwyxTray sollte nur auf `127.0.0.1` lauschen — sonst kann jeder im Netz Tabs öffnen,
|
||||
schließen und die Tab-Liste mitlesen.
|
||||
- Die Permission `tabs` ist nötig, um `title` und `url` der Tabs zu lesen.
|
||||
Reference in New Issue
Block a user