From 7072882b0b7c88c724d0affcbb8c5c76a7fe9decafbabecb14dab14bffbc1353 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Wed, 10 Dec 2025 16:18:32 +0300 Subject: [PATCH] =?UTF-8?q?10=2012=2025=20=D0=92=D1=80=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=20=D0=B2=D1=81=D1=91=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB.=20=D0=90=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D1=84=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=D1=86=D0=B8=D1=8E.=20(=D0=BE=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BB=D0=BE=D1=81=D1=8C=20=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D0=B5=D1=81=D1=81=D0=B8=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=81=D0=B5=D1=81=D1=81=D0=B8=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/shine.geo/ClientInfoService.java | 60 ++++++++++++++++--- .../auth/Net_CreateAuthSession__Handler.java | 24 +++++--- .../auth/Net_RefreshSession_Handler.java | 17 +++++- 3 files changed, 82 insertions(+), 19 deletions(-) diff --git a/shine-server-geo/src/main/java/shine.geo/ClientInfoService.java b/shine-server-geo/src/main/java/shine.geo/ClientInfoService.java index dd1d217..26fb7f5 100644 --- a/shine-server-geo/src/main/java/shine.geo/ClientInfoService.java +++ b/shine-server-geo/src/main/java/shine.geo/ClientInfoService.java @@ -14,6 +14,10 @@ public final class ClientInfoService { private ClientInfoService() { } + /** + * Собирает строку с информацией о клиенте: + * User-Agent, client-hints и удалённый IP. + */ public static String buildClientInfoString(Session wsSession) { if (wsSession == null) { return CLIENT_INFO_UNKNOWN; @@ -29,14 +33,8 @@ public final class ClientInfoService { String secChPlatform = getFirstHeader(req, "Sec-CH-UA-Platform"); String secChMobile = getFirstHeader(req, "Sec-CH-UA-Mobile"); - // --- Исправленный блок определения IP --- - String remoteIp = ""; - SocketAddress rawAddr = wsSession.getRemoteAddress(); - if (rawAddr instanceof InetSocketAddress inet) { - if (inet.getAddress() != null) { - remoteIp = inet.getAddress().getHostAddress(); - } - } + // IP берём через общий метод, чтобы не дублировать логику + String remoteIp = extractClientIp(wsSession); StringBuilder sb = new StringBuilder(); @@ -55,7 +53,7 @@ public final class ClientInfoService { appendSep(sb); sb.append("mobile=").append(secChMobile); } - if (!remoteIp.isEmpty()) { + if (remoteIp != null && !remoteIp.isEmpty()) { appendSep(sb); sb.append("remote=").append(remoteIp); } @@ -64,6 +62,49 @@ public final class ClientInfoService { return result.isEmpty() ? CLIENT_INFO_UNKNOWN : result; } + /** + * Пытается вытащить реальный IP клиента из WebSocket-сессии. + * + * Приоритет: + * 1) X-Forwarded-For (если стоим за прокси / балансировщиком) + * 2) X-Real-IP + * 3) remoteAddress из WebSocket-сессии + */ + public static String extractClientIp(Session wsSession) { + if (wsSession == null) { + return null; + } + + UpgradeRequest req = wsSession.getUpgradeRequest(); + + // 1) X-Forwarded-For: может быть список IP через запятую + if (req != null) { + String xff = getFirstHeader(req, "X-Forwarded-For"); + if (xff != null && !xff.isBlank()) { + String first = xff.split(",")[0].trim(); + if (!first.isBlank()) { + return first; + } + } + + // 2) X-Real-IP + String xRealIp = getFirstHeader(req, "X-Real-IP"); + if (xRealIp != null && !xRealIp.isBlank()) { + return xRealIp.trim(); + } + } + + // 3) fallback: remoteAddress из WebSocket-сессии + SocketAddress rawAddr = wsSession.getRemoteAddress(); + if (rawAddr instanceof InetSocketAddress inet) { + if (inet.getAddress() != null) { + return inet.getAddress().getHostAddress(); + } + } + + return null; + } + public static String extractPreferredLanguageTag(Session wsSession) { if (wsSession == null) { return LANGUAGE_UNKNOWN; @@ -102,5 +143,6 @@ public final class ClientInfoService { if (sb.length() > 0) { sb.append("; "); } + // если строка пустая — разделитель не нужен } } \ No newline at end of file diff --git a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_CreateAuthSession__Handler.java b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_CreateAuthSession__Handler.java index a7d90b0..9e4d389 100644 --- a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_CreateAuthSession__Handler.java +++ b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_CreateAuthSession__Handler.java @@ -15,12 +15,11 @@ import shine.db.dao.ActiveSessionsDAO; import shine.db.entities.ActiveSession; import shine.db.entities.SolanaUser; import shine.geo.ClientInfoService; +import shine.geo.GeoLookupService; import utils.crypto.Ed25519Util; import org.eclipse.jetty.websocket.api.Session; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.security.SecureRandom; @@ -178,17 +177,26 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler { String clientInfoFromRequest = ClientInfoService.buildClientInfoString(wsSession); String userLanguage = ClientInfoService.extractPreferredLanguageTag(wsSession); - String clientIp = ""; + String clientIp = null; if (wsSession != null) { - SocketAddress rawAddr = wsSession.getRemoteAddress(); - if (rawAddr instanceof InetSocketAddress inet) { - if (inet.getAddress() != null) { - clientIp = inet.getAddress().getHostAddress(); + // стандартный метод получения IP + clientIp = ClientInfoService.extractClientIp(wsSession); + + // Дёргаем запрос геолокации (ничего не сохраняем в сессию), + // нужно лишь для того, чтобы данные попали в кэш сервера. + if (clientIp != null && !clientIp.isBlank()) { + try { + GeoLookupService.resolveCountryCityOrIpWithCache(clientIp); + } catch (Exception e) { + // геолокация не критична, можно тихо залогировать на debug + log.debug("Geo lookup failed for ip={}", clientIp, e); } } } -// TODO и сдесь тоже переписываем получение ИП адреса на стандартный метод и тоже дёргаем запрос геолокации который никуда не сохраняем просто что бы он в кэш сервера попал + if (clientIp == null) { + clientIp = ""; + } // --- создаём запись ActiveSession и сохраняем в БД --- ActiveSessionsDAO dao = ActiveSessionsDAO.getInstance(); diff --git a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_RefreshSession_Handler.java b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_RefreshSession_Handler.java index ad5cd49..e5644ab 100644 --- a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_RefreshSession_Handler.java +++ b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_RefreshSession_Handler.java @@ -16,6 +16,7 @@ import shine.db.dao.SolanaUsersDAO; import shine.db.entities.ActiveSession; import shine.db.entities.SolanaUser; import shine.geo.ClientInfoService; +import shine.geo.GeoLookupService; import java.sql.SQLException; @@ -125,8 +126,20 @@ public class Net_RefreshSession_Handler implements JsonMessageHandler { String userLanguage = null; if (ctx != null && ctx.getWsSession() != null) { - clientIp = "8.8.8.8"; //TODO сделать нормальное получение ип адреса -// и сделать запрос геолокации и никуда его не сохранять запрос нужен просто что бы в кэш данные добавилиь если нужно + // Нормальное получение IP-адреса клиента + clientIp = ClientInfoService.extractClientIp(ctx.getWsSession()); + + // Сделать запрос геолокации и никуда её не сохранять: + // вызов с кэшированием в БД, нужно только для прогрева кэша. + if (clientIp != null && !clientIp.isBlank()) { + try { + GeoLookupService.resolveCountryCityOrIpWithCache(clientIp); + } catch (Exception e) { + // Геолокация не критична, просто логируем на debug/trace при желании + log.debug("Geo lookup failed for ip={}", clientIp, e); + } + } + clientInfoFromRequest = ClientInfoService.buildClientInfoString(ctx.getWsSession()); userLanguage = ClientInfoService.extractPreferredLanguageTag(ctx.getWsSession()); }