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:
+12
-1
@@ -43,6 +43,14 @@ pub struct ApiState {
|
||||
pub jwt_secret: String,
|
||||
pub bot_token: String,
|
||||
pub admin_tg_id: i64,
|
||||
/// `Domain` для сессионных cookie. Пусто (по умолчанию, локальная разработка) →
|
||||
/// cookie host-only. В проде — `.netrunner-vpn.com`, чтобы одна сессия работала
|
||||
/// и на лендинге, и на ЛК (общий родительский домен, разные сабдомены).
|
||||
pub cookie_domain: String,
|
||||
/// Origin'ы, с которых разрешён cookie-based доступ к мутирующим ручкам
|
||||
/// (CSRF-проверка в `auth::guard`). Отдельно от `CORS_ALLOWED_ORIGINS`, т.к. туда
|
||||
/// же попадают Bearer-клиенты (Tauri), для которых CSRF неактуален.
|
||||
pub csrf_allowed_origins: Vec<String>,
|
||||
}
|
||||
|
||||
impl Clone for ApiState {
|
||||
@@ -57,6 +65,8 @@ impl Clone for ApiState {
|
||||
jwt_secret: self.jwt_secret.clone(),
|
||||
bot_token: self.bot_token.clone(),
|
||||
admin_tg_id: self.admin_tg_id,
|
||||
cookie_domain: self.cookie_domain.clone(),
|
||||
csrf_allowed_origins: self.csrf_allowed_origins.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +119,8 @@ pub fn create_router(state: ApiState, frontend_dir: &str) -> Router {
|
||||
// чтобы помимо веб-фронта пускать и десктоп/мобайл-приложение (Tauri webview).
|
||||
let allowed_origins: Vec<axum::http::HeaderValue> = std::env::var("CORS_ALLOWED_ORIGINS")
|
||||
.unwrap_or_else(|_| {
|
||||
"https://netrunner-vpn.com,tauri://localhost,http://tauri.localhost,\
|
||||
"https://netrunner-vpn.com,https://account.netrunner-vpn.com,\
|
||||
tauri://localhost,http://tauri.localhost,\
|
||||
http://localhost:1420,http://192.168.110.169:1420"
|
||||
.to_string()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user