A zero-knowledge secret sharing service built with Go. Secrets are encrypted client-side before storage — the server never holds plaintext data or decryption keys.
- Create — the client sends a secret via
POST /secrets. The server generates a random AES-256 key, encrypts the content, stores only the ciphertext, and returns a singleurlfield containing the complete shareable link (incorporating the secret ID and decryption key) to the caller. - Share — the caller shares the returned link. Since the key is never stored on the server, only someone with the full link can read the secret.
- Read — on first access the server decrypts the content on the fly, returns it, and immediately deletes the record (burn-on-read). A background worker also purges any time-expired secrets every 5 minutes.
POST /secrets → { url }
GET /secrets/{id}?key → { content } (then deleted)
| Layer | Technology |
|---|---|
| Language | Go 1.26 |
| Database | PostgreSQL via Supabase |
| Crypto | AES-256-GCM (stdlib crypto/aes) |
| Container | Docker (multi-stage build, ~15 MB) |
| Hosting | Render (Docker runtime) |
fugax/
├── cmd/api/
│ └── main.go # Entry point — server, router, background worker
├── internal/
│ ├── crypto/
│ │ └── crypto.go # AES-256-GCM encrypt / decrypt
│ ├── db/
│ │ └── db.go # PostgreSQL connection pool and queries
│ └── handler/
│ └── handler.go # HTTP handlers and route registration
├── Dockerfile
└── docker-compose.yml
curl -X POST http://localhost:8080/secrets \
-H "Content-Type: application/json" \
-d '{
"content": "my secret",
"burn_on_read": true,
"expires_in_minutes": 60
}'Response:
{
"url": "http://localhost:8080/secrets/550e8400-e29b-41d4-a716-446655440000?key=3f9a2c8b..."
}curl "http://localhost:8080/secrets/<id>?key=<key>"Response:
{
"content": "my secret"
}The record is deleted immediately after this response. A second request returns 404.
Prerequisites: Go 1.26+, Docker, a Supabase project.
- Clone the repo and create a
.envfile:
DATABASE_URL=postgresql://postgres:[password]@[host]:6543/postgres
APP_PORT=8080
APP_BASE_URL=http://localhost:8080Important
Production / Render Configuration: In production, remember to set the APP_BASE_URL environment variable (e.g. https://fugax.onrender.com) in your deployment environment (like the Render dashboard) so the system generates shareable URLs using your live domain.
- Create the
secretstable in Supabase SQL Editor:
CREATE TABLE secrets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
encrypted_content TEXT NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE,
burn_on_read BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);- Run directly with Go:
go run ./cmd/apiOr with Docker Compose:
docker compose up- Zero-knowledge: the server stores only AES-256-GCM ciphertext. The decryption key is returned once at creation time and never persisted.
- Nonce: a fresh random nonce is generated per encryption and prepended to the ciphertext, ensuring that two encryptions of the same plaintext produce different outputs.
- Burn-on-read: secrets are deleted from the database immediately after the first successful read.
- TTL: an optional
expires_in_minutesfield sets a hard expiry. A goroutine-based background worker purges expired records every 5 minutes. - No logging of plaintext: handlers only log errors, never request content.