| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- """Token refresh helpers for the zhuce6 ChatGPT platform."""
- from __future__ import annotations
- from dataclasses import dataclass
- from datetime import datetime, timedelta
- import logging
- from typing import Any
- from curl_cffi import requests as cffi_requests
- from .constants import (
- OAUTH_CLIENT_ID,
- OAUTH_REDIRECT_URI,
- OPENAI_IMPERSONATE,
- OPENAI_SEC_CH_UA,
- OPENAI_SEC_CH_UA_MOBILE,
- OPENAI_SEC_CH_UA_PLATFORM,
- OPENAI_USER_AGENT,
- )
- logger = logging.getLogger(__name__)
- @dataclass
- class TokenRefreshResult:
- success: bool
- access_token: str = ""
- refresh_token: str = ""
- account_id: str = ""
- email: str = ""
- session_token: str = ""
- expires_at: datetime | None = None
- error_message: str = ""
- class TokenRefreshManager:
- SESSION_URL = "https://chatgpt.com/api/auth/session"
- TOKEN_URL = "https://auth.openai.com/oauth/token"
- def __init__(self, proxy_url: str | None = None) -> None:
- self.proxy_url = proxy_url
- self._oauth_client_id = OAUTH_CLIENT_ID
- self._oauth_redirect_uri = OAUTH_REDIRECT_URI
- @property
- def _default_headers(self) -> dict[str, str]:
- return {
- "user-agent": OPENAI_USER_AGENT,
- "accept-language": "en-US,en;q=0.9",
- "sec-ch-ua": OPENAI_SEC_CH_UA,
- "sec-ch-ua-mobile": OPENAI_SEC_CH_UA_MOBILE,
- "sec-ch-ua-platform": OPENAI_SEC_CH_UA_PLATFORM,
- }
- def _create_session(self) -> cffi_requests.Session:
- return cffi_requests.Session(impersonate=OPENAI_IMPERSONATE, proxy=self.proxy_url)
- def refresh_by_session_token(self, session_token: str) -> TokenRefreshResult:
- result = TokenRefreshResult(success=False)
- try:
- session = self._create_session()
- session.cookies.set(
- "__Secure-next-auth.session-token",
- session_token,
- domain=".chatgpt.com",
- path="/",
- )
- response = session.get(
- self.SESSION_URL,
- headers={**self._default_headers, "accept": "application/json"},
- timeout=30,
- )
- if response.status_code != 200:
- result.error_message = f"Session token refresh failed: HTTP {response.status_code}"
- return result
- data = response.json()
- access_token = str(data.get("accessToken") or "").strip()
- if not access_token:
- result.error_message = "Session token refresh failed: missing accessToken"
- return result
- expires_at = None
- expires_str = str(data.get("expires") or "").strip()
- if expires_str:
- try:
- expires_at = datetime.fromisoformat(expires_str.replace("Z", "+00:00"))
- except ValueError:
- expires_at = None
- result.success = True
- result.access_token = access_token
- user = data.get("user") or {}
- result.account_id = str(data.get("account_id") or (user.get("id") if isinstance(user, dict) else "") or "").strip()
- result.email = str((user.get("email") if isinstance(user, dict) else "") or data.get("email") or "").strip()
- result.session_token = session_token
- result.expires_at = expires_at
- return result
- except Exception as exc:
- result.error_message = f"Session token refresh exception: {exc}"
- logger.error(result.error_message)
- return result
- def refresh_by_oauth_token(self, refresh_token: str, client_id: str | None = None) -> TokenRefreshResult:
- result = TokenRefreshResult(success=False)
- try:
- session = self._create_session()
- response = session.post(
- self.TOKEN_URL,
- headers={
- **self._default_headers,
- "content-type": "application/x-www-form-urlencoded",
- "accept": "application/json",
- },
- data={
- "client_id": client_id or self._oauth_client_id,
- "grant_type": "refresh_token",
- "refresh_token": refresh_token,
- "redirect_uri": self._oauth_redirect_uri,
- },
- timeout=30,
- )
- if response.status_code != 200:
- result.error_message = f"OAuth token refresh failed: HTTP {response.status_code}"
- return result
- data = response.json()
- access_token = str(data.get("access_token") or "").strip()
- if not access_token:
- result.error_message = "OAuth token refresh failed: missing access_token"
- return result
- result.success = True
- result.access_token = access_token
- result.refresh_token = str(data.get("refresh_token") or refresh_token).strip()
- result.expires_at = datetime.utcnow() + timedelta(seconds=int(data.get("expires_in", 3600)))
- return result
- except Exception as exc:
- result.error_message = f"OAuth token refresh exception: {exc}"
- logger.error(result.error_message)
- return result
- def refresh_account(self, account: Any) -> TokenRefreshResult:
- session_token = str(getattr(account, "session_token", "") or "").strip()
- if session_token:
- session_result = self.refresh_by_session_token(session_token)
- if session_result.success:
- return session_result
- refresh_token = str(getattr(account, "refresh_token", "") or "").strip()
- if refresh_token:
- return self.refresh_by_oauth_token(
- refresh_token=refresh_token,
- client_id=str(getattr(account, "client_id", "") or "").strip() or None,
- )
- return TokenRefreshResult(success=False, error_message="No session_token or refresh_token available")
|