75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
import json
|
|
import logging
|
|
from urllib.parse import parse_qsl
|
|
|
|
from fastapi import Depends, Header, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.config import settings
|
|
from app.core.database import get_db
|
|
from app.core.security import validate_init_data
|
|
from app.models.user import User
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _log_auth_failure(reason: str, init_data: str | None) -> None:
|
|
parsed = dict(parse_qsl(init_data or "", keep_blank_values=True))
|
|
logger.warning(
|
|
"telegram auth failed: reason=%s init_len=%s has_hash=%s has_user=%s auth_date=%s bot_token_set=%s",
|
|
reason,
|
|
len(init_data or ""),
|
|
bool(parsed.get("hash")),
|
|
bool(parsed.get("user")),
|
|
parsed.get("auth_date", ""),
|
|
bool(settings.bot_token),
|
|
)
|
|
|
|
|
|
async def get_current_user(
|
|
x_telegram_init_data: str | None = Header(None, alias="X-Telegram-Init-Data"),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> User:
|
|
if not x_telegram_init_data:
|
|
_log_auth_failure("missing_header", x_telegram_init_data)
|
|
raise HTTPException(status_code=401, detail="Open this page from the Telegram bot Mini App")
|
|
|
|
data = validate_init_data(x_telegram_init_data)
|
|
if data is None:
|
|
_log_auth_failure("invalid_init_data", x_telegram_init_data)
|
|
raise HTTPException(status_code=401, detail="Invalid Telegram auth data")
|
|
|
|
user_json = data.get("user", "{}")
|
|
try:
|
|
user_data = json.loads(user_json)
|
|
except (json.JSONDecodeError, TypeError):
|
|
_log_auth_failure("invalid_user_json", x_telegram_init_data)
|
|
raise HTTPException(status_code=401, detail="Invalid user data")
|
|
|
|
user_id = user_data.get("id")
|
|
if not user_id:
|
|
_log_auth_failure("missing_user_id", x_telegram_init_data)
|
|
raise HTTPException(status_code=401, detail="Missing user id")
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
user = result.scalar_one_or_none()
|
|
|
|
if user is None:
|
|
user = User(
|
|
id=user_id,
|
|
username=user_data.get("username"),
|
|
first_name=user_data.get("first_name", ""),
|
|
last_name=user_data.get("last_name"),
|
|
)
|
|
db.add(user)
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
else:
|
|
user.username = user_data.get("username")
|
|
user.first_name = user_data.get("first_name") or user.first_name
|
|
user.last_name = user_data.get("last_name")
|
|
await db.commit()
|
|
|
|
return user
|