""" 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='Ошибка авторизации. Используйте официальный клиент.' )