121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
import requests
|
||
import json
|
||
import random
|
||
from dataclasses import dataclass
|
||
from typing import Any
|
||
|
||
def generate_device_id():
|
||
return f"{random_hex(8)}-{random_hex(4)}-{random_hex(4)}-{random_hex(4)}-{random_hex(12)}"
|
||
|
||
def random_hex(length):
|
||
return ''.join(random.choices('0123456789abcdef', k=length))
|
||
|
||
@dataclass(frozen=True)
|
||
class CheckoutResult:
|
||
ok: bool
|
||
checkout_url: str | None = None
|
||
error: str | None = None
|
||
raw: Any | None = None
|
||
|
||
def create_eu_billing_with_browser_sim(access_token: str, *, timeout: int = 30) -> CheckoutResult:
|
||
"""模拟浏览器请求生成欧洲账单,返回 CheckoutResult。"""
|
||
|
||
device_id = generate_device_id()
|
||
|
||
headers = {
|
||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0',
|
||
'Accept': '*/*',
|
||
'Accept-Language': 'en-US,en;q=0.5',
|
||
'Accept-Encoding': 'gzip, deflate, br',
|
||
'Referer': 'https://chatgpt.com/',
|
||
'OAI-Language': 'en-US',
|
||
'OAI-Device-Id': device_id,
|
||
'OAI-Client-Version': 'prod-04eaaa443c69cfc8b46b5d52d2b61dbceba21862',
|
||
'OAI-Client-Build-Number': '4053703',
|
||
'Authorization': f'Bearer {access_token}',
|
||
'Content-Type': 'application/json',
|
||
'Origin': 'https://chatgpt.com',
|
||
'Connection': 'keep-alive',
|
||
'Sec-Fetch-Dest': 'empty',
|
||
'Sec-Fetch-Mode': 'cors',
|
||
'Sec-Fetch-Site': 'same-origin',
|
||
'Priority': 'u=4',
|
||
'TE': 'trailers'
|
||
}
|
||
|
||
payload = {
|
||
"plan_name": "chatgptteamplan",
|
||
"team_plan_data": {
|
||
"workspace_name": "Sepa",
|
||
"price_interval": "month",
|
||
"seat_quantity": 5
|
||
},
|
||
"billing_details": {
|
||
"country": "DE",
|
||
"currency": "EUR"
|
||
},
|
||
"promo_campaign": {
|
||
"promo_campaign_id": "team-1-month-free",
|
||
"is_coupon_from_query_param": False
|
||
},
|
||
"checkout_ui_mode": "redirect"
|
||
}
|
||
|
||
url = "https://chatgpt.com/backend-api/payments/checkout"
|
||
|
||
try:
|
||
response = requests.post(
|
||
url,
|
||
headers=headers,
|
||
json=payload,
|
||
timeout=timeout,
|
||
allow_redirects=False
|
||
)
|
||
|
||
try:
|
||
result = response.json()
|
||
except json.JSONDecodeError:
|
||
return CheckoutResult(
|
||
ok=False,
|
||
error=f"响应不是 JSON(HTTP {response.status_code})",
|
||
raw=response.text,
|
||
)
|
||
|
||
checkout_url = result.get('url')
|
||
checkout_session_id = result.get('checkout_session_id')
|
||
processor_entity = result.get('processor_entity')
|
||
|
||
# 如果 url 为空,手动构造
|
||
if not checkout_url and checkout_session_id:
|
||
entity = processor_entity if processor_entity else "openai_llc"
|
||
checkout_url = f"https://chatgpt.com/checkout/{entity}/{checkout_session_id}"
|
||
|
||
if checkout_url:
|
||
return CheckoutResult(ok=True, checkout_url=checkout_url, raw=result)
|
||
|
||
detail = result.get('detail', result)
|
||
return CheckoutResult(ok=False, error=str(detail), raw=result)
|
||
|
||
except requests.RequestException as e:
|
||
return CheckoutResult(ok=False, error=str(e))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
print("=" * 70)
|
||
print("欧洲账单生成器")
|
||
print("=" * 70)
|
||
|
||
access_token = input("\n输入 Access Token: ").strip()
|
||
|
||
if not access_token:
|
||
print("[!] Access Token 不能为空!")
|
||
exit(1)
|
||
|
||
print("\n[*] 正在生成...\n")
|
||
result = create_eu_billing_with_browser_sim(access_token)
|
||
if result.ok and result.checkout_url:
|
||
print(f"\n[✓] Checkout URL:")
|
||
print(f" {result.checkout_url}\n")
|
||
else:
|
||
print(f"\n[!] 失败: {result.error}\n")
|