feat: auto-fetch codex login otp from mailbox
This commit is contained in:
@@ -198,12 +198,14 @@ class CodexOAuthHTTPFlow:
|
|||||||
otp: str = "",
|
otp: str = "",
|
||||||
workspace_id: str = "",
|
workspace_id: str = "",
|
||||||
use_browser: bool = False,
|
use_browser: bool = False,
|
||||||
|
mailbox: dict | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.authorize_url = authorize_url
|
self.authorize_url = authorize_url
|
||||||
self.email = email
|
self.email = email
|
||||||
self.password = password
|
self.password = password
|
||||||
self.otp = otp
|
self.otp = otp
|
||||||
self.workspace_id = workspace_id
|
self.workspace_id = workspace_id
|
||||||
|
self.mailbox = mailbox
|
||||||
self.auth_base = "https://auth.openai.com"
|
self.auth_base = "https://auth.openai.com"
|
||||||
self.proxy = load_proxy()
|
self.proxy = load_proxy()
|
||||||
self.http = HTTPClient(self.proxy)
|
self.http = HTTPClient(self.proxy)
|
||||||
@@ -304,13 +306,36 @@ class CodexOAuthHTTPFlow:
|
|||||||
print(f"[otp] sending email code via {send_url}")
|
print(f"[otp] sending email code via {send_url}")
|
||||||
return self._api_json("GET", send_url, referer=referer)
|
return self._api_json("GET", send_url, referer=referer)
|
||||||
|
|
||||||
|
def _fetch_otp_from_mailbox(self) -> str:
|
||||||
|
"""Try to fetch OTP from mailbox automatically."""
|
||||||
|
if not self.mailbox:
|
||||||
|
return ""
|
||||||
|
from vmail_client import MailClient
|
||||||
|
mail = MailClient()
|
||||||
|
print("[otp] auto-fetching OTP from mailbox...")
|
||||||
|
try:
|
||||||
|
code = mail.wait_for_otp(self.mailbox, timeout=120, poll=3.0)
|
||||||
|
print(f" OTP: {code}")
|
||||||
|
return code
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[otp] auto-fetch failed: {e}")
|
||||||
|
return ""
|
||||||
|
|
||||||
def _validate_email_otp(self, referer: str) -> dict[str, Any]:
|
def _validate_email_otp(self, referer: str) -> dict[str, Any]:
|
||||||
validate_url = f"{self.auth_base}/api/accounts/email-otp/validate"
|
validate_url = f"{self.auth_base}/api/accounts/email-otp/validate"
|
||||||
resend_url = f"{self.auth_base}/api/accounts/email-otp/resend"
|
resend_url = f"{self.auth_base}/api/accounts/email-otp/resend"
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
code = (self.otp or input("Email OTP (or type 'resend'): ").strip()).strip()
|
if self.otp:
|
||||||
self.otp = ""
|
code = self.otp.strip()
|
||||||
|
self.otp = ""
|
||||||
|
elif self.mailbox:
|
||||||
|
code = self._fetch_otp_from_mailbox()
|
||||||
|
if not code:
|
||||||
|
raise FlowError("Failed to auto-fetch OTP from mailbox")
|
||||||
|
else:
|
||||||
|
code = input("Email OTP (or type 'resend'): ").strip()
|
||||||
|
|
||||||
if not code:
|
if not code:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
22
src/main.py
22
src/main.py
@@ -103,6 +103,26 @@ def cmd_codex_login(args):
|
|||||||
|
|
||||||
authorize_url = args.authorize_url or DEFAULT_AUTHORIZE_URL
|
authorize_url = args.authorize_url or DEFAULT_AUTHORIZE_URL
|
||||||
|
|
||||||
|
# Try to get mailbox token for auto OTP fetching
|
||||||
|
mailbox = None
|
||||||
|
if args.mailbox_password:
|
||||||
|
import httpx
|
||||||
|
try:
|
||||||
|
token_resp = httpx.post(
|
||||||
|
"https://api.mail.tm/token",
|
||||||
|
json={"address": email, "password": args.mailbox_password},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
if token_resp.status_code == 200:
|
||||||
|
mailbox = {
|
||||||
|
"address": email,
|
||||||
|
"password": args.mailbox_password,
|
||||||
|
"token": token_resp.json()["token"],
|
||||||
|
}
|
||||||
|
print(f"Mailbox token obtained, will auto-fetch OTP if needed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: Failed to get mailbox token: {e}")
|
||||||
|
|
||||||
print(f"Starting Codex OAuth flow for {email}")
|
print(f"Starting Codex OAuth flow for {email}")
|
||||||
flow = CodexOAuthHTTPFlow(
|
flow = CodexOAuthHTTPFlow(
|
||||||
authorize_url=authorize_url,
|
authorize_url=authorize_url,
|
||||||
@@ -110,6 +130,7 @@ def cmd_codex_login(args):
|
|||||||
password=password,
|
password=password,
|
||||||
otp=args.otp or "",
|
otp=args.otp or "",
|
||||||
workspace_id=args.workspace_id or "",
|
workspace_id=args.workspace_id or "",
|
||||||
|
mailbox=mailbox,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
callback_url = flow.run()
|
callback_url = flow.run()
|
||||||
@@ -153,6 +174,7 @@ Examples:
|
|||||||
p_codex.add_argument("--otp", default="", help="Email OTP code (if already known)")
|
p_codex.add_argument("--otp", default="", help="Email OTP code (if already known)")
|
||||||
p_codex.add_argument("--workspace-id", dest="workspace_id", default="", help="Workspace ID to select")
|
p_codex.add_argument("--workspace-id", dest="workspace_id", default="", help="Workspace ID to select")
|
||||||
p_codex.add_argument("--authorize-url", dest="authorize_url", default="", help="Custom authorize URL")
|
p_codex.add_argument("--authorize-url", dest="authorize_url", default="", help="Custom authorize URL")
|
||||||
|
p_codex.add_argument("--mailbox-password", dest="mailbox_password", default="", help="Mailbox password for auto OTP fetching")
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user