From e4e9465bed3c10553f232a09ce86fd67ba9fe222 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Tue, 18 Nov 2025 11:23:58 +0800 Subject: [PATCH] dasdasd --- src/tools/account-register/sites/windsurf.js | 176 +++++++++++-------- 1 file changed, 101 insertions(+), 75 deletions(-) diff --git a/src/tools/account-register/sites/windsurf.js b/src/tools/account-register/sites/windsurf.js index ff5dc0e..2fc125a 100644 --- a/src/tools/account-register/sites/windsurf.js +++ b/src/tools/account-register/sites/windsurf.js @@ -1192,61 +1192,69 @@ class WindsurfRegister { logger.info(this.siteName, ' → Token 已注入,准备点击 checkbox'); } - // 等待一下,让 token 生效 - await this.human.randomDelay(1000, 2000); + // 等待更长时间,让 hCaptcha 完全响应(可能降级为图片) + logger.info(this.siteName, ' → 等待 hCaptcha 响应(5秒)...'); + await this.human.randomDelay(5000, 6000); - // 点击对话框中的 checkbox(必须!) - logger.info(this.siteName, ' → 查找并点击 checkbox...'); - try { - const checkboxClicked = await this.page.evaluate(() => { - const dialog = document.querySelector('[role="dialog"]'); - if (!dialog) return { success: false, reason: 'no-dialog' }; - - // 查找 checkbox 元素 - const checkbox = dialog.querySelector('input[type="checkbox"]') || - dialog.querySelector('[role="checkbox"]') || - dialog.querySelector('#checkbox'); - - if (checkbox) { - const rect = checkbox.getBoundingClientRect(); - if (rect.width > 0 && rect.height > 0) { - checkbox.click(); - return { - success: true, - checked: checkbox.checked, - coords: { x: Math.round(rect.left + rect.width/2), y: Math.round(rect.top + rect.height/2) } - }; - } - return { success: false, reason: 'not-visible' }; - } - return { success: false, reason: 'not-found' }; - }); + // 检测是否有图片挑战出现 + logger.info(this.siteName, ' → 检测验证码状态...'); + const captchaStatus = await this.page.evaluate(() => { + // 检查所有 iframe + const iframes = document.querySelectorAll('iframe'); + let hasImageChallenge = false; + let challengeText = ''; - if (checkboxClicked.success) { - logger.success(this.siteName, ` → ✓ 已点击 checkbox`); - } else { - logger.warn(this.siteName, ` → ⚠️ 未找到 checkbox (${checkboxClicked.reason}),尝试坐标点击...`); - - // 备用方案:通过坐标点击对话框左侧 - const coords = await this.page.evaluate(() => { - const dialog = document.querySelector('[role="dialog"]'); - if (!dialog) return null; - - const rect = dialog.getBoundingClientRect(); - // checkbox 通常在对话框左侧,距离顶部约 1/3 处 - return { - x: rect.left + 40, - y: rect.top + rect.height * 0.4 - }; - }); - - if (coords) { - await this.page.mouse.click(coords.x, coords.y); - logger.success(this.siteName, ` → ✓ 已点击坐标 (${coords.x}, ${coords.y})`); + for (const iframe of iframes) { + try { + // 检查 iframe 的 src 是否包含 hcaptcha + if (iframe.src && iframe.src.includes('hcaptcha')) { + // 尝试访问 iframe 内容(跨域可能失败) + try { + const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; + if (iframeDoc) { + const bodyText = iframeDoc.body ? iframeDoc.body.innerText : ''; + if (bodyText.includes('点击') || bodyText.includes('选择') || bodyText.includes('Select')) { + hasImageChallenge = true; + challengeText = bodyText.substring(0, 50); + break; + } + } + } catch (e) { + // 跨域 iframe,无法访问内容 + } + + // 即使无法访问内容,如果 iframe 存在且可见,也认为可能有挑战 + const rect = iframe.getBoundingClientRect(); + if (rect.width > 300 && rect.height > 300) { + hasImageChallenge = true; + break; + } + } + } catch (e) { + // 忽略错误 } } - } catch (e) { - logger.warn(this.siteName, ` → 点击失败: ${e.message}`); + + // 检查主页面的 response + const response = document.querySelector('[name="h-captcha-response"]') || + document.querySelector('[name="g-recaptcha-response"]'); + const hasResponse = response && response.value && response.value.length > 20; + + return { + hasImageChallenge, + hasResponse, + challengeText, + iframeCount: iframes.length + }; + }); + + logger.info(this.siteName, ` → 检测结果: iframe数=${captchaStatus.iframeCount}, 图片挑战=${captchaStatus.hasImageChallenge}, token已填充=${captchaStatus.hasResponse}`); + + if (captchaStatus.hasImageChallenge) { + logger.warn(this.siteName, ' → ⚠️ 检测到图片挑战,Token 可能被拒绝!'); + if (captchaStatus.challengeText) { + logger.info(this.siteName, ` → 挑战内容: ${captchaStatus.challengeText}`); + } } await this.human.randomDelay(1000, 2000); @@ -1255,53 +1263,70 @@ class WindsurfRegister { logger.info(this.siteName, ' → 等待验证完成...'); const startTime = Date.now(); let dialogClosed = false; - let hasImageChallenge = false; - const maxWaitTime = 60000; // 最多60秒(包含图片挑战时间) + let hasImageChallenge = captchaStatus.hasImageChallenge; // 使用前面检测的结果 + const maxWaitTime = 120000; // 图片挑战需要更长时间,最多120秒 + + if (hasImageChallenge) { + logger.warn(this.siteName, ' → ⚠️ 需要手动完成图片验证(最多等待120秒)...'); + } while (Date.now() - startTime < maxWaitTime) { + // 优先检查页面是否跳转(支付成功) + const currentUrl = this.page.url(); + if (!currentUrl.includes('stripe.com') && !currentUrl.includes('checkout.stripe.com')) { + dialogClosed = true; + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + logger.success(this.siteName, ` → ✓ 验证完成,页面已跳转(耗时${elapsed}秒)`); + break; + } + const status = await this.page.evaluate(() => { - const dialog = document.querySelector('[role="dialog"]'); - if (!dialog) return { dialogGone: true, verified: true, hasImageChallenge: false }; - - const style = window.getComputedStyle(dialog); - const isHidden = style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0'; - - // 检查 token 是否已填充 + // 检查 token 是否已填充(主要判断依据) const response = document.querySelector('[name="h-captcha-response"]') || document.querySelector('[name="g-recaptcha-response"]'); const hasResponse = response && response.value && response.value.length > 20; - // 检查是否有图片挑战 - const dialogText = dialog.innerText || ''; - const hasImageTask = dialogText.includes('选择') || - dialogText.includes('Select') || - dialog.querySelector('img[src*="hcaptcha"]') || - dialog.querySelector('[class*="task"]'); + // 检查 iframe 中的图片挑战 + let hasImageChallenge = false; + const iframes = document.querySelectorAll('iframe[src*="hcaptcha"]'); + for (const iframe of iframes) { + const rect = iframe.getBoundingClientRect(); + if (rect.width > 300 && rect.height > 300) { + hasImageChallenge = true; + break; + } + } return { - dialogGone: !dialog || isHidden, verified: hasResponse, - hasImageChallenge: hasImageTask, - dialogText: dialogText.substring(0, 80) + hasImageChallenge: hasImageChallenge, + iframeCount: iframes.length }; }); - // 第一次检测到图片挑战 + // 第一次检测到图片挑战(之前没检测到) if (status.hasImageChallenge && !hasImageChallenge) { hasImageChallenge = true; - logger.warn(this.siteName, ' → ⚠️ Token 被降级,出现图片挑战!'); - logger.info(this.siteName, ` → 任务: ${status.dialogText}`); + logger.warn(this.siteName, ' → ⚠️ 检测到图片挑战!'); logger.warn(this.siteName, ' → 请手动完成图片验证...'); } - // 验证完成 - if (status.dialogGone || (status.verified && !status.hasImageChallenge)) { + // 验证完成的条件:token 已填充 且 没有图片挑战 + if (status.verified && !status.hasImageChallenge) { dialogClosed = true; const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); logger.success(this.siteName, ` → ✓ 验证完成(耗时${elapsed}秒)`); break; } + // 每10秒输出一次进度(仅在有图片挑战时) + if (hasImageChallenge) { + const elapsed = Date.now() - startTime; + if (elapsed > 0 && elapsed % 10000 === 0) { + logger.info(this.siteName, ` → 等待手动验证... (${(elapsed/1000).toFixed(0)}秒)`); + } + } + // 动态调整检查间隔 const interval = hasImageChallenge ? 2000 : 1000; await new Promise(resolve => setTimeout(resolve, interval)); @@ -1978,7 +2003,8 @@ class WindsurfRegister { billingDate: this.billingInfo ? this.billingInfo.date : null, paymentCardNumber: this.cardInfo ? this.cardInfo.number : null, paymentCountry: this.cardInfo ? this.cardInfo.country : 'MO', - status: 'active' + status: 'active', + isOnSale: false }; // 保存到数据库