Merge pull request #542 from Fr1ngg/bedolaga/fix-bot-token-authorization-issue

Ensure bootstrap web API token works without migration
This commit is contained in:
Egor
2025-09-28 06:24:31 +03:00
committed by GitHub

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
from datetime import datetime
from secrets import compare_digest
from typing import Optional, Tuple
from sqlalchemy.ext.asyncio import AsyncSession
@@ -27,21 +28,82 @@ class WebApiTokenService:
*,
remote_ip: Optional[str] = None,
) -> Optional[WebApiToken]:
token_hash = self.hash_token(token_value)
normalized_value = token_value.strip()
token_hash = self.hash_token(normalized_value)
token = await crud.get_token_by_hash(db, token_hash)
token = await self._ensure_bootstrap_token_if_needed(
db,
token,
normalized_value,
token_hash,
)
if not token or not token.is_active:
return None
if token.expires_at and token.expires_at < datetime.utcnow():
now = datetime.utcnow()
if token.expires_at and token.expires_at < now:
return None
token.last_used_at = datetime.utcnow()
token.last_used_at = now
if remote_ip:
token.last_used_ip = remote_ip
await db.flush()
return token
async def _ensure_bootstrap_token_if_needed(
self,
db: AsyncSession,
token: Optional[WebApiToken],
provided_value: str,
token_hash: str,
) -> Optional[WebApiToken]:
"""Гарантирует работу бутстрап-токена из настроек даже без миграции."""
if token and token.is_active:
return token
default_token = (settings.WEB_API_DEFAULT_TOKEN or "").strip()
if not default_token:
return token
if not compare_digest(default_token, provided_value):
return token
token_name = (settings.WEB_API_DEFAULT_TOKEN_NAME or "Bootstrap Token").strip() or "Bootstrap Token"
now = datetime.utcnow()
if token:
updated = False
if not token.is_active:
token.is_active = True
updated = True
if token.name != token_name:
token.name = token_name
updated = True
if updated:
token.updated_at = now
await db.flush()
return token
token = await crud.create_token(
db,
name=token_name,
token_hash=token_hash,
token_prefix=default_token[:12],
description="Автоматически создан при авторизации бутстрап-токеном",
created_by="bootstrap",
)
token.created_at = token.created_at or now
token.updated_at = now
return token
async def create_token(
self,
db: AsyncSession,