Direct browser-to-browser transfers over WebRTC with relay fallback - #42
Merged
Conversation
Devices behind the same public IP are usually on the same LAN, yet every byte went up the uplink and back down through the server. Clicking Download now first tries a WebRTC DataChannel to the sender, signaled over the existing WebSocket, and silently falls back to GET /share/:uuid if the channel isn't open within 5 seconds. Security model, unchanged trust boundary: - a signaling session can only be opened toward the owner of a share in the requester's own namespace (same authorization as /share/:uuid); session ids are minted by the server, client identities never exposed - only LAN host candidates are relayed (mDNS names or private/link-local addresses), no STUN/TURN, never a public address; enforced on both sides, SDP scrubbed server-side - all signaling inputs validated and size-capped, sessions and candidates capped per client, cleanup on disconnect - the channel is DTLS-encrypted end to end; the server never sees content A service worker (public/sw.js) streams received chunks straight into a regular browser download, so size isn't bounded by memory; without it small files are saved from a Blob and big ones use the relay. Also: share uuids now come from crypto.randomUUID() (they're capability tokens), specs pin how the client IP is resolved behind the proxy, and the relay fallback uses an anchor click rather than a navigation, which made Firefox/Safari drop the WebSocket.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Devices behind the same public IP are usually on the same LAN, yet every
byte went up the uplink and back down through the server. Clicking
Download now first tries a WebRTC DataChannel to the sender, signaled
over the existing WebSocket, and silently falls back to GET /share/:uuid
if the channel isn't open within 5 seconds.
Security model, unchanged trust boundary:
the requester's own namespace (same authorization as /share/:uuid);
session ids are minted by the server, client identities never exposed
addresses), no STUN/TURN, never a public address; enforced on both
sides, SDP scrubbed server-side
candidates capped per client, cleanup on disconnect
A service worker (public/sw.js) streams received chunks straight into a
regular browser download, so size isn't bounded by memory; without it
small files are saved from a Blob and big ones use the relay.
Also: share uuids now come from crypto.randomUUID() (they're capability
tokens), specs pin how the client IP is resolved behind the proxy, and
the relay fallback uses an anchor click rather than a navigation, which
made Firefox/Safari drop the WebSocket.