Commit graph

12 commits

Author SHA1 Message Date
f586cf9fa3 feat: backup & restore built into the admin panel
Neither Remnawave nor Marzban has this natively (community tools only,
per docs.rw's own comparison table) — one-click download of a tar.gz
with a consistent SQLite snapshot (via sqlite3's backup API, safe even
under WAL) plus .env, and upload-to-restore from the same file.

Restore validates the archive is real (gzip + tar structure), that
mbs.db is an actual sqlite database with the expected tables (not
just any file named mbs.db), and rejects oversized uploads — before
touching anything live. Takes a timestamped safety copy of the
current db/.env before overwriting, clears stale -wal/-shm siblings
so the restored file doesn't get replayed against the wrong WAL, and
restarts mbs-bot automatically when .env was part of the restore
(api.py isn't restarted from within its own request handler for the
obvious reason).

Verified with a full round-trip test: backup -> mutate state -> restore
-> confirm the mutation is reverted, plus three negative cases (garbage
data, oversized upload, a fake non-sqlite mbs.db) all correctly
rejected with no side effects.

Needs python-multipart for FastAPI's UploadFile — added to
requirements.txt, picked up by the next 'mbs update'.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 10:23:38 +05:00
f9ee4f5933 fix: 18-point audit pass — payment races, hwid limit bugs, blocking SSH/HTTP in event loops, N+1 queries, ssh host-key pinning, dead code
payments: _grant_paid_subscription now validates plan/node exist before
marking a payment paid instead of after (was leaving charged-but-ungranted
payments with no error trail); mark_payment_paid is now a single atomic
UPDATE ... WHERE status='pending' instead of check-then-act, closing a
double-grant race between webhooks and the periodic reconciler; yookassa
webhook now re-verifies payment status server-side via the API instead of
trusting the posted body (platega already had HMAC verification).

hwid: 'user["hwid_limit"] or FALLBACK' treated an explicit 0 (admin fully
blocking a user) as unset — now an explicit None check. Device count-check
and insert are now one atomic transaction (db.add_device_if_under_limit)
instead of two raceable statements.

perf: payment webhooks and _grant_paid_subscription's SSH/HTTP calls now
run via asyncio.to_thread instead of blocking the event loop; same for
bot.py's periodic_sync/reconcile_pending_payments and the manual admin
sync button. Admin endpoints (traffic/subscriptions/payments/gift-codes/
user-card) now resolve node labels from one db.list_nodes() call instead
of a fresh db.get_node() per row. revoke/reset-traffic use a direct PK
lookup instead of scanning up to 5000 rows. Dashboard now asks the API
for 8 rows instead of fetching 200 and slicing client-side.

security: mbs.db (and -wal/-shm) now chmod 600 right after creation —
it held session tokens and subscription bearer tokens world-readable
by default. Node SSH connections now pin host keys via a persisted
known_hosts file (TOFU) instead of accepting any key on every connection.
delete_node now refuses to delete a node with active subscriptions
instead of silently orphaning their xray clients.

deadcode: removed unused xray_manager.list_client_ids and admin.html's
superseded staggerReveal (rows animate via rowAttr() inline now).

Also guards gift-code redemption against a plan/node deleted after the
code was created (was an unhandled KeyError/TypeError crash).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 22:20:54 +05:00
bfc2fd7b4c settings: change Telegram bot token/username from the admin UI (validated via getMe); mbs restart now covers bot+api+xray+nginx
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 23:29:58 +05:00
04db4a359e ui: dark scrollbars everywhere, Документация section (architecture/nodes/password/fail2ban)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 23:25:37 +05:00
5725922bdc fix: refresh node cache on Gifts/User card open (new nodes weren't showing up); preselect country flag in node edit modal
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 23:06:46 +05:00
f5f8f21f5d payments: status verification (check + auto-reconcile pending), admin Payments view
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:46:55 +05:00
ca6e928f98 design: staggered reveal animation on every table/list row across the panel
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:19:34 +05:00
a275000b5d admin: full user card — subscription history, manual grant, devices/HWID in one modal
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:17:16 +05:00
9a86b8cb03 admin: reset traffic counter per subscription (xray api statsquery -reset)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:14:16 +05:00
fe579430bd hwid: per-user device limit like Remnawave (x-hwid header, opt-in)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:06:15 +05:00
f657644ce6 admin: full node editing (label/address/port/sni/keys), country picker in edit modal
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 18:21:13 +05:00
23bb0da6c0 frontend: admin panel SPA and public site pages
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 17:45:43 +05:00