chatgpt2api / services /codex_cpa_service.py
tx1538's picture
Upload 179 files
9d7ddb9 verified
Raw
History Blame
3.07 kB
from __future__ import annotations
import base64
import json
import re
from datetime import datetime, timedelta, timezone
from typing import Any
CPA_TZ = timezone(timedelta(hours=8))
ACCOUNT_ID_CLAIMS = (
"https://api.openai.com/auth.account_id",
"chatgpt_account_id",
"project_id",
)
INVALID_FILENAME_CHARS = re.compile(r'[\\/:*?"<>|]+')
def decode_jwt_payload(token: str) -> dict[str, Any]:
try:
payload = str(token or "").split(".")[1]
payload += "=" * (-len(payload) % 4)
data = json.loads(base64.urlsafe_b64decode(payload.encode("ascii")))
return data if isinstance(data, dict) else {}
except Exception:
return {}
def format_cpa_time(timestamp: int | float | str | None = None) -> str:
if timestamp is None:
dt = datetime.now(CPA_TZ)
else:
dt = datetime.fromtimestamp(float(timestamp), timezone.utc)
return dt.strftime("%Y-%m-%dT%H:%M:%S.000+08:00")
def _first_text(*values: object) -> str:
for value in values:
text = str(value or "").strip()
if text:
return text
return ""
def _email_from_payloads(tokens: dict, access_payload: dict, id_payload: dict) -> str:
profile = access_payload.get("https://api.openai.com/profile")
profile_email = profile.get("email") if isinstance(profile, dict) else ""
return _first_text(tokens.get("email"), id_payload.get("email"), access_payload.get("email"), profile_email)
def _account_id_from_payloads(access_payload: dict, id_payload: dict) -> str:
for claim in ACCOUNT_ID_CLAIMS:
value = _first_text(id_payload.get(claim), access_payload.get(claim))
if value:
return value
auth = access_payload.get("https://api.openai.com/auth")
if isinstance(auth, dict):
return _first_text(auth.get("user_id"), auth.get("account_id"))
return ""
def build_codex_auth_payload(tokens: dict) -> dict:
access_token = str(tokens.get("access_token") or "").strip()
refresh_token = str(tokens.get("refresh_token") or "").strip()
id_token = str(tokens.get("id_token") or "").strip()
access_payload = decode_jwt_payload(access_token)
id_payload = decode_jwt_payload(id_token)
exp = access_payload.get("exp")
return {
"type": "codex",
"email": _email_from_payloads(tokens, access_payload, id_payload),
"expired": format_cpa_time(exp),
"id_token": id_token,
"account_id": _account_id_from_payloads(access_payload, id_payload),
"disabled": False,
"access_token": access_token,
"last_refresh": format_cpa_time(),
"refresh_token": refresh_token,
}
def _safe_filename(email: str) -> str:
name = INVALID_FILENAME_CHARS.sub("_", str(email or "").strip())
return f"{name or 'codex-auth'}.json"
def build_codex_upload_file(tokens: dict) -> tuple[str, bytes]:
payload = build_codex_auth_payload(tokens)
body = json.dumps(payload, ensure_ascii=False, indent=2).encode("utf-8")
return _safe_filename(payload.get("email") or ""), body