Anonymous music message sharing platform. Send a song with a secret message — no accounts, no tracking, completely anonymous.
| Layer | Technology |
|---|---|
| Language | Rust (stable) |
| Framework | Axum 0.8 |
| Runtime | Tokio |
| Database | PostgreSQL + SQLx |
| Templating | Askama (auto-escaping) |
| Password hashing | Argon2 |
| Middleware | Tower HTTP (trace, compression, timeout, rate limiting) |
- 100% anonymous — no accounts, no cookies, no tracking
- Password-protected messages — optional Argon2-secured lock
- Expiration — 24h / 7d / 30d / never
- Themes — dark, sunset, ocean, rose
- View counter — unique IP-based
- Embed support — Spotify & YouTube auto-converted to embeds
- Background worker — auto-cleans expired messages every 24h
- Rate limiting — per-IP (60 req/min global, 5 creates/hour)
soundofus/
├── Cargo.toml
├── .env.example
├── migrations/
│ └── 002_anonymous_messages.sql
├── src/
│ ├── main.rs # Entrypoint, middleware stack, server
│ ├── routes.rs # Router definition
│ ├── handlers.rs # Request handlers + template rendering
│ ├── models.rs # Structs, validation, Argon2, embed helpers
│ ├── db.rs # Pool, migrations, queries
│ ├── error.rs # Unified AppError enum
│ ├── middleware.rs # IP-based rate limiter
│ └── worker.rs # Background cleanup task
├── templates/
│ ├── index.html # Create-message form
│ ├── message.html # View message (themed)
│ └── password.html # Password unlock form
└── static/ # Static assets
- Rust (stable) — rustup.rs
- PostgreSQL 14+
git clone <repo-url> && cd soundofus
cp .env.example .env
# Edit .env → set your DATABASE_URLcreatedb soundofusMigrations run automatically on startup. To run manually:
psql -d soundofus -f migrations/002_anonymous_messages.sqlcargo run
# → http://localhost:3000- Open
http://localhost:3000 - Write a message, paste a Spotify/YouTube link, pick options
- Submit → redirected to
/m/{uuid}with the embedded song - Share the link!
| Method | Path | Description |
|---|---|---|
GET |
/ |
Homepage — create message form |
POST |
/create |
Create anonymous message → redirect |
GET |
/m/{uuid} |
View message (or password gate) |
POST |
/m/{uuid}/unlock |
Submit password to unlock |
GET |
/static/* |
Static file serving |
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | — | PostgreSQL connection string |
PORT |
No | 3000 |
HTTP listen port |
RUST_LOG |
No | soundofus=debug,tower_http=debug |
Tracing filter |
| Column | Type | Notes |
|---|---|---|
id |
UUID (PK) | Generated v4 |
message |
TEXT | Max 1000 chars |
song_url |
TEXT | Original URL |
song_platform |
TEXT | "spotify" / "youtube" / "other" |
theme |
TEXT | "dark" / "sunset" / "ocean" / "rose" |
expires_at |
TIMESTAMPTZ NULL | Optional expiration |
password_hash |
TEXT NULL | Argon2 hash |
views |
INTEGER | Unique-IP view count |
created_at |
TIMESTAMPTZ | Auto |
deleted_at |
TIMESTAMPTZ NULL | Soft delete |
| Column | Type | Notes |
|---|---|---|
id |
SERIAL (PK) | Auto |
message_id |
UUID (FK) | → messages.id |
ip_address |
TEXT | Client IP |
viewed_at |
TIMESTAMPTZ | Auto |
Unique constraint on (message_id, ip_address).
- SQL injection — parameterized queries (SQLx)
- XSS — Askama auto-escapes all template variables
- Password — Argon2id hashing with random salt
- Rate limiting — in-memory per-IP limiter with periodic cleanup
- Timeouts — 30s request timeout via Tower
- Compression — gzip response compression
- Input validation — length limits, URL parsing, theme whitelist
cargo build --releaseBinary: target/release/soundofus (or .exe on Windows).
DATABASE_URL=postgres://user:pass@host/soundofus PORT=8080 ./target/release/soundofusMIT