Skip to content

v0.3.0 — payloads expire, multi-peer mesh, IPv6-aware network check

Choose a tag to compare

@NiKrause NiKrause released this 02 Aug 11:19
22bf9d3

First release where the published package moves since 0.1.0 — and the first
where the git tag and the npm version are the same string.

Package: @le-space/libp2p-webrtc-qr@0.3.0

Signed payloads now expire. A signed offer used to be usable for as long as
the offerer's peer connection lived, so anyone who photographed a displayed code,
or kept a copy of an invite link from a chat, could replay it for that whole
window.

  • notBefore/notAfter sit inside the canonical form, so the signature
    covers them. Rewriting the window invalidates the signature rather than
    extending the payload.
  • Ten minutes by default; pass lifetimeMs to change it.
  • Two minutes of clock skew tolerated, because two devices that have never
    spoken cannot be assumed to agree on the time.
  • The window is checked after signature verification, so a rewritten window
    is reported as forgery rather than as an expiry — the more accurate of the two.
  • New exports: DEFAULT_LIFETIME_MS, CLOCK_SKEW_MS. Both encodeSignedPayload
    and decodeSignedPayload accept now, so tests do not have to wait.

Breaking

PAYLOAD_VERSION goes 1 → 2, and the signature prefix with it. A 0.1.0 peer
and a 0.3.0 peer cannot verify each other's payloads.
That is deliberate:
adding signed fields changes what gets signed in both directions, and a version
that did not move would surface a format mismatch as "signature is invalid".

Why 0.3.0 and not 0.2.0

npm had 0.1.0, while every repo tag since — v0.1.1 through v0.2.1 — carried
package version 0.1.0, because those releases were about the demo. Checking out
the tag that matched a published version therefore gave you a package.json that
disagreed with it. Skipping a minor on a 0.x package costs nothing and fixes that
for good.

The transport, the multiaddr connection and the vendored @libp2p/webrtc
internals are untouched since 0.1.0.

Demo

None of this is published to npm, but it is live at
webrtc-qr.le-space.de.

More than two peers. Scanning is only needed for the first connection. Two
peers that have both reached a third learn about each other over the existing
links, exchange their signed payloads through it, and connect directly. The
forwarding peer cannot tamper with anything — signatures are verified end to end
— and thanks to the replay window it cannot replay anything either.

A network check before you scan anything. Three indicators — IPv4, IPv6, and
a summary that is green when either family is usable. Tap any of them for the
reasoning; a phone has no hover.

  • IPv6 is reported separately because carrier-grade NAT is an IPv4 problem.
    If both peers have a global IPv6 address there is no translation to defeat,
    only a stateful firewall that ICE opens by itself — no relay, no TURN.
  • STUN now also runs against IPv6 literals. A reflexive candidate exists only
    for an address family a STUN transaction actually used, and the IPv6 host
    candidate is hidden behind mDNS like every other host candidate. When a
    resolver returns A but no AAAA for the STUN hostnames, a machine with working
    IPv6 gathered no IPv6 candidate at all — and the peers never exchanged the
    addresses that would have beaten carrier NAT without a relay.
  • A bug in the previous check is fixed. Every engine masks the base behind a
    reflexive candidate as raddr 0.0.0.0 rport 0, so relatedPort is always 0
    and never null. Keying by it put IPv4 and IPv6 in one bucket, whose ports of
    course differ — and an ordinary cone NAT was labelled symmetric.

The page now says who sees your address. The check asks Cloudflare and
Google what address the request arrived from; over IPv4 that is your router's,
over IPv6 this device's own. The disclosure sits above the button, so it is
readable while the choice to press it is still open.

Invite links, and a reply that finds its way back. The QR encodes a link, so
scanning with the system camera opens the demo instead of showing raw text. A
reply opened in a second tab reports back to the tab that is holding the
connection.

Verified

24 unit tests, 96 browser tests across Chromium, Firefox and WebKit, and 6 Helia
transfer tests. npm pack: 11 files, 14.3 kB.

Not yet confirmed by hand: laptop on wifi to phone on mobile data. That is the
case the IPv6 work exists for.