Unify auth into refresh-token cookie sessions; server-authoritative nodes and Cyberhack
Auth was effectively broken for every login path: the Telegram handler built a Set-Cookie header but never attached it to the response, and Ghost Protocol (seed) login never set a cookie at all — so billing, the game, and admin actions never actually worked once the frontend was fixed to stop trying to read an HttpOnly cookie from JS. Replaced the bare 10-minute JWT with AuthService::issue_session: a 15-minute access cookie plus a rotating 30-day refresh cookie (opaque token, only its SHA-256 hash stored in the new refresh_sessions table); reusing an already- rotated refresh token now revokes every session for that user. CSRF/CORS origin allowlists moved from a single hardcoded domain to env-configured lists so the same session works across the landing and account subdomains. The bot's WebApp deep links (Личный Кабинет/Тарифы/Синдикат) now bridge through a short-lived bootstrap token exchanged via POST /auth/exchange instead of a bare access token in the URL. Nodes: /nodes/routing now serializes the tunnel_* fields, public_key, sni_domain and a one-time session token gated on an active subscription instead of a stub ip/port/protocol list; node provisioning returns 202 immediately and finishes in the background instead of blocking the request for the whole SSH run; a new background task TCP-pings nodes every 60s and flips online/offline itself; admin can now force-restart a node over SSH. Billing: TON exchange rate is cached in Redis (60s) instead of hitting TonAPI on every invoice, and the request/response now actually uses the requested currency and TonAPI's real (uppercase) key casing — previously only USD/RUB were ever requested and the lookup used the wrong case, so non-USD/RUB plans could never price correctly. Cyberhack: the server now generates and stores the board itself and replays the client's raw click path to compute the score, instead of clamping a client-reported number — closes the "final score is whatever the browser sends" hole flagged in the security audit. Frontend: api.ts no longer tries to read the HttpOnly session cookie from JS (that never worked) and instead relies on same-origin credentials plus a silent refresh-and-retry on 401; AdminDashboard's restart/delete actions are wired up; Auth.tsx drops the artificial delays and requires an explicit seed download/confirmation before continuing, since a lost Ghost seed is unrecoverable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
|
||||
1. **`POST /billing/pay/initiate`** (`initiate_payment`) — сервер сам смотрит цену тарифа
|
||||
в нужной валюте (`plan_prices`, см. [`migrations/0001_init.sql`](../../../migrations/0001_init.sql)),
|
||||
запрашивает текущий курс TON у TonAPI, считает сумму в nanoTON с буфером **+2%**
|
||||
берёт курс TON (сначала кеш в Redis — `ton_rate:<currency>`, TTL 60с; на промах —
|
||||
TonAPI, ответ кладётся в кеш), считает сумму в nanoTON с буфером **+2%**
|
||||
(`calculate_ton_invoice` — компенсация волатильности курса между генерацией инвойса и
|
||||
отправкой транзакции юзером) и создаёт `invoices`-запись со статусом `pending`.
|
||||
Клиент **не может повлиять на сумму** — она целиком считается на сервере.
|
||||
Клиент **не может повлиять на сумму** — она целиком считается на сервере. Запрос к
|
||||
TonAPI идёт по коду валюты из инвойса (не захардкожен на `usd,rub`), а ответ
|
||||
разбирается по ключу в ВЕРХНЕМ регистре (`prices.USD`) — так его и отдаёт TonAPI.
|
||||
2. Фронтенд получает `{ destination, amount, comment }` и просит кошелёк (TonConnect)
|
||||
отправить транзакцию с этим `comment` (= `invoice_id`) — по нему инвойс потом находится.
|
||||
3. **`POST /billing/pay/confirm`** (`confirm_payment`) — клиент присылает `tx_hash`
|
||||
@@ -36,8 +39,8 @@
|
||||
`activate_trial` доступен только аккаунтам с `tg_id` (см. [`auth/README.md`](../auth/README.md#sybil-защита))
|
||||
и только один раз (`has_used_trial`).
|
||||
|
||||
## Известные ограничения (см. корневой README «Недоделки»)
|
||||
## Известные ограничения
|
||||
|
||||
Синхронный запрос курса TON на каждый `initiate_payment` и пересборка `providers`
|
||||
(включая повторное чтение env) при каждом `Clone` сервиса — оба помечены `// TODO` прямо
|
||||
в `service.rs`.
|
||||
Пересборка `providers` (включая повторное чтение env) при каждом `Clone` сервиса —
|
||||
axum клонирует `ApiState`, а с ним и `BillingService`, на каждый HTTP-запрос; см. `//
|
||||
TODO` прямо в `service.rs`. Курс TON теперь кешируется (см. выше), это ограничение — нет.
|
||||
|
||||
Reference in New Issue
Block a user