Skip to content

iamdoubz/gmmff

Repository files navigation

A view from space of a giant worm hole sucking in your favorite file types... oh the horror!

gmmff — peer-to-peer file transfer

GitHub Release GitHub Actions Workflow Docker Status GitHub Issues GitHub Closed Pulls GitHub License Go Report Card

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.


Application overview

Installing

Please use the guide here for installing gmmff.

Building

Please use the guide here for building gmmff.

CLI

CLI documentation

WASM Webclient

WASM documentation

Schedule — encrypted server-side transfers

Schedule documentation

Limitations

The crypto api is only available in secure contexts: https and localhost. If you attempt to use schedule using http, it will not work!

Local-network mode (no internet required)

Local mode documentation


Commands

See the Commands documentation


Environment variables

See the Commands documentation and the env example


STUN/TURN configuration

See the STUN/TURN documentation


Quick Start

Option A — Docker Compose

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/ws

Option B — Local Go + Redis or Valkey

Prerequisites: 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 debug

Verify

curl http://localhost:8080/healthz   # → ok
curl http://localhost:8080/readyz    # → ok (or 503 if Redis is down)
curl http://localhost:8080/metrics   # → JSON counters

Server configuration

Most 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.


Deployment

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.

Security model

See Security Documentation for more information.


Wire protocol

See Protocol Documentation for more information.


Privacy & logging

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.


Architecture overview

Peer A ──┐                          ┌── Peer B
         │  wss://host/ws           │
         └──── Signaling server ────┘
                    │
               Redis (slot state)
  1. Peer A runs gmmff create and receives a one-time 3-word code
  2. Peer A shares that code out-of-band with Peer B
  3. Peer B runs gmmff join <code> on any machine, anywhere
  4. CPace PAKE authenticates both sides — the signaling server stays blind
  5. The SDP offer/answer is HMAC-signed with the PAKE shared key, preventing man-in-the-middle substitution
  6. A direct WebRTC/DTLS control channel opens; the signaling server's job is done
  7. 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.


Project structure

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

Features

Current

  • Local-network modegmmff local is a fully self-contained mode with embedded server, auto TLS, mDNS discovery, and QR code; no internet or external server required
  • Multi-peer sessionsgmmff create --max-peers N allows 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 cancellationCtrl+C or \q delivers clean messages to all peers; partial file preserved
  • SHA-256 integrity — full-file hash verified before TransferOK is 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) or GMMFF_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 CLIgmmff schedule upload/download/delete for 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.json control tab visibility, ICE settings, share links, QR codes, server field, peers slider, MOTD, and allowed languages

Backlog

  • 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

Probably won't do

  • wasm webclient: window slider (defaults to 2, 1–16 range)
  • Password-protected zips — optional encryption on the zip archive

Inspiration

xkcd comic explaining the difficulties of sending large files between two people


License

MIT — see LICENSE. All dependencies are MIT or Apache-2.0.

About

Fast, secure, private, simple open source file transfer and messaging application

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages