Lightweight web UI for Magic Wormhole built with Go and vanilla JavaScript. End-to-end encryption, real-time progress, ~15MB Docker image.
- TypeScript 40.5%
- JavaScript 28.1%
- Go 16.9%
- CSS 13.1%
- HTML 0.8%
- Other 0.6%
| .forgejo | ||
| src | ||
| static | ||
| .dockerignore | ||
| .gitignore | ||
| bun.lock | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| main_test.go | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
magic-wormhole-web
A modern web UI for Magic Wormhole file transfers. Built with Go and vanilla JavaScript — send files, folders, and encrypted messages between devices using a short wormhole code.
Features
- File and folder transfer (folders are zipped on the fly)
- Text messages (snippets, codes, links)
- End-to-end encryption built in via Magic Wormhole's PAKE handshake; optional additional AES-256-GCM password layer
- Real-time progress over WebSocket
- System-aware light/dark theme
- Responsive desktop / mobile UI
- Zero frontend dependencies — pure vanilla JS, no framework
Quick Start
Docker (pre-built image)
docker run -p 8080:8080 git.neomint.com/nm/magic-wormhole-web:latest
Open http://localhost:8080.
Docker Compose
docker compose up -d
Build locally
docker build -t magic-wormhole-web .
docker run -p 8080:8080 magic-wormhole-web
Native (Go + Bun)
bun install
bun run build # typecheck + lint + bundle TS to static/
go mod tidy
go run . # serves on :8080
Usage
Sending Files
- Click the Send tab
- Drag & drop files/folders or click to browse
- Optionally enable encryption and set a password
- Click Send to generate a wormhole code
- Share the code (and password, if encrypted) with the recipient
Receiving Files
- Click the Receive tab
- Enter the wormhole code (format:
number-word-word) - If encrypted, enter the password when prompted
- Download or copy the received content
Configuration
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP server port |
Architecture
wormhole-web/
├── main.go # Go backend server
├── static/
│ ├── index.html # Single-page app shell
│ ├── app.js # Application logic
│ ├── styles.css # App styles with CSS variables
│ ├── particles.js # Particle animation system
│ └── particles.css # Particle styles (standalone)
├── Dockerfile # Multi-stage build
└── docker-compose.yml # Container orchestration
Backend (Go)
- Embedded static files using
go:embed - WebSocket support for real-time progress updates
- Automatic temp file cleanup
- Uses wormhole-william for Magic Wormhole protocol
Frontend (Vanilla JS)
- State-based rendering without virtual DOM
- CSS custom properties for theming
- Web Crypto API for client-side encryption
- File System Access API for native save dialogs
Particle Animation System
The particle animation is a standalone module that can be reused:
<link rel="stylesheet" href="particles.css">
<script src="particles.js"></script>
<div class="particle-container" id="container"></div>
<script>
const container = document.getElementById('container');
// Start animation
initParticles(container, 'up'); // Stream upward
initParticles(container, 'down'); // Stream downward
initParticles(container, 'drift'); // 3D rotating sphere
// Morph to shapes
morphParticlesToCheck(container); // Green checkmark
morphParticlesToError(container); // Red X
// Transitions
transitionToDrift(container); // Smooth stream-to-sphere transition
</script>
Customize colors via CSS variables:
:root {
--particle-color: #2563eb; /* Default particle color */
--particle-success: #16a34a; /* Checkmark color */
--particle-error: #ef4444; /* Error X color */
}
API Reference
POST /api/send/text
Send a text message.
{ "text": "Hello, world!" }
POST /api/send/file
Send files via multipart form data.
file: Single file uploadfiles: Multiple filespaths: JSON array of file paths (for folder structure)
POST /api/receive
Receive content using a wormhole code.
{ "code": "7-guitarist-revenge" }
GET /api/ws?id={transferId}
WebSocket endpoint for real-time transfer status updates.
GET /api/download/{transferId}/{filename}
Download received files.
Security
- All transfers use Magic Wormhole's PAKE-based encryption
- Optional additional AES-256-GCM encryption for sensitive content
- No data stored on server after transfer completion
- Automatic cleanup of expired transfers (1 hour TTL)
- Path traversal protection on file downloads
- Input validation on wormhole codes and transfer IDs
License
MIT — © 2026 NeoMINT Research
Built by NeoMINT.