修复bug
This commit is contained in:
@@ -6,5 +6,29 @@
|
|||||||
"oai_did": "fcc455da-9239-4683-bb2a-43ef01d8eb0a",
|
"oai_did": "fcc455da-9239-4683-bb2a-43ef01d8eb0a",
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"timestamp": "2026-01-29 17:04:08"
|
"timestamp": "2026-01-29 17:04:08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": "user_f09ab8e154890e0b@gnd.qzz.io",
|
||||||
|
"password": "eHt4uOnxI6nW",
|
||||||
|
"access_token": "",
|
||||||
|
"oai_did": "758c617c-8324-4470-bd4f-0515813f6d95",
|
||||||
|
"status": "success",
|
||||||
|
"timestamp": "2026-01-29 19:08:22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": "user_f604f293e147919e@gnd.qzz.io",
|
||||||
|
"password": "P8dM44ts2q7j",
|
||||||
|
"access_token": "",
|
||||||
|
"oai_did": "3fd9815d-3720-4a42-aea5-9de7363767ec",
|
||||||
|
"status": "success",
|
||||||
|
"timestamp": "2026-01-29 19:10:23"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": "user_2b2d083ea1f5d4e4@gnd.qzz.io",
|
||||||
|
"password": "BBE88LdQPGMW",
|
||||||
|
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE5MzQ0ZTY1LWJiYzktNDRkMS1hOWQwLWY5NTdiMDc5YmQwZSIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MSJdLCJjbGllbnRfaWQiOiJhcHBfWDh6WTZ2VzJwUTl0UjNkRTduSzFqTDVnSCIsImV4cCI6MTc3MDU0OTI0OSwiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS9hdXRoIjp7ImNoYXRncHRfYWNjb3VudF9pZCI6ImQxMDU2ZjMzLWE4NTAtNGYyNi05MDU4LWJlM2RiYTUzNmVjMSIsImNoYXRncHRfYWNjb3VudF91c2VyX2lkIjoidXNlci16dE1zeUIwWmx1TUxiMHR1UUNEbzA2RTRfX2QxMDU2ZjMzLWE4NTAtNGYyNi05MDU4LWJlM2RiYTUzNmVjMSIsImNoYXRncHRfY29tcHV0ZV9yZXNpZGVuY3kiOiJub19jb25zdHJhaW50IiwiY2hhdGdwdF9wbGFuX3R5cGUiOiJmcmVlIiwiY2hhdGdwdF91c2VyX2lkIjoidXNlci16dE1zeUIwWmx1TUxiMHR1UUNEbzA2RTQiLCJ1c2VyX2lkIjoidXNlci16dE1zeUIwWmx1TUxiMHR1UUNEbzA2RTQifSwiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS9wcm9maWxlIjp7ImVtYWlsIjoidXNlcl8yYjJkMDgzZWExZjVkNGU0QGduZC5xenouaW8iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZX0sImlhdCI6MTc2OTY4NTI0OSwiaXNzIjoiaHR0cHM6Ly9hdXRoLm9wZW5haS5jb20iLCJqdGkiOiIwYTE4YTViMy04NjQxLTQ5ZmYtYmYwMi1lZjc4Y2YxMmNhZWUiLCJuYmYiOjE3Njk2ODUyNDksInB3ZF9hdXRoX3RpbWUiOjE3Njk2ODUyNDc0NTcsInNjcCI6WyJvcGVuaWQiLCJlbWFpbCIsInByb2ZpbGUiLCJvZmZsaW5lX2FjY2VzcyIsIm1vZGVsLnJlcXVlc3QiLCJtb2RlbC5yZWFkIiwib3JnYW5pemF0aW9uLnJlYWQiLCJvcmdhbml6YXRpb24ud3JpdGUiXSwic2Vzc2lvbl9pZCI6ImF1dGhzZXNzX0JyMjZQbW5vY3lGNzlobzBJZ0JFazcxZSIsInN1YiI6ImF1dGgwfGFZZk53eTJyaGdDNm9ZeUFqcVhLand5aSJ9.4vLBUWmKbZZDEKiXnXnDQcEhwsg3X3j7h92LZaH5IFJA1YScXODmJ4YCYvGT5akxKUZVeA6PLS0EJS77augPk3cNP1DdR0lQC2ZQec-aCXTe3_zYZBZMLqzvHgOpwdNjFVD187sZopbtcS1thgITEqT6-10xcEv9zEE4mT6PVBYhVl9usOf2DP7ibmdYG5Wgqw7xy-G5v0ySeMd7eWgtjJr_3n0Egdegr6uGrKROuOIDd_KUIW6VkCU5PaNUXCl3EhYaulJ5ynG498y6IaCgMQLbSEqOef2QEwIud1L6rt1B5l0oUUdOHSV-TESUBc6Ajp5-W5ADaYMJGFIOUvgaG7P24gXTDJ-egldz69yudd51sakvrly8PRPbEATklAYqJVk66X42uOUiWxtQGjroPkLv2Wk8tFRrHb7BZ8583I6rLzrAAtseD_nJc7wqMmJBQ9o8j22VBxObiHeoNUYMk4YD3wikZWxQW0VfEJjAcV0UFBJ7AR9px-tGi8WRGwmgZa-BFAKz_q-921kj3B5L8oNA-eYahggvGVONyb3Ad1mz1JTqj5B8aOjQtC2aga_7GKvI1dRzI_bT1WC3D8HRv-EXTo1-I7252KIbf_JF6hi6CsUoWstcnc3GWVyAT_q3_IAI_2xwGsV6A7R-zFWL9EgY0QICl1uSaz6dgYVs7oo",
|
||||||
|
"oai_did": "5ab55e47-ddb4-46b0-91f7-30eec383700a",
|
||||||
|
"status": "success",
|
||||||
|
"timestamp": "2026-01-29 19:14:18"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
135
core/flow.py
135
core/flow.py
@@ -6,7 +6,7 @@ import random
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from core.session import OAISession, CloudflareBlockError, SessionInvalidError, RateLimitError
|
from core.session import OAISession, CloudflareBlockError, SessionInvalidError
|
||||||
from core.sentinel_handler import SentinelHandler
|
from core.sentinel_handler import SentinelHandler
|
||||||
from core.challenge import CloudflareSolver
|
from core.challenge import CloudflareSolver
|
||||||
from utils.mail_box import MailHandler
|
from utils.mail_box import MailHandler
|
||||||
@@ -27,8 +27,7 @@ class RegisterFlow:
|
|||||||
AUTH_SEND_OTP = "https://auth.openai.com/api/accounts/email-otp/send"
|
AUTH_SEND_OTP = "https://auth.openai.com/api/accounts/email-otp/send"
|
||||||
AUTH_VALIDATE_OTP = "https://auth.openai.com/api/accounts/email-otp/validate"
|
AUTH_VALIDATE_OTP = "https://auth.openai.com/api/accounts/email-otp/validate"
|
||||||
AUTH_COMPLETE_PROFILE = "https://auth.openai.com/api/accounts/create_account"
|
AUTH_COMPLETE_PROFILE = "https://auth.openai.com/api/accounts/create_account"
|
||||||
|
AUTH_CONSENT = "https://auth.openai.com/api/accounts/consent"
|
||||||
# 获取 Token 相关
|
|
||||||
CHATGPT_SESSION = "https://chatgpt.com/api/auth/session"
|
CHATGPT_SESSION = "https://chatgpt.com/api/auth/session"
|
||||||
|
|
||||||
def __init__(self, session: OAISession, config, email: Optional[str] = None, password: Optional[str] = None):
|
def __init__(self, session: OAISession, config, email: Optional[str] = None, password: Optional[str] = None):
|
||||||
@@ -44,7 +43,7 @@ class RegisterFlow:
|
|||||||
self.csrf_token: Optional[str] = None
|
self.csrf_token: Optional[str] = None
|
||||||
self.sentinel_token: Optional[Dict[str, Any]] = None
|
self.sentinel_token: Optional[Dict[str, Any]] = None
|
||||||
self.otp: Optional[str] = None
|
self.otp: Optional[str] = None
|
||||||
self.access_token: Optional[str] = None
|
self.oauth_callback_url: Optional[str] = None
|
||||||
|
|
||||||
logger.info(f"RegisterFlow initialized for {self.email} (oai-did: {self.s.oai_did})")
|
logger.info(f"RegisterFlow initialized for {self.email} (oai-did: {self.s.oai_did})")
|
||||||
|
|
||||||
@@ -72,14 +71,12 @@ class RegisterFlow:
|
|||||||
await self._step6_send_email_otp()
|
await self._step6_send_email_otp()
|
||||||
await self._step7_submit_otp()
|
await self._step7_submit_otp()
|
||||||
await self._step8_complete_profile()
|
await self._step8_complete_profile()
|
||||||
await self._step9_get_access_token()
|
|
||||||
|
|
||||||
logger.success(f"[{self.email}] Registration completed successfully! ✅")
|
logger.success(f"[{self.email}] Registration completed successfully! ✅")
|
||||||
return {
|
return {
|
||||||
"email": self.email,
|
"email": self.email,
|
||||||
"password": self.password,
|
"password": self.password,
|
||||||
"oai_did": self.s.oai_did,
|
"oai_did": self.s.oai_did,
|
||||||
"access_token": self.access_token,
|
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"message": "Account registered successfully"
|
"message": "Account registered successfully"
|
||||||
}
|
}
|
||||||
@@ -92,10 +89,6 @@ class RegisterFlow:
|
|||||||
logger.error(f"[{self.email}] Session invalid: {e}")
|
logger.error(f"[{self.email}] Session invalid: {e}")
|
||||||
return {"email": self.email, "password": self.password, "status": "session_invalid", "error": str(e)}
|
return {"email": self.email, "password": self.password, "status": "session_invalid", "error": str(e)}
|
||||||
|
|
||||||
except RateLimitError as e:
|
|
||||||
logger.error(f"[{self.email}] Rate limited: {e}")
|
|
||||||
return {"email": self.email, "password": self.password, "status": "rate_limited", "error": str(e)}
|
|
||||||
|
|
||||||
except NotImplementedError as e:
|
except NotImplementedError as e:
|
||||||
logger.warning(f"[{self.email}] Feature not implemented: {e}")
|
logger.warning(f"[{self.email}] Feature not implemented: {e}")
|
||||||
return {"email": self.email, "password": self.password, "status": "pending_manual", "error": str(e)}
|
return {"email": self.email, "password": self.password, "status": "pending_manual", "error": str(e)}
|
||||||
@@ -245,53 +238,101 @@ class RegisterFlow:
|
|||||||
resp = self.s.post(
|
resp = self.s.post(
|
||||||
self.AUTH_COMPLETE_PROFILE,
|
self.AUTH_COMPLETE_PROFILE,
|
||||||
json={"name": name, "birthdate": birthdate},
|
json={"name": name, "birthdate": birthdate},
|
||||||
headers={"Content-Type": "application/json", "Referer": self.AUTH_CREATE_ACCOUNT},
|
headers={"Content-Type": "application/json", "Referer": self.AUTH_CREATE_ACCOUNT}
|
||||||
allow_redirects=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if resp.status_code not in [200, 302, 303]:
|
if resp.status_code != 200:
|
||||||
raise RuntimeError(f"Profile completion failed: {resp.status_code}")
|
raise RuntimeError(f"Profile completion failed: {resp.status_code}")
|
||||||
|
|
||||||
# 检查是否有 continue_url 需要跟随
|
# 获取 OAuth 回调 URL
|
||||||
try:
|
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
continue_url = data.get("continue_url")
|
self.oauth_callback_url = data.get("continue_url")
|
||||||
if continue_url:
|
logger.debug(f"[{self.email}] OAuth callback URL: {self.oauth_callback_url}")
|
||||||
logger.info(f"[{self.email}] Following OAuth callback...")
|
|
||||||
if not continue_url.startswith("http"):
|
|
||||||
continue_url = f"https://auth.openai.com{continue_url}"
|
|
||||||
|
|
||||||
# 跟随 OAuth 回调,最终会重定向到 chatgpt.com
|
|
||||||
callback_headers = {
|
|
||||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
||||||
"Referer": "https://auth.openai.com/",
|
|
||||||
"Sec-Fetch-Dest": "document",
|
|
||||||
"Sec-Fetch-Mode": "navigate",
|
|
||||||
"Sec-Fetch-Site": "same-origin",
|
|
||||||
"Upgrade-Insecure-Requests": "1",
|
|
||||||
}
|
|
||||||
self.s.get(continue_url, headers=callback_headers, allow_redirects=True)
|
|
||||||
logger.info(f"[{self.email}] ✓ OAuth callback completed")
|
|
||||||
except Exception as e:
|
|
||||||
logger.debug(f"[{self.email}] No continue_url or parse error: {e}")
|
|
||||||
|
|
||||||
logger.info(f"[{self.email}] ✓ Profile completed")
|
logger.info(f"[{self.email}] ✓ Profile completed")
|
||||||
|
|
||||||
async def _step9_get_access_token(self):
|
async def _step9_complete_oauth_callback(self):
|
||||||
"""Step 9: 通过登录流程获取 Access Token"""
|
"""Step 9: 完成 OAuth 回调,获取 session-token"""
|
||||||
logger.info(f"[{self.email}] Step 9: Getting access token via login")
|
logger.info(f"[{self.email}] Step 9: Completing OAuth callback")
|
||||||
|
|
||||||
from core.login_flow import LoginFlow
|
# 使用 step 8 返回的 continue_url,跟随重定向链到 chatgpt.com
|
||||||
|
if self.oauth_callback_url:
|
||||||
# 使用当前 session 执行登录流程
|
# continue_url 可能是相对路径或完整 URL
|
||||||
login_flow = LoginFlow(self.s, self.email, self.password)
|
if self.oauth_callback_url.startswith("http"):
|
||||||
result = await login_flow.run()
|
callback_url = self.oauth_callback_url
|
||||||
|
|
||||||
if result.get("status") == "success":
|
|
||||||
self.access_token = result.get("access_token")
|
|
||||||
logger.info(f"[{self.email}] ✓ Access token obtained: {self.access_token[:50]}...")
|
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[{self.email}] Failed to get access token: {result.get('error')}")
|
callback_url = f"https://auth.openai.com{self.oauth_callback_url}"
|
||||||
|
else:
|
||||||
|
# 如果没有 continue_url,尝试访问 consent 端点
|
||||||
|
callback_url = self.AUTH_CONSENT
|
||||||
|
|
||||||
|
logger.debug(f"[{self.email}] Following OAuth callback: {callback_url}")
|
||||||
|
|
||||||
|
# 循环跟随重定向,直到到达 chatgpt.com 或获取到 session-token
|
||||||
|
max_redirects = 10
|
||||||
|
for i in range(max_redirects):
|
||||||
|
resp = self.s.get(callback_url, allow_redirects=True)
|
||||||
|
|
||||||
|
# 检查是否已到达 chatgpt.com
|
||||||
|
if 'chatgpt.com' in str(resp.url):
|
||||||
|
logger.debug(f"[{self.email}] Reached chatgpt.com")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 检查响应是否包含重定向 URL(JSON 格式)
|
||||||
|
try:
|
||||||
|
data = resp.json()
|
||||||
|
redirect_url = data.get("redirect_url") or data.get("location") or data.get("url")
|
||||||
|
if redirect_url:
|
||||||
|
logger.debug(f"[{self.email}] Following JSON redirect ({i+1}): {redirect_url[:100]}...")
|
||||||
|
callback_url = redirect_url
|
||||||
|
continue
|
||||||
|
except (json.JSONDecodeError, ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 没有更多重定向,退出循环
|
||||||
|
break
|
||||||
|
|
||||||
|
# 检查是否获取到 session-token cookie
|
||||||
|
session_token = self.s.get_cookie('__Secure-next-auth.session-token')
|
||||||
|
|
||||||
|
if not session_token:
|
||||||
|
# 尝试直接访问 chatgpt.com 首页触发 cookie 设置
|
||||||
|
logger.debug(f"[{self.email}] Session token not found, trying chatgpt.com homepage")
|
||||||
|
self.s.get(self.CHATGPT_HOME, allow_redirects=True)
|
||||||
|
session_token = self.s.get_cookie('__Secure-next-auth.session-token')
|
||||||
|
|
||||||
|
if not session_token:
|
||||||
|
# 打印所有 cookies 用于调试,但不抛出错误
|
||||||
|
# 尝试继续获取 access token,有时候 session token 不是必需的
|
||||||
|
all_cookies = self.s.get_cookies()
|
||||||
|
logger.warning(f"[{self.email}] Session token not found, available cookies: {list(all_cookies.keys())}")
|
||||||
|
logger.info(f"[{self.email}] Continuing without session-token, will try to get access token directly")
|
||||||
|
else:
|
||||||
|
logger.info(f"[{self.email}] ✓ OAuth callback completed, session-token obtained")
|
||||||
|
|
||||||
|
async def _step10_get_access_token(self) -> str:
|
||||||
|
"""Step 10: 获取 AccessToken"""
|
||||||
|
logger.info(f"[{self.email}] Step 10: Getting access token")
|
||||||
|
|
||||||
|
resp = self.s.get(
|
||||||
|
self.CHATGPT_SESSION,
|
||||||
|
headers={
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Referer': 'https://chatgpt.com/',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if resp.status_code != 200:
|
||||||
|
raise RuntimeError(f"Failed to get access token: {resp.status_code}")
|
||||||
|
|
||||||
|
data = resp.json()
|
||||||
|
access_token = data.get('accessToken')
|
||||||
|
|
||||||
|
if not access_token:
|
||||||
|
raise RuntimeError("AccessToken not found in response")
|
||||||
|
|
||||||
|
logger.info(f"[{self.email}] ✓ AccessToken obtained successfully")
|
||||||
|
return access_token
|
||||||
|
|
||||||
def _generate_email(self) -> str:
|
def _generate_email(self) -> str:
|
||||||
"""生成随机邮箱"""
|
"""生成随机邮箱"""
|
||||||
|
|||||||
@@ -257,7 +257,20 @@ class OAISession:
|
|||||||
返回:
|
返回:
|
||||||
Cookie 字典 {name: value}
|
Cookie 字典 {name: value}
|
||||||
"""
|
"""
|
||||||
return {cookie.name: cookie.value for cookie in self.client.cookies}
|
# curl_cffi 的 cookies 可能存在同名不同域的 cookie,需要遍历 jar
|
||||||
|
result = {}
|
||||||
|
try:
|
||||||
|
for cookie in self.client.cookies.jar:
|
||||||
|
# 用 domain:name 作为 key 避免冲突,或者直接覆盖
|
||||||
|
result[cookie.name] = cookie.value
|
||||||
|
except Exception:
|
||||||
|
# 兼容处理
|
||||||
|
try:
|
||||||
|
for cookie in self.client.cookies:
|
||||||
|
result[cookie.name] = cookie.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return result
|
||||||
|
|
||||||
def get_cookie(self, name: str) -> Optional[str]:
|
def get_cookie(self, name: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
154
login.py
Normal file
154
login.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
OpenAI 账号登录获取 Token
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
python login.py
|
||||||
|
python login.py email@example.com password123
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from core.session import OAISession
|
||||||
|
from core.login_flow import LoginFlow
|
||||||
|
from config import load_config
|
||||||
|
from utils.logger import logger, setup_logger
|
||||||
|
|
||||||
|
|
||||||
|
async def login_and_get_token(email: str, password: str, proxy: str = None) -> dict:
|
||||||
|
"""
|
||||||
|
登录并获取 access_token
|
||||||
|
|
||||||
|
参数:
|
||||||
|
email: 登录邮箱
|
||||||
|
password: 登录密码
|
||||||
|
proxy: 代理地址(可选)
|
||||||
|
|
||||||
|
返回:
|
||||||
|
登录结果字典
|
||||||
|
"""
|
||||||
|
session = None
|
||||||
|
try:
|
||||||
|
# 创建会话
|
||||||
|
session = OAISession(proxy=proxy, impersonate="chrome124")
|
||||||
|
|
||||||
|
# 执行登录流程
|
||||||
|
flow = LoginFlow(session, email, password)
|
||||||
|
result = await flow.run()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if session:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def save_token(result: dict):
|
||||||
|
"""保存 token 到文件"""
|
||||||
|
if result.get("status") != "success":
|
||||||
|
return
|
||||||
|
|
||||||
|
email = result.get("email", "unknown")
|
||||||
|
access_token = result.get("access_token", "")
|
||||||
|
session_token = result.get("session_token", "")
|
||||||
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
# 保存到 accounts.json
|
||||||
|
json_file = Path("accounts.json")
|
||||||
|
accounts = []
|
||||||
|
if json_file.exists():
|
||||||
|
try:
|
||||||
|
with open(json_file, "r", encoding="utf-8") as f:
|
||||||
|
accounts = json.load(f)
|
||||||
|
except:
|
||||||
|
accounts = []
|
||||||
|
|
||||||
|
# 查找是否已存在该邮箱,更新 token
|
||||||
|
found = False
|
||||||
|
for acc in accounts:
|
||||||
|
if acc.get("email") == email:
|
||||||
|
acc["access_token"] = access_token
|
||||||
|
acc["session_token"] = session_token
|
||||||
|
acc["token_updated"] = timestamp
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
accounts.append({
|
||||||
|
"email": email,
|
||||||
|
"access_token": access_token,
|
||||||
|
"session_token": session_token,
|
||||||
|
"timestamp": timestamp
|
||||||
|
})
|
||||||
|
|
||||||
|
with open(json_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(accounts, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
logger.info(f"Token saved to accounts.json")
|
||||||
|
|
||||||
|
# 同时保存到单独文件
|
||||||
|
token_dir = Path("tokens")
|
||||||
|
token_dir.mkdir(exist_ok=True)
|
||||||
|
token_file = token_dir / f"{email.replace('@', '_at_')}.txt"
|
||||||
|
with open(token_file, "w", encoding="utf-8") as f:
|
||||||
|
f.write(f"Email: {email}\n")
|
||||||
|
f.write(f"Access Token: {access_token}\n")
|
||||||
|
f.write(f"Session Token: {session_token}\n")
|
||||||
|
f.write(f"Timestamp: {timestamp}\n")
|
||||||
|
|
||||||
|
logger.info(f"Token saved to {token_file}")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# 初始化日志
|
||||||
|
setup_logger()
|
||||||
|
|
||||||
|
# 加载配置
|
||||||
|
config = load_config()
|
||||||
|
|
||||||
|
# 获取邮箱和密码
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
email = sys.argv[1]
|
||||||
|
password = sys.argv[2]
|
||||||
|
else:
|
||||||
|
print("\n=== OpenAI 账号登录 ===\n")
|
||||||
|
email = input("Email: ").strip()
|
||||||
|
password = input("Password: ").strip()
|
||||||
|
|
||||||
|
if not email or not password:
|
||||||
|
logger.error("Email and password are required")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取代理
|
||||||
|
proxy = config.proxy.get_next_proxy()
|
||||||
|
if proxy:
|
||||||
|
logger.info(f"Using proxy: {proxy[:30]}...")
|
||||||
|
|
||||||
|
print()
|
||||||
|
logger.info(f"Starting login for {email}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 执行登录
|
||||||
|
result = await login_and_get_token(email, password, proxy)
|
||||||
|
|
||||||
|
print()
|
||||||
|
if result.get("status") == "success":
|
||||||
|
logger.success(f"✅ Login successful!")
|
||||||
|
print()
|
||||||
|
print(f"Access Token: {result['access_token'][:80]}...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 保存 token
|
||||||
|
save_token(result)
|
||||||
|
else:
|
||||||
|
logger.error(f"❌ Login failed: {result.get('error', 'Unknown error')}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
14
main.py
14
main.py
@@ -175,6 +175,20 @@ async def register_account(
|
|||||||
|
|
||||||
# 保存成功的账号
|
# 保存成功的账号
|
||||||
if result["status"] == "success":
|
if result["status"] == "success":
|
||||||
|
# 注册成功后,立即登录获取 token
|
||||||
|
logger.info(f"[Task {task_id}] Registration done, now logging in to get token...")
|
||||||
|
|
||||||
|
from core.login_flow import LoginFlow
|
||||||
|
login_flow = LoginFlow(session, result["email"], result["password"])
|
||||||
|
login_result = await login_flow.run()
|
||||||
|
|
||||||
|
if login_result.get("status") == "success":
|
||||||
|
result["access_token"] = login_result.get("access_token")
|
||||||
|
result["session_token"] = login_result.get("session_token")
|
||||||
|
logger.success(f"[Task {task_id}] ✅ Token obtained!")
|
||||||
|
else:
|
||||||
|
logger.warning(f"[Task {task_id}] ⚠️ Login failed: {login_result.get('error')}")
|
||||||
|
|
||||||
await save_account(result, config.accounts_output_file)
|
await save_account(result, config.accounts_output_file)
|
||||||
logger.success(
|
logger.success(
|
||||||
f"[Task {task_id}] ✅ Account created: {result['email']}:{result['password']}"
|
f"[Task {task_id}] ✅ Account created: {result['email']}:{result['password']}"
|
||||||
|
|||||||
Reference in New Issue
Block a user