diff --git a/.env.example b/.env.example index 90145fa..e4a38e8 100644 --- a/.env.example +++ b/.env.example @@ -27,4 +27,5 @@ telegram_bot_enabled = "1" telegram_whitelist_ids = "1,2,3" origins="http://127.0.0.1,https://web.openmax.su" sms_gateway_url = "http://127.0.0.1:8100/sms-gateway" -firebase_credentials_path = "" \ No newline at end of file +firebase_credentials_path = "" +geo_db_path = "" \ No newline at end of file diff --git a/.gitignore b/.gitignore index fe86ff6..72eb6b3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ __pycache__ *.pem *.sqlite *.crt -*-adminsdk-*.json \ No newline at end of file +*-adminsdk-*.json +*.mmdb \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 42e211a..0df3a06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,12 @@ -aiogram -aiomysql -msgpack -lz4 -websockets -pydantic -aiosqlite -aiohttp -python-dotenv -cryptography -firebase-admin \ No newline at end of file +aiogram==3.26.0 +aiomysql==0.3.2 +msgpack==1.1.2 +lz4==4.4.5 +websockets==16.0 +pydantic==2.12.5 +aiosqlite==0.22.1 +aiohttp==3.13.5 +python-dotenv==1.2.2 +cryptography==46.0.6 +firebase-admin==7.4.0 +geoip2==5.2.0 \ No newline at end of file diff --git a/src/common/config.py b/src/common/config.py index 7b340d5..2c5d9f2 100644 --- a/src/common/config.py +++ b/src/common/config.py @@ -54,3 +54,6 @@ class ServerConfig: ### Firebase firebase_credentials_path = os.getenv("firebase_credentials_path", "") + + ### Путь к гео бд + geo_db_path = os.getenv("geo_db_path", "") \ No newline at end of file diff --git a/src/common/tools.py b/src/common/tools.py index 3024427..75a535a 100644 --- a/src/common/tools.py +++ b/src/common/tools.py @@ -1,5 +1,8 @@ import json import time +import os + +import geoip2.database class Tools: @@ -546,3 +549,15 @@ class Tools: presence[int(contact_id)] = {"seen": int(lastseen)} return presence + + def get_geo(self, ip, db_path): + """ + Получение страны пользователя по его айпи адресу + Используется во время запуска сессии + """ + try: + with geoip2.database.Reader(db_path) as reader: + response = reader.country(ip) + return response.country.name or "Localhost Federation" + except Exception: + return "Localhost Federation" \ No newline at end of file diff --git a/src/oneme/processors/auth.py b/src/oneme/processors/auth.py index fdce2ca..ac019d7 100644 --- a/src/oneme/processors/auth.py +++ b/src/oneme/processors/auth.py @@ -197,7 +197,7 @@ class AuthProcessors(BaseProcessor): await self._send(writer, packet) self.logger.debug(f"Код для {phone}: {code} (существующий={user_exists})") - async def auth(self, payload, seq, writer, deviceType, deviceName, appVersion): + async def auth(self, payload, seq, writer, deviceType, deviceName, appVersion, ip): """Обработчик проверки кода""" try: VerifyCodePayloadModel.model_validate(payload) @@ -285,8 +285,10 @@ class AuthProcessors(BaseProcessor): hashed_login, deviceType, deviceName, - "Little Saint James Island", - int(time.time()), + self.tools.get_geo( + ip=ip, db_path=self.config.geo_db_path + ), + int(time.time() * 1000), ), # весь покрытый зеленью, абсолютно весь, остров невезения в океане есть ) @@ -333,7 +335,7 @@ class AuthProcessors(BaseProcessor): # Отправляем await self._send(writer, packet) - async def auth_confirm(self, payload, seq, writer, deviceType, deviceName, appVersion): + async def auth_confirm(self, payload, seq, writer, deviceType, deviceName, appVersion, ip): """Обработчик подтверждения регистрации нового пользователя""" # Валидируем данные пакета try: @@ -456,8 +458,10 @@ class AuthProcessors(BaseProcessor): hashed_login, deviceType or "ANDROID", deviceName or "Unknown", - "Little Saint James Island", - now_s, + self.tools.get_geo( + ip=ip, db_path=self.config.geo_db_path + ), + now_ms, ), ) diff --git a/src/oneme/socket.py b/src/oneme/socket.py index ee9b7e9..d93f328 100644 --- a/src/oneme/socket.py +++ b/src/oneme/socket.py @@ -114,7 +114,7 @@ class OnemeMobile: ) else: await self.processors.auth( - payload, seq, writer, deviceType, deviceName, appVersion + payload, seq, writer, deviceType, deviceName, appVersion, address[0] ) case self.opcodes.AUTH_CONFIRM: if not self.auth_rate_limiter.is_allowed(address[0]): @@ -126,7 +126,7 @@ class OnemeMobile: ) elif payload and payload.get("tokenType") == "REGISTER": await self.processors.auth_confirm( - payload, seq, writer, deviceType, deviceName, appVersion + payload, seq, writer, deviceType, deviceName, appVersion, address[0] ) else: self.logger.warning( diff --git a/src/oneme/websocket.py b/src/oneme/websocket.py index 88a630a..693878c 100644 --- a/src/oneme/websocket.py +++ b/src/oneme/websocket.py @@ -88,7 +88,7 @@ class OnemeWS: ) else: await self.processors.auth( - payload, seq, websocket, deviceType, deviceName, appVersion + payload, seq, websocket, deviceType, deviceName, appVersion, address[0] ) case self.opcodes.AUTH_CONFIRM: if not self.auth_rate_limiter.is_allowed(address[0]): @@ -100,7 +100,7 @@ class OnemeWS: ) elif payload and payload.get("tokenType") == "REGISTER": await self.processors.auth_confirm( - payload, seq, websocket, deviceType, deviceName, appVersion + payload, seq, websocket, deviceType, deviceName, appVersion, address[0] ) else: self.logger.warning( diff --git a/src/tamtam/processors/auth.py b/src/tamtam/processors/auth.py index 4d48384..aabca77 100644 --- a/src/tamtam/processors/auth.py +++ b/src/tamtam/processors/auth.py @@ -158,7 +158,7 @@ class AuthProcessors(BaseProcessor): await self._send(writer, packet) - async def auth_confirm(self, payload, seq, writer, deviceType, deviceName): + async def auth_confirm(self, payload, seq, writer, deviceType, deviceName, ip): """Обработчик финальной аутентификации""" # Валидируем данные пакета try: @@ -212,8 +212,16 @@ class AuthProcessors(BaseProcessor): # Создаем сессию await cursor.execute( "INSERT INTO tokens (phone, token_hash, device_type, device_name, location, time) VALUES (%s, %s, %s, %s, %s, %s)", - (stored_token.get("phone"), hashed_login, deviceType, deviceName, - "Epstein Island", int(time.time())) + ( + stored_token.get("phone"), + hashed_login, + deviceType, + deviceName, + self.tools.get_geo( + ip=ip, db_path=self.config.geo_db_path + ), + int(time.time() * 1000) + ) ) # Аватарка с биографией diff --git a/src/tamtam/socket.py b/src/tamtam/socket.py index 603356f..9286dc0 100644 --- a/src/tamtam/socket.py +++ b/src/tamtam/socket.py @@ -96,7 +96,7 @@ class TamTamMobile: if not self.auth_rate_limiter.is_allowed(address[0]): await self.processors._send_error(seq, self.opcodes.AUTH_CONFIRM, self.processors.error_types.RATE_LIMITED, writer) else: - await self.processors.auth_confirm(payload, seq, writer, deviceType, deviceName) + await self.processors.auth_confirm(payload, seq, writer, deviceType, deviceName, address[0]) case self.opcodes.LOGIN: if not self.auth_rate_limiter.is_allowed(address[0]): await self.processors._send_error(seq, self.opcodes.LOGIN, self.processors.error_types.RATE_LIMITED, writer) diff --git a/src/tamtam/websocket.py b/src/tamtam/websocket.py index 57d2f30..774ec5d 100644 --- a/src/tamtam/websocket.py +++ b/src/tamtam/websocket.py @@ -82,7 +82,7 @@ class TamTamWS: if not self.auth_rate_limiter.is_allowed(address[0]): await self.processors._send_error(seq, self.opcodes.AUTH_CONFIRM, self.processors.error_types.RATE_LIMITED, websocket) else: - await self.processors.auth_confirm(payload, seq, websocket, deviceType, deviceName) + await self.processors.auth_confirm(payload, seq, websocket, deviceType, deviceName, address[0]) case self.opcodes.LOGIN: if not self.auth_rate_limiter.is_allowed(address[0]): await self.processors._send_error(seq, self.opcodes.LOGIN, self.processors.error_types.RATE_LIMITED, websocket)