Skip to content

Repository files navigation

DropBeam

Universal any-device-to-any-device file sharing. AirDrop / Quick Share / Snapdrop / WeTransfer rolled into one open protocol — browser-first, zero-account, end-to-end encrypted in transit (DTLS) with optional application-layer AES-GCM-256.

Phone → Laptop. Mac → Windows. Android → iPad. Any direction. Files stream peer-to-peer in your browser. No upload server holds them, no size limit, no account. Works without internet when both devices are on the same Wi-Fi.

Transport ladder (fastest → most compatible):

  loopback          same host, in-memory
  lan-quic          same LAN, Rust/QUIC binary (zero-RTT, TLS 1.3)
  lan               same LAN, WebRTC DataChannels (host candidates)
  wifi-direct       nearby, OS-native (MultipeerConnectivity / WifiP2p)
  p2p-direct        cross-NAT, WebRTC (STUN hole-punch)
  p2p-relayed       cross-NAT via TURN relay

What's in the web app

The apps/web/ PWA is the universal frontend — any browser, any device.

  • Two-mode picker: Same Wi-Fi (no internet, host-candidate WebRTC) or Anywhere (STUN/TURN over the internet). Auto-detected from the host the page is served from.
  • QR + short code: senders get both a typeable share code and a QR encoding a deep-link URL. Receivers either type the code or scan with their camera (Chrome on Android uses the native BarcodeDetector API).
  • Deep-link auto-join: /?c=K7-9P3-MX2A auto-fills the code and jumps straight to the receive flow.
  • Live transport badge: shows whether the chosen WebRTC path ended up as LAN-direct · no internet, P2P-direct · encrypted, or TURN relayed.
  • Streaming to disk: receivers pick a save folder (showDirectoryPicker in Chrome/Edge) — files stream straight to disk, never held in memory.
  • PWA installable: works offline (app shell cached) once visited once.
  • Drag, paste, click, share: clipboard paste, drag-and-drop, native Web Share, copy code, copy link.

Repo layout

DropBeam/
├── packages/
│   ├── protocol/          — wire types (signaling + frame codec)
│   ├── transfer/          — transfer engine (sender, receiver, QUIC transport, WASM core)
│   └── transfer-core/     — Rust crate → WASM (sha256, AES-GCM, frame codec)
├── apps/
│   ├── web/               — Vite/TS PWA, the universal frontend
│   ├── signaling/         — Bun WebSocket signaling server (also serves the web bundle when WEB_ROOT is set)
│   ├── cli/               — Node/Bun CLI (dropbeam send / recv)
│   ├── quic-relay/        — Rust/quinn QUIC binary (dropbeam-quic)
│   ├── desktop/           — Tauri 2 desktop app (mDNS, tray, clipboard)
│   ├── ios/               — Swift app (MultipeerConnectivity + WebRTC) — stub
│   └── android/           — Kotlin app (WifiP2p + WebRTC) — stub

Quick start

Prerequisites

  • Bun ≥ 1.0 — bun.sh
  • Node.js ≥ 20 (for ws / werift native deps)
  • Rust ≥ 1.78 + wasm-pack (for QUIC binary / WASM core, optional)
git clone https://github.com/you/DropBeam && cd DropBeam
bun install

1 — Web app (the primary UX)

In one terminal:

bun run dev:signaling      # ws://0.0.0.0:8787/ws

In another:

bun run dev:web            # http://localhost:5173

Open the URL on both devices (same machine for a quick test). Click Send, drop a file, share the code or QR. On the other device click Receive and either type the code or scan the QR.

1b — One-port LAN deploy (no internet anywhere)

For the "two phones on a hotel Wi-Fi with no uplink" case, host the built web app from the signaling process itself so you only need one URL:

bun run lan
# → builds apps/web → dist, then starts signaling on :8787
# → web app served at  http://<your-lan-ip>:8787/
# → signaling WS at    ws://<your-lan-ip>:8787/ws

The web app auto-detects that it's on a private IP and switches to LAN mode (no STUN servers, host-only ICE candidates).

2 — CLI file transfer (WebRTC path)

# Terminal A — receiver creates a room and prints a code
dropbeam recv --signaling ws://localhost:8787/ws --out ./received

# Terminal B — sender joins using that code
dropbeam send --signaling ws://localhost:8787/ws --join-code "K7-9P3-MX2A" ./photo.jpg ./video.mp4

# Or let sender create the room and wait for receiver
dropbeam send --signaling ws://localhost:8787/ws ./file.zip

3 — QUIC direct LAN transfer (fastest)

Build the binary once:

cd apps/quic-relay && cargo build --release
# binary: apps/quic-relay/target/release/dropbeam-quic

Then transfer:

# Receiver machine
dropbeam recv --quic --port 9898 --token my-secret --out ./received

# Sender machine (same LAN)
dropbeam send --quic --host 192.168.1.42 --port 9898 --token my-secret ./bigfile.iso

4 — Encrypted transfer (AES-GCM-256)

dropbeam recv --signaling ws://... --out ./recv --passphrase "hunter2"
dropbeam send --signaling ws://... ./secret.zip --passphrase "hunter2"

CLI reference

dropbeam send  --signaling <url> [OPTIONS] <file>...
dropbeam recv  --signaling <url> --out <dir> [OPTIONS]

# QUIC (skips signaling)
dropbeam send  --quic --host <ip> --port <n> --token <tok> [--lanes 4] <file>...
dropbeam recv  --quic --port <n> --token <tok> --out <dir>

OPTIONS
  --signaling <url>     Signaling server (or DROPBEAM_SIGNALING env var)
  --join-code <code>    Join existing room
  --passphrase <str>    AES-GCM-256 passphrase
  --ttl <sec>           Room TTL (default 1800)
  --adapter <name>      WebRTC adapter: auto (default) | node-dc | werift
  --wasm/--no-wasm      Force WASM or TS crypto core
  --out <dir>           Output directory (recv)
  --lanes <n>           Parallel QUIC streams (default 4)
  --transfer-id <id>    Resume ID

Run tests

bun test                          # all unit + integration tests (26 tests)
bun run e2e                       # end-to-end: signaling + full transfer round-trip

Individual package tests:

bun test packages/transfer        # transfer engine (sender/receiver/router)
bun test apps/signaling           # signaling server (room codes, rate limiting, WS)

Deploy web + signaling

Signaling on Northflank

Use apps/signaling/Dockerfile as the Dockerfile path and / as the build context. The container listens on PORT and exposes /healthz, so configure the Northflank health check to hit:

GET /healthz

The WebSocket endpoint is:

wss://<your-northflank-domain>/ws

Web frontend on Vercel

The root vercel.json deploys apps/web as a Vite app:

Install Command: bun install --frozen-lockfile
Build Command:   bun run --cwd apps/web build
Output Dir:      apps/web/dist

Set this Vercel environment variable before production deploys:

VITE_SIGNALING_URL=wss://<your-northflank-domain>/ws

Build native components (optional)

WASM crypto core

cd packages/transfer-core
wasm-pack build --target bundler --out-dir pkg

The WASM module is imported automatically by @dropbeam/transfer with a pure-TypeScript fallback if the build is absent.

QUIC binary

cd apps/quic-relay
cargo build --release
# → target/release/dropbeam-quic
# Place on PATH or next to the dropbeam CLI binary

Tauri desktop app

cd apps/desktop
npm install
npx tauri build          # production bundle
npx tauri dev            # dev mode

Requires Tauri 2 prerequisites: tauri.app/v2/guides/prerequisites


iOS app

apps/ios/DropBeam/ — Swift 5.9, iOS 15+

cd apps/ios/DropBeam
pod install              # installs GoogleWebRTC
open DropBeam.xcworkspace

Key classes:

  • NearbyTransfer — MultipeerConnectivity (same-LAN, AirDrop-style)
  • WebRTCFallback — GoogleWebRTC DataChannels (remote/cross-NAT)
  • SignalingClient — WebSocket room/SDP relay
  • FileTransfer — coordinator (picks transport, routes events)

Android app

apps/android/ — Kotlin, minSdk 26, Gradle 8

cd apps/android
./gradlew assembleDebug

Dependencies: stream-webrtc-android, okhttp3, kotlinx-coroutines.

Key classes:

  • NearbyTransfer — WifiP2pManager (WiFi Direct), raw TCP socket transfer
  • WebRTCFallback — WebRTC DataChannels via stream-webrtc-android
  • SignalingClient — OkHttp WebSocket + Kotlin Flow events
  • FileTransfer — coordinator

Required manifest permissions: NEARBY_WIFI_DEVICES, CHANGE_WIFI_STATE, INTERNET.


Architecture

Frame format (binary, 16-byte header)

 0        1        2        3
 magic    ver      flags    reserved
 0xDB     0x01     0bxxxxxx 0x00

 4 ─── 7  : uint32 BE  fileId
 8 ─── 11 : uint32 BE  chunkIndex
 12 ── 15 : uint32 BE  payloadLen
 16+      : payload (optionally AES-GCM encrypted)

flags:
  bit 0 = ENCRYPTED
  bit 1 = LAST (final chunk of file)

Smart router

sameHost?     → loopback
sameLan+quic? → lan-quic   (Rust/quinn, UDP, TLS 1.3, zero-RTT)
sameLan?      → lan        (WebRTC DataChannels)
nearby?       → wifi-direct (OS-native: MPC / WifiP2p)
directReach?  → p2p-direct  (WebRTC, STUN hole-punch)
else          → p2p-relayed (WebRTC + TURN)

WebRTC adapter fallback chain

node-datachannel (C++, libdatachannel)  ← fastest, requires native binary
   ↓ if unavailable
werift (pure TypeScript)                ← zero native deps, works everywhere

Crypto core fallback chain

WASM (Rust: sha2 + aes-gcm crates)  ← hot path, ~10× faster
   ↓ if WASM not bundled
TypeScript (WebCrypto API)           ← universal fallback

Fork / extend

  1. Add a new transport: implement PeerConnection interface in packages/transfer/src/peer.ts
  2. Add a new signaling backend: implement the wire types in packages/protocol/src/signaling.ts
  3. Plug in TURN: edit iceServers in weriftAdapter.ts / nodeDCAdapter.ts / iOS WebRTCFallback.swift / Android WebRTCFallback.kt
  4. Custom frame format: extend packages/transfer-core/src/frame.rs + packages/protocol/src/transfer.ts

Privacy

DropBeam cannot see your files. They go peer-to-peer over a DTLS-encrypted WebRTC data channel; the signaling server only relays opaque SDP/ICE handshake blobs to introduce the two devices. No upload bucket, no cache, no analytics. Add the optional passphrase and every chunk is also AES-GCM-256 encrypted in your browser before it leaves the device.

The user-facing privacy statement is in-app — open the web UI and click "Privacy" in the footer.

More docs

  • SETUP.mdstart here. Plain-English fork → install → run → first-transfer walkthrough.
  • FEATURES.md — comprehensive feature catalog (use this as the source-of-truth for building marketing pages, app listings, or mobile screens).
  • DEPLOY.md — production deploy: Vercel for the web app, Koyeb (or Render / Fly.io) for the signaling server. Includes the Vercel CLI walkthrough and a section on running ads honestly.
  • FORK.md — coding conventions and where to add new transports / brandings / self-hosted deploys.

Mission

If this ever earns money — ads, freemium API, office tier — 30 % is donated to people in need (recipients voted on quarterly, receipts posted publicly) and 70 % is reinvested in infrastructure, dev, and keeping the free tier alive. Built by Vara Prasad Karewar (@VaraKare · @the.varaprasad).

License

MIT — see header in each source file. Use it, fork it, rebrand it, ship it commercially. Just don't sue us if a file gets corrupted.

About

Universal any-device-to-any-device file sharing. Browser-first, peer-to-peer, end-to-end encrypted, works on the same Wi-Fi without internet.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages