nakama/moderation/backend-py/middleware/telegram_auth.py

126 lines
4.8 KiB
Python
Raw Normal View History

2025-12-15 00:04:03 +00:00
"""
Telegram Mini App authentication middleware
"""
from typing import Optional
from fastapi import Request, HTTPException, status
from database import users_collection
from utils.telegram_initdata import validate_init_data, normalize_telegram_user
from config import settings
async def authenticate_telegram_moderation(request: Request) -> Optional[dict]:
"""
Authenticate user via Telegram Mini App initData
Returns:
User dict if authenticated, None otherwise
Raises:
HTTPException: If authentication fails
"""
# Get initData from headers
auth_header = request.headers.get('authorization', '')
init_data_raw = None
if auth_header.startswith('tma '):
init_data_raw = auth_header[4:].strip()
if not init_data_raw:
init_data_raw = request.headers.get('x-telegram-init-data')
if init_data_raw:
init_data_raw = init_data_raw.strip()
if not init_data_raw:
print('[TelegramAuth] No initData found in headers')
return None
try:
# Validate initData
payload = validate_init_data(init_data_raw, settings.MODERATION_BOT_TOKEN)
telegram_user = payload.get('user')
if not telegram_user:
print('[TelegramAuth] No user data in initData')
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Отсутствуют данные пользователя в initData'
)
# Normalize user data
normalized_user = normalize_telegram_user(telegram_user)
telegram_id = normalized_user.get('id')
if not telegram_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Неверный ID пользователя'
)
print(f'[TelegramAuth] Validated initData for telegramId={telegram_id}')
# Find or create user
from bson import ObjectId
user = await users_collection().find_one({'telegramId': telegram_id})
if not user:
# Create new user
from datetime import datetime
user_doc = {
'telegramId': telegram_id,
'username': normalized_user.get('username') or normalized_user.get('firstName') or 'user',
'firstName': normalized_user.get('firstName'),
'lastName': normalized_user.get('lastName'),
'photoUrl': normalized_user.get('photoUrl'),
'role': 'user',
'createdAt': datetime.utcnow()
}
result = await users_collection().insert_one(user_doc)
user = await users_collection().find_one({'_id': result.inserted_id})
print(f'[TelegramAuth] Created new user: {telegram_id}')
else:
# Update user data if needed
update_fields = {}
if normalized_user.get('username') and not user.get('username'):
update_fields['username'] = normalized_user.get('username')
if normalized_user.get('firstName') and not user.get('firstName'):
update_fields['firstName'] = normalized_user.get('firstName')
if normalized_user.get('lastName') is not None:
update_fields['lastName'] = normalized_user.get('lastName')
if normalized_user.get('photoUrl') and not user.get('photoUrl'):
update_fields['photoUrl'] = normalized_user.get('photoUrl')
if update_fields:
from datetime import datetime
update_fields['lastActiveAt'] = datetime.utcnow()
await users_collection().update_one(
{'_id': user['_id']},
{'$set': update_fields}
)
user.update(update_fields)
if user.get('banned'):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Пользователь заблокирован'
)
return user
except HTTPException:
raise
except ValueError as e:
print(f'[TelegramAuth] Validation error: {e}')
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f'{str(e)}. Используйте официальный клиент.'
)
except Exception as e:
print(f'[TelegramAuth] Error: {type(e).__name__}: {e}')
import traceback
traceback.print_exc()
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Ошибка авторизации. Используйте официальный клиент.'
)