{
  "markdown": "<p align=\"center\">\n  <img src=\"imgs/gmmff-social.png\" alt=\"A view from space of a giant worm hole sucking in your favorite file types... oh the horror!\">\n</p>\n\n# gmmff — peer-to-peer file transfer\n\n[![GitHub Release](https://img.shields.io/github/v/release/iamdoubz/gmmff?display_name=tag&style=for-the-badge&logo=refinedgithub&logoColor=fff&label=Latest&color=007EC6)](https://github.com/iamdoubz/gmmff/releases/latest)\n[![GitHub Actions Workflow Docker Status](https://img.shields.io/github/actions/workflow/status/iamdoubz/gmmff/docker.yml?style=for-the-badge&logo=githubactions&logoColor=fff&label=Builds)](https://github.com/iamdoubz/gmmff/actions/workflows/docker.yml)\n[![GitHub Issues](https://img.shields.io/github/issues-raw/iamdoubz/gmmff?style=for-the-badge&logo=freecodecamp&logoColor=fff&color=ec7013&label=Issues)](https://github.com/iamdoubz/gmmff/issues)\n[![GitHub Closed Pulls](https://img.shields.io/github/issues-pr-closed/iamdoubz/gmmff?style=for-the-badge&logo=git&logoColor=fff&color=a64dff&label=Pulls)](https://github.com/iamdoubz/gmmff/pulls?q=is%3Apr+is%3Aclosed)\n[![GitHub License](https://img.shields.io/github/license/iamdoubz/gmmff?style=for-the-badge&logo=readthedocs&color=67AC09)](LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/iamdoubz/gmmff/v2)](https://goreportcard.com/report/github.com/iamdoubz/gmmff/v2)\n\n> **gmmff** (pronounced *gimph*) is a brutally simple, cryptographically sound\n> peer-to-peer file and message transfer system.\n\ngmmff consists of two parts: a **signaling server** that brokers the initial\nconnection, and a **CLI client** that handles the actual transfer.  The server\nnever sees file contents — once two (or more) peers are connected, all data flows\ndirectly between them over an encrypted WebRTC data channel.\n\n---\n\n## Application overview\n\n### Installing\n\nPlease use the [guide here](docs/INSTALL.md) for installing `gmmff`.\n\n### Building\n\nPlease use the [guide here](docs/BUILD.md) for building `gmmff`.\n\n### CLI\n\n[CLI documentation](docs/CLI.md)\n\n### WASM Webclient\n\n[WASM documentation](docs/WASM.md)\n\n### Schedule — encrypted server-side transfers\n\n[Schedule documentation](docs/SCHEDULE.md)\n\n#### Limitations\n\nThe crypto api is only available in secure contexts: https and localhost. If\nyou attempt to use schedule using http, it will not work!\n\n### Local-network mode (no internet required)\n\n[Local mode documentation](docs/LOCAL.md)\n\n---\n\n## Commands\n\nSee the [Commands documentation](docs/CMDS.md)\n\n---\n\n## Environment variables\n\nSee the [Commands documentation](docs/CMDS.md) and the [env example](configs/.env.example)\n\n---\n\n## STUN/TURN configuration\n\nSee the [STUN/TURN documentation](docs/TURN.md)\n\n---\n\n## Quick Start\n\n### Option A — Docker Compose\n\n```bash\ngit clone https://github.com/iamdoubz/gmmff\ncd gmmff\ncp configs/.env.example configs/.env\ndocker compose up -d\n# Server available at ws://localhost:8080/ws\n```\n\n### Option B — Local Go + Redis or Valkey\n\nPrerequisites: **Go 1.23+**, and **Redis 7+** *or* **Valkey 7.2+** (wire-compatible\ndrop-in — the same client talks to either; use a `valkey://` URL if you prefer).\n\n```bash\n# Start Redis (or: valkey-server)\nredis-server\n\n# Run with in-memory store (no Redis/Valkey needed for dev)\ngo run ./cmd/gmmff serve --memory --log-pretty --log-level debug\n\n# Or with Redis/Valkey (set GMMFF_REDIS_URL; valkey:// is accepted)\ngo run ./cmd/gmmff serve --log-pretty --log-level debug\n```\n\n### Verify\n\n```bash\ncurl http://localhost:8080/healthz   # → ok\ncurl http://localhost:8080/readyz    # → ok (or 503 if Redis is down)\ncurl http://localhost:8080/metrics   # → JSON counters\n```\n\n---\n\n## Server configuration\n\n*Most* flags have environment variable equivalents with the `GMMFF_` prefix.\nCopy `configs/.env.example` to `.env` and adjust.\n\nSee [ENV.md](docs/ENV.md) and the [example env file](configs/.env.example) for more information.\n\n---\n\n## Deployment\n\nFor production deployments, see the dedicated guides in the `docs/` directory:\n\n- **[docs/SYSTEMD.md](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.\n- **[docs/NGINX.md](docs/NGINX.md)** — Configuring nginx as a reverse proxy with TLS termination, WebSocket upgrade headers, timeout tuning, and endpoint access control.\n\n---\n\n## Security model\n\nSee [Security Documentation](docs/SECURITY.md) for more information.\n\n---\n\n## Wire protocol\n\nSee [Protocol Documentation](docs/PROTOCOL.md) for more information.\n\n---\n\n## Privacy & logging\n\nLogs contain **only**:\n\n- Timestamp\n- Component name (`broker`, `store`, `main`)\n- Slot UUID (opaque — means nothing to outsiders)\n- Error code (e.g. `ERR_REDIS_UNAVAILABLE`)\n- HTTP method + path + status code\n\nLogs **never** contain: file names, file sizes, IP addresses, user agents,\nslot codes, or any data that could identify a transfer or a user.\n\n---\n\n## Architecture overview\n\n```\nPeer A ──┐                          ┌── Peer B\n         │  wss://host/ws           │\n         └──── Signaling server ────┘\n                    │\n               Redis (slot state)\n```\n\n1. Peer A runs `gmmff create` and receives a one-time 3-word code\n2. Peer A shares that code out-of-band with Peer B\n3. Peer B runs `gmmff join <code>` on any machine, anywhere\n4. CPace PAKE authenticates both sides — the signaling server stays blind\n5. The SDP offer/answer is HMAC-signed with the PAKE shared key, preventing man-in-the-middle substitution\n6. A direct WebRTC/DTLS control channel opens; the signaling server's job is done\n7. Both peers enter the session REPL and can freely exchange files and messages\n\n| Phase | What the server does |\n|-------|----------------------|\n| `slot.create`  | Generates a UUID + 3-word code, persists in Redis with 10-min TTL |\n| `slot.join`    | Resolves code → slot, links the responder, sends `slot.ready` to both |\n| Relay          | Forwards `pake.*`, `sdp.*`, `ice.*` frames opaquely to the other peer |\n| `bye` / expire | Deletes both Redis keys; notifies peer |\n\nThe server **cannot** intercept the session.  PAKE authentication happens\nentirely between the two clients, and the DTLS session key is bound to the\nPAKE shared secret via HMAC — so a compromised signaling server cannot\nsubstitute its own SDP fingerprints.\n\nIf you want to learn more, see the dedicated [Architecture document](docs/ARCHITECTURE.md).\n\n---\n\n## Project structure\n\n```\ngmmff/\n├── cmd/gmmff/              # Binary entrypoint (Cobra CLI)\n│   ├── main.go             # Root command + serve subcommand + shared helpers\n│   ├── create.go           # gmmff create — starts file+message session, session REPL\n│   ├── chat.go             # gmmff chat — pure chat; gmmff join — joins any session\n│   ├── local.go            # gmmff local — self-contained local-network mode\n│   └── cleanup.go          # gmmff cleanup — remove expired schedule uploads (cron-friendly)\n├── internal/\n│   ├── broker/             # WebSocket hub, message router, HTTP server, UI config\n│   │   ├── broker.go\n│   │   ├── server.go\n│   │   └── uiconfig.go     # Feature flags served via /config.json\n│   ├── schedule/           # Server-side encrypted file storage (Schedule feature)\n│   │   ├── config.go       # Env parsing, TTL options, IP allowlists\n│   │   ├── store.go        # Pending/complete file lifecycle, chunk storage\n│   │   ├── handler.go      # HTTP handlers: /api/schedule/*\n│   │   └── cleanup.go      # Crontab parser, background cleanup goroutine\n│   ├── store/              # Redis + in-memory slot persistence\n│   │   └── store.go\n│   ├── slot/               # Slot domain model & state machine\n│   │   └── slot.go\n│   ├── crypto/             # Slot code generation (3-word passphrase)\n│   │   └── codegen.go\n│   ├── log/                # Privacy-safe structured logger\n│   │   └── log.go\n│   ├── archive/            # On-the-fly zip for multi-file transfers\n│   │   └── archive.go\n│   ├── peer/               # WebRTC + PAKE orchestration; StartSession/JoinSession\n│   │   └── peer.go\n│   ├── peerconfig/         # Shared Config type (avoids peer↔session import cycle)\n│   │   └── peerconfig.go\n│   ├── session/            # Bidirectional session coordinator\n│   │   └── session.go\n│   ├── signaling/          # WebSocket signaling client\n│   │   ├── client_native.go\n│   │   ├── client_js.go\n│   │   └── b64.go\n│   ├── transfer/           # Binary chunk protocol (send + receive state machines)\n│   │   └── transfer.go\n│   ├── localmode/          # Self-contained local-network mode\n│   │   ├── embed.go\n│   │   ├── tls.go\n│   │   ├── mdns.go\n│   │   └── local.go\n│   └── turn/               # TURN URL parsing and ephemeral credential derivation\n│       └── turn.go\n├── pkg/protocol/           # Wire message types (shared server/client)\n│   └── protocol.go\n├── web/                    # Browser UI (Wasm + plain JS)\n│   ├── cmd/gmmff-wasm/     # Go→Wasm entry point (syscall/js bridge)\n│   │   └── main.go\n│   └── static/             # Served files\n│       ├── index.html      # Single-page UI (Files + Chat + Schedule tabs)\n│       ├── css/\n│       │   └── app.css\n│       ├── js/\n│       │   └── app.js      # UI logic + Schedule IIFE module (AES-GCM crypto)\n│       ├── themes/\n│       │   └── default.json\n│       └── i18n/\n│           ├── languages.json\n│           ├── en.json\n│           └── ...         # 32 languages total\n├── configs/\n│   ├── .env.example        # All environment variable reference\n│   ├── gmmff.conf          # nginx reverse proxy configuration\n│   └── gmmff.service       # systemd service unit\n├── docs/\n│   ├── ARCHITECTURE.md\n│   ├── BUILD.md\n│   ├── CLI.md\n│   ├── CMDS.md\n│   ├── INSTALL.md\n│   ├── LOCAL.md\n│   ├── NGINX.md\n│   ├── PROTOCOL.md\n│   ├── SCHEDULE.md\n│   ├── SECURITY.md\n│   ├── SYSTEMD.md\n│   ├── TURN.md\n│   └── WASM.md\n├── Dockerfile\n├── docker-compose.yml\n├── go.mod\n├── go.sum\n└── README.md\n```\n\n---\n\n## Features\n\n### Current\n\n- **Local-network mode** — `gmmff local` is a fully self-contained mode with embedded server, auto TLS, mDNS discovery, and QR code; no internet or external server required\n- **Multi-peer sessions** — `gmmff create --max-peers N` allows 2–10 participants; 2-peer sessions are bidirectional, 3–10 peer sessions broadcast from the initiator to all\n- **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\n- **Signaling server** — Go, Redis-backed, privacy-safe structured logs, Docker-ready\n- **CPace PAKE** — zero-knowledge authentication; server stays blind to the shared secret\n- **SDP MAC binding** — HMAC-signed SDP with HKDF-derived subkeys; prevents MITM via signaling relay\n- **DTLS 1.3** — all data channel traffic encrypted end-to-end via Pion WebRTC\n- **Multi-file and directory transfers** — multiple files and directories zipped on the fly\n- **Transfer queue** — multiple transfers serialized automatically; each gets its own progress bar\n- **Resumable transfers** — partial + meta sidecar files; progress bars pick up at the correct offset\n- **Clean cancellation** — `Ctrl+C` or `\\q` delivers clean messages to all peers; partial file preserved\n- **SHA-256 integrity** — full-file hash verified before `TransferOK` is sent\n- **Secure chat** — pure text chat (`gmmff chat`) or inline messaging within a file session\n- **Sliding window** — configurable in-flight chunks (`--window`); default 2\n- **Configurable chunk size** — up to SCTP maximum 65526 bytes (`--chunk-size`)\n- **STUN multi-server** — append additional STUN servers via `--stun` (repeatable) or `GMMFF_STUN`\n- **TURN support** — long-term and ephemeral credentials, mixed auth types, transport hints, max 3 servers\n- **Browser UI (Wasm)** — same Go source compiled to WebAssembly; Files, Chat, and Schedule tabs\n- **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\n- **Schedule CLI** — `gmmff schedule upload/download/delete` for terminal-based encrypted transfers; full browser↔CLI interoperability\n- **Drag and drop** — drop files anywhere on the browser UI to queue them for sending\n- **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\n- **ICE settings panel** — configurable STUN/TURN in the browser UI, persisted 7 days\n- **Share links + QR codes** — shareable URLs and scannable QR codes on all code screens\n- **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\n\n### Backlog\n\n- **Browser extension** — use your favorite browser to send/receive files\n- **More languages** — 32 languages shipped; contributions welcome\n- **Trusted local CA** — one-time CA install for iOS Safari support in `gmmff local`\n- **Quantum-safe encryption** — post-quantum algorithms with elliptic-curve fallback\n\n### Probably won't do\n\n- wasm webclient: window slider (defaults to 2, 1–16 range)\n- **Password-protected zips** — optional encryption on the zip archive\n\n---\n\n## Inspiration\n\n<p align=\"center\">\n  <a href=\"https://xkcd.com/949\" target=\"_blank\"><img src=\"https://imgs.xkcd.com/comics/file_transfer.png\" alt=\"xkcd comic explaining the difficulties of sending large files between two people\"></a>\n</p>\n\n- [X] [webwormhole](https://github.com/saljam/webwormhole) by [@saljam](https://github.com/saljam)\n- [X] [FilePizza](https://github.com/kern/filepizza) by [@kern](https://github.com/kern) and [@neerajbaid](https://github.com/neerajbaid)\n- [X] [Firefox Send](https://gitlab.com/timvisee/send) by [@mozilla](https://github.com/mozilla/) new fork by [@timvisee](https://github.com/timvisee)\n- [X] [Jirafeau](https://gitlab.com/jirafeau/Jirafeau) by [Jerome Jutteau](https://gitlab.com/mojo42) and many [others](https://gitlab.com/jirafeau/Jirafeau/-/blob/master/AUTHORS.md?ref_type=heads)...\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).  All dependencies are MIT or Apache-2.0.\n",
  "bytes": 14388,
  "sha": "b511e5b7bc6f67f4beb49bef0f04cbcabd52170f9d817db0904cac0a633c6897",
  "repo_slug": "iamdoubz/gmmff",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_iamdoubz_gmmff_openwiki_index_md_991090d0/readme"
}