Ich betreibe ein kleines Forum und drei weitere Websites, und mir ist immer wieder dasselbe aufgefallen. Die Leute waren bereit, im Chat zu plaudern, sobald sie auf dem Forum waren, aber niemand geht auf ein Forum, um eine kurze Frage zu stellen. Sie stellen sie dort, wo sie sich gerade befinden, oder sie stellen sie gar nicht erst.
Deshalb habe ich ein Plugin entwickelt, das den Chat des Forums auf diese anderen Websites bringt. Ein einzelnes Skript-Tag, und es erscheint eine Blase in der Ecke. Besucher melden sich mit ihrem bestehenden Forum-Konto über den eigenen Login-Bildschirm des Forums an und chatten in denselben Kanälen, die sie auch auf dem Forum sehen würden. Die Nachrichten, die sie senden, erscheinen im Chat des Forums wie jede andere Nachricht auch, denn genau das sind sie.
Repository: GitHub - capodieci/discourse-chat-bridge: Allows to install discourse chat as a plugin in other websites · GitHub (MIT)
<script src="https://forum.example.com/chat-bridge/widget.js"
data-site-key="your-site-key" defer></script>
Warum es ein Plugin ist und kein Dienst
Ich begann damit, eine externe Brücke zu entwerfen, die über die API mit Discourse kommunizieren sollte. Dann las ich den Quellcode. Das änderte das Design vollständig, und die Gründe könnten für jeden nützlich sein, der etwas Ähnliches in Betracht zieht.
Das Chat-Plugin registriert genau einen feingranularen API-Scope: create_message. Alles über das Posten hinaus – also das Lesen von Kanälen, das Abrufen des Verlaufs oder das Öffnen einer Direktnachricht – benötigt einen globalen Scope-Schlüssel. Ein globaler Scope-Schlüssel für jeden Benutzer ist ein großer Haufen an Zugangsdaten, die verwaltet werden müssen. Die Standard-Ratenlimits betragen 60 Anfragen pro Minute im Admin-Bucket und 20 im User-Bucket, was ein Chat-Client ohne großen Aufwand aufbraucht. Und die Chat-Webhooks tragen vier Nachrichtenevents und nichts anderes, daher sind Reaktionen, Präsenzstatus und Lesezustand schlicht nicht verfügbar, um sie weiterzuleiten.
All diese Probleme verschwinden, wenn der Code innerhalb von Discourse läuft und Guardian direkt fragen kann. Keine Schlüssel, kein Ratenlimit-Dach und eine einzige Quelle der Wahrheit statt eines Caches, der mit dem Forum nicht übereinstimmen kann.
Was funktioniert
Kanäle, Nachrichtenverlauf, Senden, Direktnachrichten mit Personensuche und Sprachnachrichten, die im Browser aufgenommen werden. Sprachnachrichten erscheinen für Mitglieder, die den eigenen Chat des Forums lesen, als normaler Audioplayer und nicht als Download-Link. Dafür war etwas Sorgfalt nötig.
Jede Website erhält ihre eigene Akzentfarbe, Ecke und Panel-Titel, damit drei Websites wie drei verschiedene Produkte aussehen und nicht wie drei Kopien desselben Widgets. Besucher erhalten einen Benachrichtigungston, den sie abschalten können, eine helle oder dunkle Anzeige (Override) und die Möglichkeit, ein Gespräch stummzuschalten. Letzteres wird in ihre echte Discourse-Mitgliedschaft geschrieben und folgt ihnen somit zurück zum Forum.
Alles wird innerhalb einer Shadow DOM gerendert. Dies läuft auf Seiten, die ich nicht kontrolliere, und die CSS-Regeln einer Seite sollten die andere nicht beschädigen können.
Was nicht funktioniert und warum
Es gibt keine Audio- oder Videoanrufe. Das ist beabsichtigt und liegt außerhalb des Umfangs.
Die Zustellung ist nicht sofort. Nachrichten treffen in etwa drei Sekunden ein, während das Panel geöffnet ist. Das verdient eine Erklärung, da Discourse Chat-Events tatsächlich an den MessageBus veröffentlicht und es so aussieht, als sollte es einfach funktionieren.
Ein Browser auf einer anderen Domain kann sich nicht am MessageBus-Endpunkt authentifizieren. Seine CORS-Richtlinie erlaubt vier Anfrage-Header, aber keiner davon trägt ein Bearer-Token, und der Weg über den Abfrageparameter zur Authentifizierung von Discourse ist auf RSS- und Kalender-Endpunkte beschränkt. Der eine Header, der funktioniert, X-Shared-Session-Key, wird zu einer UserAuthToken aufgelöst und authentifiziert daher jede Anfrage, die ihn trägt, nicht nur MessageBus-Anfragen. Die Übergabe dieses Headers an eine eingebettete Seite würde ein Cross-Site-Scripting-Loch auf einer Marketing-Seite in eine vollständige Übernahme des Forum-Kontos verwandeln. Drei Sekunden sind der bessere Kompromiss.
Es gibt einen sichereren Weg zu Echtzeit, der im Repository dokumentiert ist. Er verwendet einen MessageBus-Kanal, dessen unerrater Name selbst die Berechtigung darstellt und der auf eine Widget-Sitzung beschränkt ist, nicht auf das Benutzerkonto. Ich habe es nicht gebaut. Wenn jemand es tun möchte, finden sich die Überlegungen in docs/decisions.md.
Das muss man vor der Installation verstehen
Die Registrierung einer Website gewährt dieser Website Cross-Origin-Zugriff auf dein Forum unter Verwendung der Zugangsdaten deiner Mitglieder. Das ist keine Nebenwirkung, das ist der Mechanismus.
Wenn eine registrierte Website kompromittiert wird, kann ein Angreifer, der dort JavaScript ausführen kann, als jedes Mitglied handeln, das sie besucht. Nicht nur im Chat. Alles, was dieses Mitglied auf dem Forum tun könnte.
Registriere daher nur Websites, die du kontrollierst. Die Registrierung einer Website eines Partners oder Kunden bedeutet, deren Sicherheit als deine eigene zu akzeptieren. Das Plugin sagt dies auf der Admin-Seite neben dem Feld, in das du den Origin eingibst, und nicht in einem Dokument, das niemand öffnet. SECURITY.md geht darauf ein, was das Plugin tut, um den Schadensradius zu begrenzen, und was es bewusst nicht tut.
Installation
Füge es zu deiner Container-Definition hinzu und baue einmal neu:
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone --depth 1 https://github.com/capodieci/discourse-chat-bridge.git
env:
DISCOURSE_ENABLE_CORS: true
Dann aktiviere chat_bridge_enabled unter Admin, Einstellungen. Alles andere befindet sich auf einer einzigen Seite unter /chat-bridge/admin, wo du eine Website hinzufügst und das Skript-Tag erhältst.
Zwei Hinweise, die jemandem einen Nachmittag sparen: Sprachnachrichten benötigen Audio-Formate in authorized_extensions, die standardmäßig gar keine enthalten, daher teilt dir die Admin-Seite genau mit, welche fehlen. Und chat_allowed_groups ist standardmäßig auf Trust Level 1 eingestellt, sodass brandneue Konten nicht chatten können, bis sie es sich verdienen. Das Widget erklärt dies, anstatt stillschweigend zu fehlschlagen.
Kompatibilität
Getestet gegen Discourse 2026.9.0 und 2026.8.0 und im Produktivbetrieb auf einem Forum.
Dies stützt sich auf Chat-Service-Objekte, die keine öffentliche API sind, daher kann eine Discourse-Version sie verschieben. Das Repository enthält ein skriptbasiertes Vorab-Prüfungs-Tool (Read-only), das sicherstellt, dass jedes dieser Objekte noch existiert, und in Sekunden statt bei der ersten Anfrage berichtet. Es lohnt sich, es nach einem Upgrade auszuführen.
Was ich mir wünsche
Dass jemand es auf einem Forum installiert, das nicht meins ist, und mir sagt, was kaputtgegangen ist. Alles bisherige wurde gegen ein Discourse, auf einem Server, von einer Person verifiziert, und das ist der schwächste Punkt daran.
Ich würde auch gerne von jemandem hören, der eine bessere Lösung für das MessageBus-Problem kennt als die, auf die ich mich festgelegt habe.
