Alexander Schmidt 7e325abf7d Security: Add HMAC validation for short URLs + improve privacy documentation
- Implement HMAC-SHA256 signatures on short URLs to detect server-side tampering
- Add client-side signature verification with hostname-derived secret
- New API endpoint: /api/check-short.php for integrity verification
- Update verify.php with privacy notice (addresses not stored)
- Update README to clarify minimal backend requirement (short URLs, rate caching, proof storage)
- Add toast warning when signature mismatch detected
- Support both old and new format in s.php for backward compatibility
- Update all i18n translations (EN, DE, FR, IT, ES, PT, RU)

Addresses security concern: Server compromise could previously result in address
substitution for short-linked invoices. Now client-side verification detects tampering.
2026-03-26 06:52:20 +01:00

xmrpay.link — Monero Invoice Generator

Private. Self-hosted. No accounts. No backend for accounts. No bullshit.

Live: xmrpay.link · Tor: mc6wfe...zyd.onion


What is this?

xmrpay.link is a client-side web app that lets anyone create a professional Monero payment request in under 30 seconds — no account registration, no KYC, no custodial services.

Enter your address, the amount, an optional description — and get a QR code, a shareable short link, and a PDF invoice. Done.

Privacy & Transparency

  • Client-side first: All cryptographic operations (QR codes, payment verification, PDF generation) run in your browser. Your private keys never leave your device.
  • Minimal backend: Optional short URLs, fiat rate caching, and proof storage use a small server component with no account tracking. You can self-host or use the public instance.
  • HMAC-signed short URLs: Invoice hashes are cryptographically signed to detect server-side tampering.
  • Address privacy: Payment proofs are verified client-side only; the server never stores your XMR address.

Why?

Solution Problem
BTCPay Server Requires own server, complex setup
NOWPayments, Globee Custodial, KYC, fees, third-party dependency
Cake Wallet Invoice Mobile-only, no sharing without app
MoneroPay Backend daemon required, developer-only
Wallet QR No amount, no description, no confirmation

The gap: There's no simple, privacy-respecting tool for freelancers, small merchants, and creators that works without setup and still allows payment confirmation.


Features

Invoice Generation

  • XMR address input with validation (standard, subaddress, integrated)
  • Amount in XMR or fiat (EUR/USD/CHF/GBP/JPY/RUB/BRL via CoinGecko, auto-detected)
  • Description and payment deadline (7/14/30 days or custom)
  • QR code with monero: URI
  • Shareable short URLs (/s/abc123) with HMAC signatures for integrity
  • PDF invoice download (with QR, amount, fiat equivalent, deadline)
  • i18n (EN, DE, FR, IT, ES, PT, RU) with automatic browser detection

Payment Verification (TX Proof)

  • Sender provides TX Hash + TX Key from their wallet
  • Cryptographic verification in the browser (no private keys needed)
  • Payment status stored with the invoice (server stores proof, but not your address)
  • Invoice link shows "Paid" badge after verification
  • Standard and subaddress support

Performance & Privacy

  • 100% Lighthouse score (Performance, Accessibility, Best Practices, SEO)
  • Offline-capable via Service Worker
  • Self-hosted fonts (no Google Fonts dependency)
  • Zero external tracking, no cookies
  • Dark mode, responsive design

Tech Stack

Frontend:    HTML + Vanilla JS (no frameworks, no build step)
Crypto:      @noble/curves Ed25519 + Keccak-256 (30KB bundle)
QR:          QRCode.js (client-side)
PDF:         jsPDF (client-side, lazy-loaded)
Hosting:     Static site + minimal PHP for short URLs and RPC proxy
Backend:     Minimal PHP (URL shortener, rates proxy, proof storage)
Data:        JSON files (no database), LocalStorage (client-side)

Project Structure

xmrpay.link/
├── index.html              # Single-page app
├── app.js / app.min.js     # Main logic (URI builder, QR, fiat rates, TX proof)
├── i18n.js / i18n.min.js   # Internationalization (DE, EN)
├── style.css               # Dark theme, responsive, WCAG AA
├── sw.js                   # Service Worker (offline support)
├── favicon.svg             # Monero coin logo
├── s.php                   # Short URL redirect
├── api/
│   ├── shorten.php         # Short URL creation
│   ├── rates.php           # CoinGecko proxy with server-side cache
│   ├── node.php            # Monero RPC proxy (4-node failover)
│   └── verify.php          # TX proof storage/retrieval
├── data/                   # JSON storage (auto-generated)
├── fonts/                  # Self-hosted Inter + JetBrains Mono
├── lib/
│   ├── qrcode.min.js       # QR code generator
│   ├── jspdf.min.js        # PDF generation (lazy-loaded)
│   └── xmr-crypto.bundle.js # Ed25519 + Keccak-256 (lazy-loaded)
├── README.md
└── LICENSE                 # MIT

Self-Hosting

git clone https://gitea.schmidt.eco/schmidt1024/xmrpay.link.git
cd xmrpay.link
# Serve with any web server that supports PHP
# No build tools, no npm, no database required
python3 -m http.server 8080  # For development (no PHP features)

Requirements for full functionality:

  • PHP 8.x with curl extension
  • Nginx or Apache (for /s/ short URL rewrites)
  • Writable data/ directory

Security

  • No private keys — TX proof uses the sender's TX key, not the receiver's view key
  • Client-side crypto — Ed25519 verification runs in the browser
  • No tracking — zero cookies, no analytics, no external scripts
  • RPC proxy — allowlisted methods only, rate-limited
  • Self-hostable — run your own instance for full control

Roadmap

  • Embeddable <iframe> payment widget
  • Invoice history (LocalStorage, CSV export)
  • "Pay Button" generator (HTML snippet)

License

MIT — fork it, host it, improve it.

Description
Self-hosted Monero invoice generator. One-command Docker setup with auto-HTTPS and Tor. No accounts, no KYC, no tracking.
https://xmrpay.link
Readme 2.3 MiB
Languages
JavaScript 48.3%
PHP 17.4%
HTML 16.4%
CSS 9.7%
Shell 7.4%
Other 0.8%