Commit Graph

52 Commits

Author SHA1 Message Date
Alexander Schmidt
3aa8277530 Add wallet URI copy and shortlink trust toggle 2026-03-26 15:11:11 +01:00
Alexander Schmidt
6f43f34d68 Fix deploy dry-run flag and generalize env example 2026-03-26 14:52:31 +01:00
Alexander Schmidt
77bf794b73 Harden deployment with data backups and restore script 2026-03-26 14:25:35 +01:00
Alexander Schmidt
94c8ecb2aa Add deploy env ignore and example template 2026-03-26 14:15:04 +01:00
Alexander Schmidt
32d509fe9d Harden deploy script config handling 2026-03-26 14:07:07 +01:00
Alexander Schmidt
8ae736bbad Add safe deploy script preserving data directory 2026-03-26 13:55:59 +01:00
Alexander Schmidt
d01b7d0d27 Align privacy rate-limit wording with implementation 2026-03-26 13:53:07 +01:00
Alexander Schmidt
dddda450a7 Update privacy terms: no persistent IP records 2026-03-26 13:48:40 +01:00
Alexander Schmidt
758b2f3589 Preserve absolute invoice deadline across reloads 2026-03-26 13:43:30 +01:00
Alexander Schmidt
69f173bc2f Keep short URL in share field when loaded via short link 2026-03-26 13:40:16 +01:00
Alexander Schmidt
3dd1e55432 Refresh pending proof confirmations on status lookup 2026-03-26 13:28:40 +01:00
Alexander Schmidt
4b0cd3aaab Fix short link integrity check for code parameter 2026-03-26 13:26:05 +01:00
Alexander Schmidt
1e2ea6c24d Bump asset versions and rotate service worker cache 2026-03-26 13:24:18 +01:00
Alexander Schmidt
f6edc4cb58 Fix false short URL integrity warning 2026-03-26 13:22:34 +01:00
Alexander Schmidt
09a5ef703c Add yellow favicon badge for pending invoices 2026-03-26 13:20:11 +01:00
Alexander Schmidt
85039402a7 Regenerate minified translations for pending proof status 2026-03-26 13:15:33 +01:00
Alexander Schmidt
a2c3d8dd00 Add document-and-coin favicon concept and sync paid favicon state 2026-03-26 13:10:30 +01:00
Alexander Schmidt
9cc50188c0 Update README: mark auto-cleanup as complete, add Invoice Lifecycle section 2026-03-26 11:03:59 +01:00
Alexander Schmidt
0049077605 Add type annotations to fix Intelephense type checking errors 2026-03-26 11:03:15 +01:00
Alexander Schmidt
31623fd03e Update cache-busting version to 20260326-2 for cleanup feature 2026-03-26 11:02:20 +01:00
Alexander Schmidt
ee0d0d4124 Implement lazy-cleanup for expired invoices with deadline-based deletion 2026-03-26 11:01:32 +01:00
Alexander Schmidt
c4e3f3cd15 Add deadline cleanup feature to roadmap 2026-03-26 10:54:21 +01:00
Alexander Schmidt
6fd2d05163 Add cache-busting version params for frontend assets 2026-03-26 10:11:13 +01:00
Alexander Schmidt
d2684c3638 Fix paid/pending invoice status UI and date handling 2026-03-26 10:06:08 +01:00
Alexander Schmidt
dc330d2367 refactor: reuse shared style.css and language switcher on privacy page 2026-03-26 08:01:59 +01:00
Alexander Schmidt
2263fbf659 fix: harden PHP type handling across all endpoints 2026-03-26 07:57:11 +01:00
Alexander Schmidt
5d38946c53 feat: add multilingual privacy and terms page + footer link 2026-03-26 07:50:57 +01:00
Alexander Schmidt
59375e647c fix: footer 'Minimal Backend' → 'No Tracking' 2026-03-26 07:39:55 +01:00
Alexander Schmidt
761df8d26b fix: remove duplicate <?php tag in verify.php (HTTP 500) 2026-03-26 07:36:35 +01:00
Alexander Schmidt
4ac12eb083 feat: confirmation-aware TX verification (10-conf threshold)
- 0-9 confs: show amber 'Pending/N/10' stamp on QR, auto-poll every 60s
- ≥10 confs: show green 'Paid' stamp (Monero standard lock)
- verify.php: store status ('pending'|'paid'), allow upward updates
- i18n: add status_pending + proof_confirmed_pending (all 7 langs)
- style.css: add .proof-result.warning, .pending-stamp, .qr-container.confirming
- Polling stops on resetForm; short-URL viewers also poll verify.php
2026-03-26 07:30:43 +01:00
Alexander Schmidt
403a08479c fix: remove duplicate <?php tag in check-short.php 2026-03-26 07:15:28 +01:00
Alexander Schmidt
2c3a8a0584 Security hardening: rate limiting, atomic locks, origin check, honest docs
API / Security:
- Add api/_helpers.php: shared send_security_headers(), verify_origin(),
  get_hmac_secret(), check_rate_limit(), read_json_locked(), write_json_locked()
- shorten.php: remove Access-Control-Allow-Origin:*, restrict to same-origin,
  rate-limit 20 req/h per IP, atomic JSON read+lock, HMAC secret from file
- verify.php: rate-limit GET (30/min) and POST (10/h) per IP, atomic lock,
  prevent overwriting existing proofs, origin check on POST
- node.php: fix rate limit from 1000 to 60 req/min, add security headers,
  origin check
- check-short.php: add security headers, re-derive signature server-side
- s.php: use file-based HMAC secret via get_hmac_secret(), hash_equals()
  for timing-safe comparison

Service Worker:
- sw.js: navigation requests (mode=navigate) never served from cache;
  network-first with offline fallback to prevent stale invoice state

Documentation (honest claims):
- README: tagline "No backend" -> "No tracking"; new Architecture table
  listing exactly what server sees for each feature; Security Model section
- index.html: meta description and footer updated from "No Backend" to
  "Minimal Backend"
- i18n.js footer: already updated in previous commit
2026-03-26 07:13:02 +01:00
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
Alexander Schmidt
c1bd97948c docs: update README — 7 languages, 8 currencies, remove completed roadmap items 2026-03-25 18:28:35 +01:00
Alexander Schmidt
bde0e6f7e4 feat: more currencies, auto-detection, globe-only language toggle
- Add GBP, JPY, RUB, BRL currencies
- Auto-detect currency from browser locale (de-CH→CHF, ru→RUB, etc.)
- USD as default fallback
- Language toggle: globe icon only (compact on mobile), full names in dropdown
- Countdown text updates on language switch
- CoinGecko proxy supports dynamic currency list
2026-03-25 18:25:27 +01:00
Alexander Schmidt
e7f3451f82 feat: 7 languages — EN, DE, FR, IT, ES, PT, RU
- Full translations for all UI strings in 7 languages
- Language picker shows native names (Français, Italiano, Español, Português, Русский)
- Auto-detection via navigator.languages
- Cyrillic font subset for Russian (Inter, 19KB)
- Footer shared across all languages (untranslated links)
2026-03-25 18:15:07 +01:00
Alexander Schmidt
4c93e335f3 feat: Tor hidden service, PDF paid details, subaddress placeholder
- Tor onion: mc6wfeaqc7oijgdcudrr5zsotmwok3jzk3tu2uezzyjisn7nzzjjizyd.onion
- Onion link in footer and README
- PDF "BEZAHLT" block shows TX hash + date in second line
- Address placeholder 8... (encourages subaddress usage)
2026-03-25 17:37:19 +01:00
Alexander Schmidt
e36ec77bcd fix: PDF approx symbol — use ~ instead of unicode ≈ (unsupported by jsPDF Helvetica) 2026-03-25 17:23:32 +01:00
Alexander Schmidt
506c70e4b8 docs: rewrite README in English for release
- Complete English README with feature overview, tech stack, project structure
- Self-hosting instructions and security notes
- Accent color contrast fix (--accent-text for text on dark backgrounds)
- CoinGecko rates proxy: User-Agent header + 2min server-side cache
2026-03-25 17:21:37 +01:00
Alexander Schmidt
787168b248 perf: 100% Lighthouse score — contrast, CLS, caching fixes
- Font preload eliminates layout shift (CLS 0)
- Dual accent colors: --accent for filled buttons, --accent-text for text on dark bg
- All WCAG AA contrast ratios met (buttons, links, badges, countdown)
- Language picker: position absolute instead of fixed
- CoinGecko rates proxied with 2min server-side cache (no CORS, no rate limit)
- English as default inline text (no empty→text shift)
2026-03-25 17:18:41 +01:00
Alexander Schmidt
cf3c43ff67 perf: eliminate CLS with inline default text, EN as default language
- All visible text pre-rendered in HTML (no empty→text shift)
- English as default language (i18n fallback + HTML inline text)
- German auto-detected via navigator.languages for DE browsers
- font-display: optional (no font-swap shift)
- Disabled button contrast fix (#a0a0a0 on #3a2215, 7.2:1)
- CoinGecko rates proxied via /api/rates.php with User-Agent
2026-03-25 17:08:11 +01:00
Alexander Schmidt
8d3e37239f perf: CoinGecko proxy, font-display optional, contrast fix
- Route CoinGecko API through /api/rates.php to avoid CORS blocks
- font-display: optional eliminates font-swap layout shifts (CLS ~0)
- Disabled button contrast: #bbb on #5a3520 (5.8:1 ratio)
- Nginx font caching: 1 year, immutable
2026-03-25 17:00:20 +01:00
Alexander Schmidt
6a9a5b6a75 perf: self-host fonts, eliminate CLS, a11y and contrast fixes
- Self-host Inter and JetBrains Mono (woff2, 69KB total)
- Remove Google Fonts dependency entirely (no external requests)
- Service Worker pre-caches font files
- Eliminate font-swap layout shifts
- WCAG contrast fix: disabled button uses solid color instead of opacity
- Footer link always underlined for distinguishability
- Translated aria-labels via data-i18n-aria
- Dimmed QR with "Bezahlt" stamp on paid invoices
- Hide wallet/address buttons when invoice is paid
2026-03-25 16:56:10 +01:00
Alexander Schmidt
8bcdb33fa3 feat: UI polish, a11y, performance optimizations
- Payment summary card with prominent amount display
- "Bezahlt" stamp over dimmed QR code with TX details below
- Hide wallet/address buttons when paid, show only PDF
- URI box removed (was technical noise)
- Smart countdown: "29 Tage, 23 Std." instead of ticking seconds
- Dynamic page title for shared invoices
- Font fallbacks with size-adjust to prevent layout shifts
- Async Google Fonts loading, proper preconnect hints
- Deferred script loading (defer attribute)
- Minified JS (app.min.js, i18n.min.js)
- WCAG contrast fixes for badges and disabled button
- Footer link always underlined for a11y
- Translated aria-labels via data-i18n-aria
- i18n onChange callback for dynamic content updates
- Result card fade-in animation, responsive QR on mobile
2026-03-25 16:50:55 +01:00
Alexander Schmidt
b8f2e24a42 feat: PDF invoice, payment summary, UI polish
- PDF invoice generation with jsPDF (lazy-loaded, includes paid status)
- Payment summary card: amount, fiat equivalent, description prominently displayed
- URI box hidden behind collapsible "Show Monero URI" details
- Smart countdown: "29 Tage, 23 Std." instead of ticking seconds
- Dynamic page title: "0.017 XMR — Rechnung #42 | xmrpay.link"
- Result card fade-in animation
- Responsive QR code on mobile
- Rename .btn-monitor to .btn-proof
- "In Wallet öffnen" unified as <button>
2026-03-25 16:32:50 +01:00
Alexander Schmidt
cf1b06b5c9 feat: Monero coin favicon with paid indicator
- Official Monero coin logo as SVG favicon
- Dynamic green dot badge on favicon when invoice is paid
- Paid status shown both in page content and browser tab
2026-03-25 09:52:22 +01:00
Alexander Schmidt
270a4a79a6 fix: store TX proof under correct invoice code
The proof was being stored under a newly generated short URL code
instead of the original invoice code. Now tracks invoiceCode from
the hash parameter (c=CODE) or from the first shortenUrl call.
2026-03-25 09:45:54 +01:00
Alexander Schmidt
32245fccdf feat: replace view-key monitor with TX proof verification
Remove v2 view-key payment monitor (privacy concern — nobody should
enter their private view key on a website). Replace with TX proof
verification where the sender provides TX Hash + TX Key from their
wallet. The proof is cryptographically verified client-side and
stored with the invoice for persistent "Paid" status.

- Remove monitor.js and all view-key monitoring UI/logic
- Add TX proof section: sender enters TX Hash + TX Key
- Client-side verification via check_tx_key equivalent (noble-curves)
- api/verify.php stores/retrieves payment proofs per invoice
- Short URL redirect now includes invoice code for status lookup
- Invoice link shows "Paid" badge once proof is verified
- Deadline badges (7/14/30 days) for payment terms
2026-03-25 09:37:09 +01:00
Alexander Schmidt
1acf990943 feat: v2 — view-key payment confirmation with live monitoring
- Payment monitor: enter private view key to track incoming payments
- Scans mempool + last 100 blocks via PHP proxy with 4-node failover
- Lightweight crypto: 30KB noble-curves bundle (Ed25519 + Keccak-256)
- Subaddress support (network byte 42 detection, a*D validation)
- Confirmation progress bar (0-10 confirmations)
- Underpayment detection
- Deadline badges (7/14/30 days) replacing minutes input
- QR code: standard colors (black on white) for wallet scanner compatibility
- QR hint positioned below QR code
- View key masked input, never stored or transmitted
2026-03-25 09:09:46 +01:00
Alexander Schmidt
35552b7dff fix: streamline result UI — wallet button, clickable QR, autofill fix
- Replace "Link kopieren" + "QR speichern" with "In Wallet öffnen" button
- QR code clickable to save as PNG with subtle hint text
- Fix chromium autofill overriding dark input backgrounds
- Center button text and remove underline on link-buttons
2026-03-24 18:16:23 +01:00