DropLink

Secure peer-to-peer file and text transfer - WebRTC + AES-256-GCM.

Next.js 16React 19TypeScript 5Tailwind CSS 3WebRTC DataChannels

Overview

DropLink uses WebRTC for direct browser-to-browser connections and AES-256-GCM end-to-end encryption. No file data ever touches a server. Transfers run entirely between the two participants; the signaling server only coordinates the initial handshake.

  • ✓Guest mode - start a transfer immediately without an account
  • ✓Optional accounts - history and one-click reconnect to buddies
  • ✓AES-256-GCM over WebRTC DataChannels; key derived from a share token via HKDF-SHA256
  • ✓Text, code and password sharing with syntax highlighting + auto-copy
  • ✓Folder uploads - recursive drag-and-drop with per-file progress
  • ✓Auto-resume on interruption; QR-code join; clipboard sync
  • ✓ICE-restart auto-reconnect; signaling rate-limited at 30/IP/min
Next.js 16React 19TypeScript 5Tailwind CSS 3WebRTC DataChannelsSocket.io 4SupabasePostgreSQLRadix UI

Evidence · from the repo

How it works

  1. Create roomSender clicks Create Room → signaling server (server/index.ts) assigns a room code.
  2. Share linkSender shares link (room code + share token). The share token is never sent to the server.
  3. Join + handshakeReceiver joins via signaling; peers exchange SDP offers/answers and ICE candidates.
  4. Encrypted channelAES-256-GCM key derived from the share token (HKDF-SHA256). All control messages and chunks encrypted - server sees ciphertext only.

ARCHITECTURE - THREE PIECES

PieceRole
Next.js frontendSend, Receive, Share Dashboard, landing. Vercel or any Node host.
Socket.io signalingRelays SDP + ICE only. Never sees payloads. Render / Fly.io / Railway.
SupabasePostgreSQL + Auth (password, magic link, OAuth) + RLS. Profiles, buddies, on_auth_user_created trigger.

ENVIRONMENT VARIABLES

From .env.example - copy to .env.local

VariablePurpose
NEXT_PUBLIC_SITE_URLPublic frontend URL for canonical + OG
NEXT_PUBLIC_SUPABASE_URLSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYSupabase anon key
NEXT_PUBLIC_SIGNALING_URLSignaling host (localhost:3001 locally)
SIGNALING_PORTServer port, default 3001
SIGNALING_ORIGINSAllowed origins in production

RUN IT LOCALLY

bash
npm install
cp .env.example .env.local
npm run dev:server   # :3001
npm run dev            # :3000 (or both via concurrently)

Build log · reproduce it

REPRODUCE
—Prerequisites: Node.js 20+, npm, a Supabase project, the included server/index.ts
—npm install && cp .env.example .env.local (fill 6 variables)
—Supabase SQL Editor → run supabase/schema.sql (profiles, buddies, RLS, trigger)
—npm run dev:server → http://localhost:3001
—npm run dev → http://localhost:3000
—Verify: two tabs, create room in one, open share link in the other