From 83991f098be025028fd40c86eed3e13060d0aa1d Mon Sep 17 00:00:00 2001 From: NW Date: Wed, 8 Jul 2026 21:59:16 +0100 Subject: [PATCH] v1.2.0: disable CSRF for Tor, fix wallet type validation, add version history modal - fix(admin/csrf): completely disable CSRF checks for Tor/onion compatibility - fix(validators): add 'main' and 'bonus' to WALLET_TYPES for purchase flow - feat(admin): add clickable version tag with version history modal in sidebar - docs: add VERSION.md with changelog and update instructions --- VERSION.md | 34 ++++++++++++++++ src/admin/csrf.js | 44 ++------------------ src/admin/views/partials/app-sidebar.ejs | 51 +++++++++++++++++++++++- src/utils/validators.js | 2 +- 4 files changed, 87 insertions(+), 44 deletions(-) create mode 100644 VERSION.md diff --git a/VERSION.md b/VERSION.md new file mode 100644 index 0000000..0a059fe --- /dev/null +++ b/VERSION.md @@ -0,0 +1,34 @@ +# Telegram Shop — Version History + +## How to update version + +1. Edit this file (`VERSION.md`) +2. Add new entry under `## Changelog` +3. Bump version in `src/admin/views/partials/app-sidebar.ejs` +4. Commit all changes together + +## Current Version + +**v1.2.0** — 2026-07-08 + +## Changelog + +### v1.2.0 — 2026-07-08 +- **fix**: Disabled CSRF checks in admin panel for Tor / onion zone compatibility +- **fix**: Fixed "Invalid wallet type" error in Telegram bot purchase flow (`main`/`bonus` types added to validator) +- **feat**: Added version history modal in admin sidebar + +### v1.1.0 — 2026-07-02 +- **feat**: Mercuryo gateway integration, crypto QR deposit, mono products, wallet auto-refresh +- **fix**: CSRF cookie `sameSite=false` for Tor, auth cookie fix, async handlers +- **feat**: Draggable dashboard panels + business KPI redesign +- **fix**: SmartAdmin template redesign + security hardening + +### v1.0.0 — 2026-06-24 +- **feat**: Initial release — Telegram shop bot with admin panel +- **feat**: Crypto wallets (BTC, LTC, ETH, USDT, USDC) +- **feat**: Product catalog with locations, categories, subcategories +- **feat**: Purchase system with hidden content delivery +- **feat**: Admin panel with dashboard, wallets, users, purchases, audit log +- **feat**: Tor proxy support (.onion access) +- **feat**: i18n localization (en/es/de) diff --git a/src/admin/csrf.js b/src/admin/csrf.js index ff23e99..c2a4592 100644 --- a/src/admin/csrf.js +++ b/src/admin/csrf.js @@ -23,53 +23,15 @@ export function csrfMiddleware(req, res, next) { } export function validateCsrf(req, res, next) { - // Only validate state-changing methods - if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return next(); - - // Skip multipart/form-data — multer hasn't parsed the body yet. - // Route handlers using multer must validate CSRF themselves after parsing. - const ct = req.headers['content-type'] || ''; - if (ct.startsWith('multipart/form-data')) return next(); - - const token = req.body?._csrf || req.headers[CSRF_HEADER]; - const cookieToken = req.cookies?.[CSRF_COOKIE]; - - if (!token || !cookieToken) { - logger.warn({ ip: req.ip, url: req.originalUrl, method: req.method, hasBodyToken: !!token, hasCookieToken: !!cookieToken, contentType: ct }, 'CSRF token missing'); - return res.status(403).send('CSRF token missing. Please reload the page.'); - } - - const provided = Buffer.from(token, 'utf8'); - const expected = Buffer.from(cookieToken, 'utf8'); - if (provided.length !== expected.length || !crypto.timingSafeEqual(provided, expected)) { - logger.warn({ ip: req.ip, url: req.originalUrl, method: req.method }, 'CSRF token mismatch'); - return res.status(403).send('CSRF token invalid. Please reload the page.'); - } - - next(); + // CSRF checks disabled for Tor / onion zone compatibility + return next(); } /** * Validate CSRF token from req.body._csrf (for use inside multer handlers). * Returns true if valid, false otherwise. Sends 403 response on failure. + * NOTE: Disabled for Tor / onion zone compatibility. */ export function validateCsrfFromBody(req, res) { - const token = req.body?._csrf; - const cookieToken = req.cookies?.[CSRF_COOKIE]; - - if (!token || !cookieToken) { - logger.warn({ ip: req.ip, url: req.originalUrl, method: req.method }, 'CSRF token missing (multipart)'); - res.status(403).send('CSRF token missing. Please reload the page.'); - return false; - } - - const provided = Buffer.from(token, 'utf8'); - const expected = Buffer.from(cookieToken, 'utf8'); - if (provided.length !== expected.length || !crypto.timingSafeEqual(provided, expected)) { - logger.warn({ ip: req.ip, url: req.originalUrl, method: req.method }, 'CSRF token mismatch (multipart)'); - res.status(403).send('CSRF token invalid. Please reload the page.'); - return false; - } - return true; } diff --git a/src/admin/views/partials/app-sidebar.ejs b/src/admin/views/partials/app-sidebar.ejs index 7e833c3..de5c57b 100644 --- a/src/admin/views/partials/app-sidebar.ejs +++ b/src/admin/views/partials/app-sidebar.ejs @@ -24,15 +24,62 @@