@@ -1741,8 +1741,10 @@ def _complete_chatgpt_bridge_stage(self, result: RegistrationResult, *, final_ur
17411741 "warning" if is_chatgpt_stage else "info" ,
17421742 )
17431743 if is_chatgpt_stage :
1744- self ._log (f"{ log_prefix } 先主动重发一次 OTP,确保当前 bridge 阶段拿到新验证码..." , "warning" )
1745- self ._send_verification_code (referer = "https://auth.openai.com/email-verification" )
1744+ self ._log (
1745+ f"{ log_prefix } 优先等待当前阶段系统自动发送的 OTP,避免过早重发导致旧验证码混入..." ,
1746+ "warning" ,
1747+ )
17461748 self ._prepare_expected_login_otp (grace_seconds = OTP_CREATED_AT_GRACE_SECONDS )
17471749 elif "auth.openai.com/log-in/password" in current_url :
17481750 self ._log (f"{ log_prefix } 已直达密码页,先提交密码再继续..." )
@@ -2641,12 +2643,6 @@ def _complete_token_exchange_native_backup(self, result: RegistrationResult) ->
26412643 原生入口对齐备份版收尾链路:
26422644 登录验证码 -> Workspace -> redirect -> OAuth callback -> token 入袋。
26432645 """
2644- def _is_registration_gate_url (url : str ) -> bool :
2645- u = str (url or "" ).strip ().lower ()
2646- if not u :
2647- return False
2648- return ("auth.openai.com/about-you" in u ) or ("auth.openai.com/add-phone" in u )
2649-
26502646 if not self ._complete_login_otp_once (result , fetch_timeout = 120 ):
26512647 return False
26522648
@@ -2667,12 +2663,12 @@ def _is_registration_gate_url(url: str) -> bool:
26672663 result .workspace_id = workspace_id
26682664
26692665 continue_url = ""
2670- if otp_continue and _is_registration_gate_url (otp_continue ):
2666+ if otp_continue and self . _is_registration_gate_url (otp_continue ):
26712667 self ._log ("OTP 返回 continue_url 指向注册门页(about-you/add-phone),本轮收尾忽略该地址" )
26722668 otp_continue = ""
26732669
26742670 cached_continue = str (self ._create_account_continue_url or "" ).strip ()
2675- if cached_continue and _is_registration_gate_url (cached_continue ):
2671+ if cached_continue and self . _is_registration_gate_url (cached_continue ):
26762672 self ._log ("create_account 缓存 continue_url 指向注册门页(about-you/add-phone),本轮收尾忽略该地址" )
26772673 cached_continue = ""
26782674
@@ -3669,6 +3665,35 @@ def _verify_email_otp_with_retry(
36693665 attempted_codes .add (code )
36703666
36713667 if self ._validate_verification_code (code ):
3668+ if chatgpt_stage :
3669+ continue_url = str (self ._last_validate_otp_continue_url or "" ).strip ()
3670+ lowered_continue = continue_url .lower ()
3671+
3672+ # ChatGPT 补会话阶段命中注册门页通常是旧会话链路,不应视为成功。
3673+ if self ._is_registration_gate_url (continue_url ):
3674+ if (not resend_after_invalid_triggered ) and attempt < max_attempts :
3675+ resend_after_invalid_triggered = True
3676+ self ._log (
3677+ f"{ stage_label } 命中注册门页 continue_url(about-you/add-phone),疑似旧会话验证码;主动重发一次 OTP..." ,
3678+ "warning" ,
3679+ )
3680+ self ._send_verification_code (referer = "https://auth.openai.com/email-verification" )
3681+ self ._prepare_expected_login_otp (grace_seconds = OTP_CREATED_AT_GRACE_SECONDS )
3682+
3683+ if attempt < max_attempts :
3684+ self ._log (
3685+ f"{ stage_label } 校验成功但 continue_url 仍指向注册门页,继续等待当前登录阶段新验证码..." ,
3686+ "warning" ,
3687+ )
3688+ time .sleep (2 )
3689+ continue
3690+ return False
3691+
3692+ # 回调明确 access_denied 时直接结束当前阶段,避免无意义循环。
3693+ if ("chatgpt.com/api/auth/callback/openai" in lowered_continue ) and ("error=access_denied" in lowered_continue ):
3694+ self ._log (f"{ stage_label } 回调返回 access_denied,终止当前验证码阶段重试" , "warning" )
3695+ return False
3696+
36723697 return True
36733698
36743699 if chatgpt_stage :
@@ -3909,16 +3934,19 @@ def _resolve_workspace_selection_referer(self, referer_url: Optional[str] = None
39093934 or "https://auth.openai.com/sign-in-with-chatgpt/codex/consent"
39103935 ).strip ()
39113936
3937+ @staticmethod
3938+ def _is_registration_gate_url (url : str ) -> bool :
3939+ lowered = str (url or "" ).strip ().lower ()
3940+ if not lowered :
3941+ return False
3942+ return ("auth.openai.com/about-you" in lowered ) or ("auth.openai.com/add-phone" in lowered )
3943+
39123944 def _fetch_workspace_selection_context (
39133945 self ,
39143946 referer_url : Optional [str ] = None ,
39153947 * ,
39163948 force_probe : bool = False ,
39173949 ) -> Tuple [str , str , Dict [str , Any ]]:
3918- def _is_registration_gate_url (url : str ) -> bool :
3919- lowered = str (url or "" ).strip ().lower ()
3920- return bool (lowered ) and ("about-you" in lowered or "add-phone" in lowered )
3921-
39223950 raw_referer = str (
39233951 referer_url
39243952 or self ._last_validate_otp_continue_url
@@ -3927,7 +3955,7 @@ def _is_registration_gate_url(url: str) -> bool:
39273955 ).strip ()
39283956 consent_page_url = raw_referer or self ._resolve_workspace_selection_referer (referer_url )
39293957 has_explicit_consent_url = _looks_like_codex_consent_url (raw_referer )
3930- should_probe_default_consent = _is_registration_gate_url (consent_page_url ) or (
3958+ should_probe_default_consent = self . _is_registration_gate_url (consent_page_url ) or (
39313959 force_probe and not has_explicit_consent_url
39323960 )
39333961 if (not consent_page_url ) or should_probe_default_consent :
@@ -3945,7 +3973,7 @@ def _is_registration_gate_url(url: str) -> bool:
39453973 timeout = 20 ,
39463974 )
39473975 response_url = str (getattr (response , "url" , request_url ) or request_url ).strip ()
3948- if response_url and ("localhost:1455" not in response_url .lower ()) and (not _is_registration_gate_url (response_url )):
3976+ if response_url and ("localhost:1455" not in response_url .lower ()) and (not self . _is_registration_gate_url (response_url )):
39493977 consent_page_url = response_url
39503978 consent_text = str (getattr (response , "text" , "" ) or "" )
39513979 except Exception as exc :
0 commit comments