gmmff (pronounced gimph) is a brutally simple, cryptographically sound peer-to-peer file and message transfer system.
gmmff consists of two parts: a signaling server that brokers the initial connection, and a CLI client that handles the actual transfer. The server never sees file contents — once two (or more) peers are connected, all data flows directly between them over an encrypted WebRTC data channel.
Please use the guide here for installing gmmff.
Please use the guide here for building gmmff.
The crypto api is only available in secure contexts: https and localhost. If you attempt to use schedule using http, it will not work!
See the Commands documentation
See the Commands documentation and the env example
See the STUN/TURN documentation
git clone https://github.com/iamdoubz/gmmff
cd gmmff
cp configs/.env.example configs/.env
docker compose up -d
# Server available at ws://localhost:8080/wsPrerequisites: Go 1.23+, and Redis 7+ or Valkey 7.2+ (wire-compatible
drop-in — the same client talks to either; use a valkey:// URL if you prefer).
# Start Redis (or: valkey-server)
redis-server
# Run with in-memory store (no Redis/Valkey needed for dev)
go run ./cmd/gmmff serve --memory --log-pretty --log-level debug
# Or with Redis/Valkey (set GMMFF_REDIS_URL; valkey:// is accepted)
go run ./cmd/gmmff serve --log-pretty --log-level debugcurl http://localhost:8080/healthz # → ok
curl http://localhost:8080/readyz # → ok (or 503 if Redis is down)
curl http://localhost:8080/metrics # → JSON countersMost flags have environment variable equivalents with the GMMFF_ prefix.
Copy configs/.env.example to .env and adjust.
See ENV.md and the example env file for more information.
For production deployments, see the dedicated guides in the docs/ directory:
- docs/SYSTEMD.md — Creating a dedicated system user, installing the binary and service file, managing configuration without editing the service file, and Redis Unix socket access.
- docs/NGINX.md — Configuring nginx as a reverse proxy with TLS termination, WebSocket upgrade headers, timeout tuning, and endpoint access control.
See Security Documentation for more information.
See Protocol Documentation for more information.
Logs contain only:
- Timestamp
- Component name (
broker,store,main) - Slot UUID (opaque — means nothing to outsiders)
- Error code (e.g.
ERR_REDIS_UNAVAILABLE) - HTTP method + path + status code
Logs never contain: file names, file sizes, IP addresses, user agents, slot codes, or any data that could identify a transfer or a user.
Peer A ──┐ ┌── Peer B
│ wss://host/ws │
└──── Signaling server ────┘
│
Redis (slot state)
- Peer A runs
gmmff createand receives a one-time 3-word code - Peer A shares that code out-of-band with Peer B
- Peer B runs
gmmff join <code>on any machine, anywhere - CPace PAKE authenticates both sides — the signaling server stays blind
- The SDP offer/answer is HMAC-signed with the PAKE shared key, preventing man-in-the-middle substitution
- A direct WebRTC/DTLS control channel opens; the signaling server's job is done
- Both peers enter the session REPL and can freely exchange files and messages
| Phase | What the server does |
|---|---|
slot.create |
Generates a UUID + 3-word code, persists in Redis with 10-min TTL |
slot.join |
Resolves code → slot, links the responder, sends slot.ready to both |
| Relay | Forwards pake.*, sdp.*, ice.* frames opaquely to the other peer |
bye / expire |
Deletes both Redis keys; notifies peer |
The server cannot intercept the session. PAKE authentication happens entirely between the two clients, and the DTLS session key is bound to the PAKE shared secret via HMAC — so a compromised signaling server cannot substitute its own SDP fingerprints.
If you want to learn more, see the dedicated Architecture document.
gmmff/
├── cmd/gmmff/ # Binary entrypoint (Cobra CLI)
│ ├── main.go # Root command + serve subcommand + shared helpers
│ ├── create.go # gmmff create — starts file+message session, session REPL
│ ├── chat.go # gmmff chat — pure chat; gmmff join — joins any session
│ ├── local.go # gmmff local — self-contained local-network mode
│ └── cleanup.go # gmmff cleanup — remove expired schedule uploads (cron-friendly)
├── internal/
│ ├── broker/ # WebSocket hub, message router, HTTP server, UI config
│ │ ├── broker.go
│ │ ├── server.go
│ │ └── uiconfig.go # Feature flags served via /config.json
│ ├── schedule/ # Server-side encrypted file storage (Schedule feature)
│ │ ├── config.go # Env parsing, TTL options, IP allowlists
│ │ ├── store.go # Pending/complete file lifecycle, chunk storage
│ │ ├── handler.go # HTTP handlers: /api/schedule/*
│ │ └── cleanup.go # Crontab parser, background cleanup goroutine
│ ├── store/ # Redis + in-memory slot persistence
│ │ └── store.go
│ ├── slot/ # Slot domain model & state machine
│ │ └── slot.go
│ ├── crypto/ # Slot code generation (3-word passphrase)
│ │ └── codegen.go
│ ├── log/ # Privacy-safe structured logger
│ │ └── log.go
│ ├── archive/ # On-the-fly zip for multi-file transfers
│ │ └── archive.go
│ ├── peer/ # WebRTC + PAKE orchestration; StartSession/JoinSession
│ │ └── peer.go
│ ├── peerconfig/ # Shared Config type (avoids peer↔session import cycle)
│ │ └── peerconfig.go
│ ├── session/ # Bidirectional session coordinator
│ │ └── session.go
│ ├── signaling/ # WebSocket signaling client
│ │ ├── client_native.go
│ │ ├── client_js.go
│ │ └── b64.go
│ ├── transfer/ # Binary chunk protocol (send + receive state machines)
│ │ └── transfer.go
│ ├── localmode/ # Self-contained local-network mode
│ │ ├── embed.go
│ │ ├── tls.go
│ │ ├── mdns.go
│ │ └── local.go
│ └── turn/ # TURN URL parsing and ephemeral credential derivation
│ └── turn.go
├── pkg/protocol/ # Wire message types (shared server/client)
│ └── protocol.go
├── web/ # Browser UI (Wasm + plain JS)
│ ├── cmd/gmmff-wasm/ # Go→Wasm entry point (syscall/js bridge)
│ │ └── main.go
│ └── static/ # Served files
│ ├── index.html # Single-page UI (Files + Chat + Schedule tabs)
│ ├── css/
│ │ └── app.css
│ ├── js/
│ │ └── app.js # UI logic + Schedule IIFE module (AES-GCM crypto)
│ ├── themes/
│ │ └── default.json
│ └── i18n/
│ ├── languages.json
│ ├── en.json
│ └── ... # 32 languages total
├── configs/
│ ├── .env.example # All environment variable reference
│ ├── gmmff.conf # nginx reverse proxy configuration
│ └── gmmff.service # systemd service unit
├── docs/
│ ├── ARCHITECTURE.md
│ ├── BUILD.md
│ ├── CLI.md
│ ├── CMDS.md
│ ├── INSTALL.md
│ ├── LOCAL.md
│ ├── NGINX.md
│ ├── PROTOCOL.md
│ ├── SCHEDULE.md
│ ├── SECURITY.md
│ ├── SYSTEMD.md
│ ├── TURN.md
│ └── WASM.md
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
└── README.md
- Local-network mode —
gmmff localis a fully self-contained mode with embedded server, auto TLS, mDNS discovery, and QR code; no internet or external server required - Multi-peer sessions —
gmmff create --max-peers Nallows 2–10 participants; 2-peer sessions are bidirectional, 3–10 peer sessions broadcast from the initiator to all - Display names — initiator and joiners can set a name; names are announced to all peers on connect and shown as message labels throughout the session
- Signaling server — Go, Redis-backed, privacy-safe structured logs, Docker-ready
- CPace PAKE — zero-knowledge authentication; server stays blind to the shared secret
- SDP MAC binding — HMAC-signed SDP with HKDF-derived subkeys; prevents MITM via signaling relay
- DTLS 1.3 — all data channel traffic encrypted end-to-end via Pion WebRTC
- Multi-file and directory transfers — multiple files and directories zipped on the fly
- Transfer queue — multiple transfers serialized automatically; each gets its own progress bar
- Resumable transfers — partial + meta sidecar files; progress bars pick up at the correct offset
- Clean cancellation —
Ctrl+Cor\qdelivers clean messages to all peers; partial file preserved - SHA-256 integrity — full-file hash verified before
TransferOKis sent - Secure chat — pure text chat (
gmmff chat) or inline messaging within a file session - Sliding window — configurable in-flight chunks (
--window); default 2 - Configurable chunk size — up to SCTP maximum 65526 bytes (
--chunk-size) - STUN multi-server — append additional STUN servers via
--stun(repeatable) orGMMFF_STUN - TURN support — long-term and ephemeral credentials, mixed auth types, transport hints, max 3 servers
- Browser UI (Wasm) — same Go source compiled to WebAssembly; Files, Chat, and Schedule tabs
- Schedule tab — browser-side AES-256-GCM encrypted uploads; server never sees plaintext; TTL, download limits, IP/password access control, QR codes, auto-download links, cleanup service
- Schedule CLI —
gmmff schedule upload/download/deletefor terminal-based encrypted transfers; full browser↔CLI interoperability - Drag and drop — drop files anywhere on the browser UI to queue them for sending
- 32 languages — English, Spanish, French, German, Italian, Swedish, Portuguese (BR/EU), Arabic, Bengali, Persian, Finnish, Hindi, Indonesian, Japanese, Korean, Marathi, Malay, Dutch, Norwegian, Polish, Russian, Thai, Filipino, Turkish, Ukrainian, Urdu, Vietnamese, Chinese (Simplified/Traditional), Tamil, Sinhala; language picker with 7-day persistence
- ICE settings panel — configurable STUN/TURN in the browser UI, persisted 7 days
- Share links + QR codes — shareable URLs and scannable QR codes on all code screens
- UI feature flags — 15 server-side feature flags served via
/config.jsoncontrol tab visibility, ICE settings, share links, QR codes, server field, peers slider, MOTD, and allowed languages
- Browser extension — use your favorite browser to send/receive files
- More languages — 32 languages shipped; contributions welcome
- Trusted local CA — one-time CA install for iOS Safari support in
gmmff local - Quantum-safe encryption — post-quantum algorithms with elliptic-curve fallback
- wasm webclient: window slider (defaults to 2, 1–16 range)
- Password-protected zips — optional encryption on the zip archive
- webwormhole by @saljam
- FilePizza by @kern and @neerajbaid
- Firefox Send by @mozilla new fork by @timvisee
- Jirafeau by Jerome Jutteau and many others...
MIT — see LICENSE. All dependencies are MIT or Apache-2.0.

