fix env auth

This commit is contained in:
qananasikq
2026-04-23 12:42:41 +03:00
parent ac2753146e
commit d2dd17a02c
3 changed files with 49 additions and 5 deletions

View File

@@ -2,6 +2,7 @@
OPENLANE_HEADLESS=true OPENLANE_HEADLESS=true
OPENLANE_LOG_LEVEL=INFO OPENLANE_LOG_LEVEL=INFO
OPENLANE_TIMEOUT_MS=45000 OPENLANE_TIMEOUT_MS=45000
OPENLANE_RUNTIME_CONFIG_FILE=runtime_config.json
# --- OpenLane Auth & API --- # --- OpenLane Auth & API ---
OPENLANE_USERNAME= OPENLANE_USERNAME=

View File

@@ -181,7 +181,7 @@ class Settings:
log_level: str = _env_str("OPENLANE_LOG_LEVEL", "INFO") log_level: str = _env_str("OPENLANE_LOG_LEVEL", "INFO")
log_file: str | None = _env_optional_str("OPENLANE_LOG_FILE") log_file: str | None = _env_optional_str("OPENLANE_LOG_FILE")
enable_trace_id_logs: bool = _env_bool("OPENLANE_ENABLE_TRACE_ID_LOGS", True) enable_trace_id_logs: bool = _env_bool("OPENLANE_ENABLE_TRACE_ID_LOGS", True)
runtime_config_file: str | None = _env_path_str("OPENLANE_RUNTIME_CONFIG_FILE") runtime_config_file: str | None = _env_path_str("OPENLANE_RUNTIME_CONFIG_FILE") or "runtime_config.json"
fingerprint: FingerprintConfig = field(default_factory=FingerprintConfig) fingerprint: FingerprintConfig = field(default_factory=FingerprintConfig)
openlane: OpenLaneConfig = field(default_factory=OpenLaneConfig) openlane: OpenLaneConfig = field(default_factory=OpenLaneConfig)
database: DatabaseConfig = field(default_factory=DatabaseConfig) database: DatabaseConfig = field(default_factory=DatabaseConfig)

View File

@@ -321,7 +321,9 @@ class OpenLaneAuthenticator:
"https://app.openlane.com/api/_next/time", "https://app.openlane.com/api/_next/time",
wait_until="domcontentloaded", wait_until="domcontentloaded",
) )
if self._is_api_authenticated(page):
return page return page
logger.warning("Access token cookie exists but API returned unauthorized, will re-authenticate")
# Пробуем прямой refresh access_token без навигации. # Пробуем прямой refresh access_token без навигации.
refresh_token = self._extract_refresh_token_from_cookies(context) or self.config.refresh_token refresh_token = self._extract_refresh_token_from_cookies(context) or self.config.refresh_token
@@ -337,8 +339,10 @@ class OpenLaneAuthenticator:
"https://app.openlane.com/api/_next/time", "https://app.openlane.com/api/_next/time",
wait_until="domcontentloaded", wait_until="domcontentloaded",
) )
if self._is_api_authenticated(page):
logger.info("OpenLane session restored via direct Okta refresh") logger.info("OpenLane session restored via direct Okta refresh")
return page return page
logger.warning("Direct Okta refresh produced token but API still unauthorized")
logger.warning("Direct refresh failed, trying sign_in fallback") logger.warning("Direct refresh failed, trying sign_in fallback")
# Если refresh_token был только в env, добавляем cookie вручную. # Если refresh_token был только в env, добавляем cookie вручную.
@@ -355,7 +359,9 @@ class OpenLaneAuthenticator:
self._wait_for_authenticated_session(page) self._wait_for_authenticated_session(page)
self._persist_storage_state(context) self._persist_storage_state(context)
self._maybe_rotate_token(context) self._maybe_rotate_token(context)
if self._is_api_authenticated(page):
return page return page
logger.warning("sign_in fallback completed but API is still unauthorized")
except OpenLaneAuthError: except OpenLaneAuthError:
logger.warning("SPA refresh_token exchange failed") logger.warning("SPA refresh_token exchange failed")
page.close() page.close()
@@ -370,6 +376,43 @@ class OpenLaneAuthenticator:
" 2. Set OPENLANE_USERNAME and OPENLANE_PASSWORD in .env" " 2. Set OPENLANE_USERNAME and OPENLANE_PASSWORD in .env"
) )
def _is_api_authenticated(self, page: Page) -> bool:
"""Проверяет, что сессия реально авторизована для OpenLane API.
Нужна для случаев, когда access_token cookie есть (и даже не истёк),
но сервер уже считает сессию невалидной.
"""
try:
status = page.evaluate(
"""async () => {
try {
const resp = await fetch('https://app.openlane.com/api/v4/search?page=1&per_page=1&source_tab=marketplace&sale_types=marketplace', {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, application/vnd.backlotcars.v3'
}
});
return resp.status;
} catch (e) {
return 0;
}
}"""
)
except Exception:
logger.warning("Failed to validate OpenLane API auth state", exc_info=True)
return False
try:
code = int(status)
except (TypeError, ValueError):
return False
# 401/403 — точно неавторизованы.
if code in (401, 403, 0):
return False
return True
def login(self, context: BrowserContext) -> Page: def login(self, context: BrowserContext) -> Page:
self.validate_credentials() self.validate_credentials()
page = context.new_page() page = context.new_page()