Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

any-share — local file sharing over Wi-Fi, no app

Live: any-share.site · Free, web-based, peer-to-peer file sharing between devices on the same Wi-Fi. No install, no signup, nothing uploaded.

Share files, media, and text directly between devices on the same wifi — no app install, no account, nothing uploaded to a server. Built for locked-down places like university lab PCs where you can't install software.

Open any-share.site on two devices, read your 6-digit code to the other person (or show your QR), they type it in, you tap Accept, and the browsers open a direct, end-to-end-encrypted WebRTC connection. Files stream peer-to-peer over your wifi.

  • Private by design — you never see a list of devices. The only way to reach someone is to be told their code, the receiver must tap Accept, and both screens show a matching verify word before anything connects. Codes are short-lived and unique among the devices currently online. (The actual transfer is still LAN-only — bytes never leave the wifi.)
  • Free to run — only cost is the domain. Frontend on Cloudflare Pages; signaling on a Cloudflare Durable Object (WebSocket Hibernation), both on the free plan.

⚠️ Local-only mode and "client isolation"

This build is strict local-only: WebRTC uses iceServers: [], so connections use only LAN/mDNS candidates and bytes never leave the wifi. The trade-off: many university/lab networks enable client isolation, which blocks device-to-device traffic even on the same wifi. There, the app shows a clear "couldn't connect on this network" screen instead of hanging. Most home/hotspot wifi works fine.

To make it work everywhere (including isolated networks) while staying private and free, you can later turn on Cloudflare's encrypted TURN relay (1,000 GB/month free). The hook is already in place — see Enabling the relay.

How it works

Browser A ──WS──┐                                  ┌──WS── Browser B
                ▼                                  ▼
        Cloudflare Worker  (one global signaling room)
                     │ routes every socket to →
        Durable Object "RoomDO"  (one global instance)
          • gives each device a unique 6-digit code
          • runs the pair → accept handshake (+ shared verify word)
          • relays WebRTC offer/answer/ICE between the two paired peers only
                     │
   A and B then open a DIRECT WebRTC DataChannel ───────────►
   (local-only: bytes stay on the wifi, encrypted end-to-end)

Project layout

worker/      Cloudflare Worker + Durable Object — signaling only (tiny control messages)
  src/index.ts   WS upgrade, route every socket to the one global RoomDO
  src/room.ts    RoomDO: code assignment, pairing, signal relay, rate-limiting
frontend/    Vite + TypeScript single-page PWA — Cloudflare Pages
  src/signaling.ts  WebSocket client
  src/webrtc.ts     RTCPeerConnection + DataChannel; getIceServers() seam
  src/transfer.ts   chunked file transfer (backpressure) + text
  src/qr.ts         QR generate + camera scan (BarcodeDetector, jsQR fallback)
  src/main.ts       UI + orchestration

Local development

# terminal 1 — signaling Worker (http://127.0.0.1:8787)
cd worker && npm install && npm run dev

# terminal 2 — frontend (http://127.0.0.1:5173, proxies /rtc to the Worker)
cd frontend && npm install && npm run dev

Open http://127.0.0.1:5173 in two tabs/devices. (On localhost both tabs are a "secure context", so WebRTC works. For phone testing, deploy first — HTTPS is required off-localhost.)

Deploy to Cloudflare (only the domain costs money)

  1. Buy a domain at any cheap registrar (Porkbun, Namecheap, …).
  2. Add it to Cloudflare (free plan) and point the registrar's nameservers at Cloudflare.
  3. Deploy the frontend to Cloudflare Pages with custom domain any-share.site:
    cd frontend && npm run build
    npx wrangler pages deploy dist --project-name any-share
    Then in the Cloudflare dashboard add the custom domain to the Pages project.
  4. Deploy the signaling Worker and put it under the same domain:
    • worker/wrangler.toml already has the routes block (any-share.site/rtc/*).
    cd worker && npx wrangler deploy
    The Worker route is more specific than Pages, so /rtc/* hits the Worker and everything else is served by Pages — all under one domain. The frontend already talks to wss://any-share.site/rtc/ws. Done — $0/month.

Note: the Worker is not in CI (only the frontend auto-deploys to Pages). After any change under worker/, ship it manually with cd worker && npx wrangler deploy.

Security notes

  • HTTPS everywhere (Cloudflare auto-TLS); WebRTC DataChannels are DTLS-encrypted end-to-end.
  • The server only ever sees tiny signaling metadata — never your files or text.
  • The server never logs IPs or files; it only relays tiny signaling messages.
  • Pairing is gated by a short code, per-device rate-limited wrong-code attempts, an explicit Accept, and a matching verify word shown on both sides. The data path is LAN-only (iceServers: []), so a remote guesser can't pull files even if they guessed a live code.

Optional: enabling the relay later

To work on client-isolated networks, return real ICE servers from getIceServers() in frontend/src/webrtc.ts:

  1. Enable Cloudflare Realtime → TURN and create a TURN key (free up to 1,000 GB/mo).
  2. Add a Worker route, e.g. GET /rtc/turn-credentials, that mints short-lived TURN credentials with your TURN key + API token (Cloudflare provides a one-call REST endpoint).
  3. Have getIceServers() fetch that endpoint and return the iceServers array.

That single change flips the app from strict-local-only to local-first-with-relay-fallback, keeping transfers private (still E2E encrypted) and free at student scale.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages