oath2.0
All checks were successful
Deploy on push / deploy (push) Successful in 2m57s

This commit is contained in:
2025-09-29 16:33:49 +03:00
parent 504152981b
commit 9b284852e9

View File

@@ -624,20 +624,54 @@ async def oauth_login_http(request: Request) -> JSONResponse | RedirectResponse:
code_challenge = create_s256_code_challenge(code_verifier)
state = token_urlsafe(32)
# 🔍 Сохраняем redirect_uri из Referer header для testing.discours.io
# Приоритет: query параметр → path параметр → Referer header → FRONTEND_URL
final_redirect_uri = (
request.query_params.get("redirect_uri")
or request.path_params.get("redirect_uri")
or request.headers.get("referer")
or FRONTEND_URL
)
logger.info(f"🎯 Final redirect URI: '{final_redirect_uri}' (from referer: {request.headers.get('referer')})")
# 🎯 Получаем redirect_uri из query параметра (фронтенд должен передавать явно)
explicit_redirect_uri = request.query_params.get("redirect_uri")
if explicit_redirect_uri:
# Декодируем если URL-encoded
from urllib.parse import unquote
if "%3A" in explicit_redirect_uri or "%2F" in explicit_redirect_uri:
explicit_redirect_uri = unquote(explicit_redirect_uri)
# Если это /oauth, меняем на /settings
if "/oauth" in explicit_redirect_uri:
from urllib.parse import urlparse, urlunparse
parsed = urlparse(explicit_redirect_uri)
explicit_redirect_uri = urlunparse(
(parsed.scheme, parsed.netloc, "/settings", parsed.params, "", parsed.fragment)
)
logger.info(f"🔧 Changed /oauth redirect to /settings: {explicit_redirect_uri}")
final_redirect_uri = explicit_redirect_uri
else:
# Fallback на настройки профиля
final_redirect_uri = FRONTEND_URL.rstrip("/") + "/settings"
logger.info(f"🎯 Final redirect URI: '{final_redirect_uri}'")
# 🔑 Создаем state с redirect URL и случайным значением для безопасности
import base64
import json
state_data = {
"redirect_uri": final_redirect_uri,
"random": token_urlsafe(16), # Для CSRF protection
"timestamp": int(time.time()),
}
# Кодируем state в base64 для передачи в URL
state_json = json.dumps(state_data)
state = base64.urlsafe_b64encode(state_json.encode()).decode().rstrip("=")
logger.info(f"🔑 Created state with redirect_uri: {final_redirect_uri}")
oauth_data = {
"code_verifier": code_verifier,
"provider": provider,
"redirect_uri": final_redirect_uri,
"state_data": state_data, # Сохраняем для callback
"created_at": int(time.time()),
}
await store_oauth_state(state, oauth_data)
@@ -918,10 +952,14 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon
else f"🔧 Session token: {session_token}"
)
# Получаем redirect_uri из OAuth данных
redirect_uri = oauth_data.get("redirect_uri", FRONTEND_URL)
# 🔑 Получаем redirect_uri из state данных (новый подход)
state_data = oauth_data.get("state_data", {})
redirect_uri = state_data.get("redirect_uri") or oauth_data.get("redirect_uri", FRONTEND_URL)
if not isinstance(redirect_uri, str) or not redirect_uri:
redirect_uri = FRONTEND_URL
redirect_uri = FRONTEND_URL.rstrip("/") + "/settings"
logger.info(f"🔑 Using redirect_uri from state: {redirect_uri}")
# 🎯 Стандартный OAuth flow: токен в URL для фронтенда
from urllib.parse import parse_qs, unquote, urlencode, urlparse, urlunparse
@@ -999,11 +1037,11 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon
if not isinstance(fallback_redirect, str):
fallback_redirect = FRONTEND_URL
# Для testing.discours.io используем главную страницу (так как /oauth редиректит на /)
# Для testing.discours.io используем страницу профиля для ошибок
if "testing.discours.io" in fallback_redirect:
from urllib.parse import quote
error_url = f"https://testing.discours.io/?error=auth_failed&provider={provider}&redirect_url={quote(fallback_redirect)}"
error_url = f"https://testing.discours.io/settings?error=auth_failed&provider={provider}&redirect_url={quote(fallback_redirect)}"
else:
error_url = f"{fallback_redirect}?error=auth_failed&provider={provider}"