libp2p WebRTC über QR
Zwei Browser verbinden sich direkt als libp2p-Peers — ohne Relay und ohne Signaling-Server. WebRTC-Offer und -Answer werden außerhalb des Netzes ausgetauscht: als signierte, komprimierte QR-Codes, die beide Telefone vom Bildschirm des jeweils anderen abscannen — einmal in jede Richtung, weil kein Server die Answer zurückträgt.
pnpm add @le-space/libp2p-webrtc-qr libp2p @multiformats/multiaddr
Der Handschlag
Browser A Browser B
| Offer erzeugen -> signieren -> QR |
|------------ Kamera-Scan ------------>|
| Signatur prüfen, Answer erzeugen
|<----------- Kamera-Scan -------------|
Signatur prüfen -> WebRTC verbunden -> libp2p-Stream
Jede Nutzlast trägt eine SDP-Beschreibung, eine Session-ID und die Peer-ID des Absenders — signiert mit dessen privatem libp2p-Schlüssel und gegen den in der Peer-ID enthaltenen öffentlichen Schlüssel geprüft, bevor überhaupt gewählt wird.
Zwei Einstiegspunkte
| Import | enthält |
|---|---|
@le-space/libp2p-webrtc-qr | Transport, Session, Payload-Codecs |
@le-space/libp2p-webrtc-qr/elements | Custom Elements, Netzprüfung, QR-Rahmung |
Tiefe Importe werden nicht unterstützt. Was nicht aus einem dieser beiden re-exportiert wird, ist keine öffentliche API.
Das kleinste, was funktioniert
import { createLibp2p } from 'libp2p'
import { QRSession, webRTCQR } from '@le-space/libp2p-webrtc-qr'
const sessions = new Map()
const node = await createLibp2p({
transports: [webRTCQR({ getOutboundSession: peerId => sessions.get(peerId.toString()) })]
})
const session = new QRSession(node)
// A zeigt das als QR-Code
const offer = await session.createOffer()
// B scannt und zeigt die Antwort
const answer = await session.acceptOffer(offer)
// A scannt die Antwort
const { peerId, connection } = await session.acceptAnswer(answer)
Weiter
| Seite | beantwortet |
|---|---|
| Session | die Handschlag-API, ihre Optionen und Ereignisse |
| Nutzlastformate | v2 gegen die kompakten q3:-Codes, und warum v3 optional ist |
| Transport | Einbau in libp2p, und warum Noise entfällt |
| Elemente | vier Custom Elements, und ihre Übersetzung |
| Netzbereitschaft | was dieser Browser erreicht, und woran man sperrt |
| Sicherheit | was die Signatur bindet — und wann das aufhört zu gelten |
| Mobil | die Randbedingung, die alles andere formt |
Bekannte Grenzen
- Kein TURN-Server. Zwei Peers hinter symmetrischen NATs können über IPv4 scheitern. Mit globalem IPv6 auf beiden Seiten verbinden sie sich trotzdem.
- Wi-Fi-Client-Isolation bricht die Verbindung, während jede Prüfung besteht – in Gästenetzen verbreitet und für die Bereitschaftsprüfung unsichtbar. Siehe Netzbereitschaft.
- Nutzlasten verfallen nach zehn Minuten, zwei Minuten Uhrenversatz werden toleriert. Das Fenster ist mitsigniert — Umschreiben macht es ungültig, nicht länger.
- Der Kameraweg ist von keinem Test abgedeckt.
getUserMedia,BarcodeDetectorund derjsQR-Rückfall werden ausschließlich von Hand geprüft. - WebKit-WebRTC ist nur unter macOS verifiziert — Playwrights Linux-WebKit hat kein funktionierendes WebRTC, die CI überspringt dort jede Spezifikation, die eine Peer-Verbindung braucht.
Die technische Aktenlage liegt im Repository: Roadmap, Hinweise für KI-Agenten.