Handle combined signup verification/profile page

This commit is contained in:
EmptyDust
2026-05-02 11:19:22 +08:00
parent 99313843c1
commit 2bfa277aa1
8 changed files with 479 additions and 7 deletions
+81 -5
View File
@@ -1145,6 +1145,12 @@ function isLikelyLoggedInChatgptHomeUrl(rawUrl = location.href) {
}
function getStep4PostVerificationState() {
// Newer auth flows can briefly render profile fields before the email-verification
// form fully exits. Do not advance to Step 5 while verification UI is still present.
if (isVerificationPageStillVisible()) {
return null;
}
if (isStep5Ready() || isSignupProfilePageUrl()) {
return {
state: 'step5',
@@ -2531,12 +2537,25 @@ async function waitForSplitVerificationInputsFilled(inputs, code, timeout = 2500
}
async function fillVerificationCode(step, payload) {
const { code } = payload;
const { code, signupProfile } = payload;
if (!code) throw new Error('未提供验证码。');
if (step === 4 && isStep5Ready()) {
log(`步骤 ${step}:检测到页面已进入下一阶段,本次验证码提交按成功处理。`, 'ok');
return { success: true, assumed: true, alreadyAdvanced: true };
if (step === 4) {
const postVerificationState = getStep4PostVerificationState();
if (postVerificationState?.state === 'logged_in_home') {
log(`步骤 ${step}:检测到页面已进入 ChatGPT 已登录态,本次验证码提交按成功处理。`, 'ok');
return {
success: true,
assumed: true,
alreadyAdvanced: true,
skipProfileStep: true,
url: postVerificationState.url || location.href,
};
}
if (postVerificationState?.state === 'step5') {
log(`步骤 ${step}:检测到页面已进入下一阶段,本次验证码提交按成功处理。`, 'ok');
return { success: true, assumed: true, alreadyAdvanced: true };
}
}
if (step === 8) {
if (isStep8Ready()) {
@@ -2554,6 +2573,17 @@ async function fillVerificationCode(step, payload) {
await waitForLoginVerificationPageReady();
}
const combinedSignupProfilePage = step === 4 && isCombinedSignupVerificationProfilePage();
if (combinedSignupProfilePage) {
if (!signupProfile || !signupProfile.firstName || !signupProfile.lastName) {
throw new Error('当前注册验证码页面要求同时填写资料,但未提供姓名或生日数据。');
}
await step5_fillNameBirthday({
...signupProfile,
prefillOnly: true,
});
}
// Find code input — could be a single input or multiple separate inputs
// Retry with 405 error recovery if needed
const maxRetries = 3;
@@ -2632,6 +2662,10 @@ async function fillVerificationCode(step, payload) {
} else {
log(`步骤 ${step}:验证码已通过${outcome.assumed ? '(按成功推定)' : ''}`, 'ok');
}
if (combinedSignupProfilePage && !outcome.invalidCode) {
outcome.skipProfileStep = true;
outcome.skipProfileStepReason = 'combined_verification_profile';
}
return outcome;
}
@@ -2663,6 +2697,11 @@ async function fillVerificationCode(step, payload) {
log(`步骤 ${step}:验证码已通过${outcome.assumed ? '(按成功推定)' : ''}`, 'ok');
}
if (combinedSignupProfilePage && !outcome.invalidCode) {
outcome.skipProfileStep = true;
outcome.skipProfileStepReason = 'combined_verification_profile';
}
return outcome;
}
@@ -3333,8 +3372,40 @@ function getStep5DirectCompletionPayload({ isAgeMode = false } = {}) {
return payload;
}
function isCombinedSignupVerificationProfilePage() {
if (!isEmailVerificationPage() || !isVerificationPageStillVisible()) {
return false;
}
if (!document.querySelector('form[action*="email-verification/register" i]')) {
return false;
}
const nameInput = document.querySelector('input[name="name"], input[autocomplete="name"]');
if (!nameInput || !isVisibleElement(nameInput)) {
return false;
}
const ageInput = document.querySelector('input[name="age"]');
if (ageInput && isVisibleElement(ageInput)) {
return true;
}
const yearSpinner = document.querySelector('[role="spinbutton"][data-type="year"]');
const monthSpinner = document.querySelector('[role="spinbutton"][data-type="month"]');
const daySpinner = document.querySelector('[role="spinbutton"][data-type="day"]');
return Boolean(
yearSpinner
&& monthSpinner
&& daySpinner
&& isVisibleElement(yearSpinner)
&& isVisibleElement(monthSpinner)
&& isVisibleElement(daySpinner)
);
}
async function step5_fillNameBirthday(payload) {
const { firstName, lastName, age, year, month, day } = payload;
const { firstName, lastName, age, year, month, day, prefillOnly = false } = payload;
if (!firstName || !lastName) throw new Error('未提供姓名数据。');
const resolvedAge = age ?? (year ? new Date().getFullYear() - Number(year) : null);
@@ -3533,6 +3604,11 @@ async function step5_fillNameBirthday(payload) {
}
if (prefillOnly) {
log('步骤 4:混合注册页资料已预填,继续填写验证码。', 'info');
return { prefilled: true };
}
// Click "完成帐户创建" button
await sleep(500);
const completeBtn = document.querySelector('button[type="submit"]')