v1.0.16.13 — TSPU/SNI-obkhod: domain selection at login + dynamic mirrors
- add DomainSelector: probe every API candidate at launcher startup, pick
fastest reachable (primary api.zern.cc, legacy .ru/.online, geo pl/swe);
integrate into CLI start and JFX network init
- Config.setServerUrl() + persist chosen domain in launcher.properties
- ZHttpClient: default BASE_URL and ZERN_SERVER health-check follow the
selected domain (runtime failover instead of hardcoded api.zernmc.ru)
- server: LAUNCHER_MIRRORS main=api.zern.cc (primary), legacy .ru/.online,
geo-pl api.pl.zern.cc, geo-swe api.swe.zern.cc; /launcher/mirrors exposes them
- diag: check all TLD+geo API hosts (api.{pl,ru,swe}.zern.cc, .ru, .online)
for DNS/TCP/HTTP, known server IPs for all 4 geo nodes
- reverse-proxy geo boxes (pl, swe) -> main:1582 so clients bypass TSPU via
an unblocked SNI; ru left as-is (VLESS VPN box, not proxying API)
This commit is contained in:
@@ -383,6 +383,7 @@ async def register(body: RegisterRequest, request: Request):
|
||||
|
||||
allowed, wait = check_rate_limit(ip)
|
||||
if not allowed:
|
||||
logger.warning("register rate limited", username=body.username, client_ip=ip)
|
||||
raise HTTPException(429, f"Слишком много попыток. Подождите {wait} секунд")
|
||||
|
||||
with get_db() as conn:
|
||||
@@ -392,6 +393,7 @@ async def register(body: RegisterRequest, request: Request):
|
||||
).fetchone()
|
||||
|
||||
if existing:
|
||||
logger.warning("register failed: username taken", username=body.username, client_ip=ip)
|
||||
raise HTTPException(409, "Пользователь с таким именем уже существует")
|
||||
|
||||
uuid = generate_uuid()
|
||||
@@ -405,6 +407,7 @@ async def register(body: RegisterRequest, request: Request):
|
||||
)
|
||||
|
||||
user_id = cursor.lastrowid
|
||||
logger.info("register ok", username=body.username, user_id=user_id, client_ip=ip)
|
||||
|
||||
# Создаем сессию
|
||||
session_token = secrets.token_urlsafe(32)
|
||||
@@ -456,6 +459,7 @@ async def login(body: LoginRequest, request: Request):
|
||||
|
||||
allowed, wait = check_rate_limit(ip)
|
||||
if not allowed:
|
||||
logger.warning("login rate limited", username=body.username, client_ip=ip)
|
||||
raise HTTPException(429, f"Слишком много попыток. Подождите {wait} секунд")
|
||||
|
||||
with get_db() as conn:
|
||||
@@ -465,15 +469,20 @@ async def login(body: LoginRequest, request: Request):
|
||||
).fetchone()
|
||||
|
||||
if not user or not verify_password(body.password, user["password_hash"]):
|
||||
logger.warning("login failed: bad credentials", username=body.username, client_ip=ip)
|
||||
record_login_attempt(ip, False)
|
||||
raise HTTPException(401, "Неверное имя пользователя или пароль")
|
||||
|
||||
if not user["is_active"]:
|
||||
logger.warning("login failed: account deactivated", username=body.username, client_ip=ip)
|
||||
raise HTTPException(403, "Аккаунт деактивирован")
|
||||
|
||||
if user["banned_until"] and user["banned_until"] > time.time():
|
||||
logger.warning("login failed: account banned", username=body.username, client_ip=ip)
|
||||
raise HTTPException(403, "Аккаунт забанен")
|
||||
|
||||
logger.info("login ok", username=user["username"], user_id=user["id"], client_ip=ip)
|
||||
|
||||
record_login_attempt(ip, True)
|
||||
|
||||
now = time.time()
|
||||
|
||||
Reference in New Issue
Block a user