This commit is contained in:
@@ -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}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user