This commit is contained in:
dengqichen 2025-11-16 21:07:17 +08:00
parent 740456ba56
commit 5d1d4e51ac
4 changed files with 91 additions and 11 deletions

View File

@ -79,7 +79,7 @@ class ImapConnector {
const sinceDate = new Date();
sinceDate.setDate(sinceDate.getDate() - sinceDays);
// 搜索条件最近N天的邮件
// 搜索条件最近N天的未读邮件
this.imap.search(['UNSEEN', ['SINCE', sinceDate]], async (err, results) => {
if (err) {
reject(err);

View File

@ -49,15 +49,19 @@ class EmailVerificationService {
const emails = await this.connector.getLatestEmails(10, 1);
if (emails && emails.length > 0) {
logger.info('EmailVerification', `找到 ${emails.length} 封未读邮件`);
// 3. 查找匹配的邮件并提取验证码
for (const email of emails.reverse()) { // 从最新的开始
logger.info('EmailVerification', `检查邮件: 发件人="${email.from}", 主题="${email.subject}"`);
for (const parser of this.parsers) {
if (parser.canParse(email)) {
logger.success('EmailVerification', `找到匹配的邮件: ${email.subject}`);
logger.success('EmailVerification', `找到匹配的邮件: ${email.subject}`);
const code = parser.extractCode(email);
if (code) {
logger.success('EmailVerification', `成功提取验证码: ${code}`);
logger.success('EmailVerification', `成功提取验证码: ${code}`);
// 标记为已读
try {
@ -70,10 +74,15 @@ class EmailVerificationService {
this.connector.disconnect();
return code;
} else {
logger.warn('EmailVerification', `邮件匹配但无法提取验证码`);
}
}
}
}
logger.warn('EmailVerification', `未找到匹配的Windsurf验证码邮件`);
} else {
logger.info('EmailVerification', `没有未读邮件`);
}
// 等待一段时间后再检查

View File

@ -10,7 +10,7 @@
* ... 根据实际情况继续添加步骤
*/
const BaseSite = require('../base-site');
const AccountDataGenerator = require('../generator');
const HumanBehavior = require('../utils/human-behavior');
const CloudflareHandler = require('../utils/cloudflare-handler');
const logger = require('../../../shared/logger');
@ -321,8 +321,63 @@ class WindsurfRegister {
*/
async handleCloudflareVerification() {
const cloudflareMode = DEFAULT_CONFIG.cloudflare.mode;
const handler = new CloudflareHandler(this.page, this.human, this.siteName, cloudflareMode);
return await handler.handle();
// 自定义检测函数检查Continue按钮是否激活
const customCheck = async () => {
try {
const buttonEnabled = await this.page.evaluate(() => {
const button = document.querySelector('button');
return button && !button.disabled;
});
return buttonEnabled;
} catch (e) {
return false;
}
};
const handler = new CloudflareHandler(this.page, this.human, this.siteName, cloudflareMode, customCheck);
const result = await handler.handle();
// 如果验证通过点击Continue按钮进入下一页
if (result === 'passed') {
logger.info(this.siteName, '[Cloudflare] 点击Continue按钮进入验证码页面...');
try {
const currentUrl = this.page.url();
const button = await this.page.$('button:not([disabled])');
if (button) {
await button.click();
// 等待页面跳转或内容改变
try {
// 方法1: 等待URL改变
await this.page.waitForFunction(
(oldUrl) => window.location.href !== oldUrl,
{ timeout: 10000 },
currentUrl
);
logger.success(this.siteName, '[Cloudflare] 页面已跳转');
} catch (e) {
// 方法2: 如果URL没变等待"Check your inbox"文本出现
try {
await this.page.waitForFunction(
() => document.body.textContent.includes('Check your inbox'),
{ timeout: 5000 }
);
logger.success(this.siteName, '[Cloudflare] 验证码页面已加载');
} catch (e2) {
logger.warn(this.siteName, '[Cloudflare] 等待页面改变超时,继续...');
}
}
// 额外等待确保页面稳定
await this.human.randomDelay(2000, 3000);
}
} catch (e) {
logger.warn(this.siteName, `[Cloudflare] 点击按钮失败: ${e.message}`);
}
}
return result;
}
/**
@ -347,14 +402,18 @@ class WindsurfRegister {
// 获取验证码(从邮箱)
logger.info(this.siteName, ' → 正在从邮箱获取验证码...');
logger.info(this.siteName, ` → 接收邮箱: ${this.accountData.email}`);
logger.info(this.siteName, ' → 注意:如果长时间无响应,请检查:');
logger.info(this.siteName, ' 1. 邮件是否已发送到邮箱');
logger.info(this.siteName, ' 2. QQ邮箱IMAP配置是否正确');
logger.info(this.siteName, ' 3. 邮件是否被标记为垃圾邮件');
const code = await this.emailService.getVerificationCode(
'windsurf',
this.accountData.email,
90 // 90秒超时
120 // 增加到120秒超时
);
logger.success(this.siteName, `验证码: ${code}`);
logger.success(this.siteName, `验证码: ${code}`);
// 等待验证码输入框加载
await this.human.randomDelay(2000, 3000);

View File

@ -11,12 +11,14 @@ class CloudflareHandler {
* @param {HumanBehavior} human - 人类行为模拟对象
* @param {string} siteName - 网站名称用于日志
* @param {string} mode - 验证模式: 'auto' 'manual' (默认 'manual')
* @param {Function} customCheck - 自定义检测函数返回Promise<boolean>检测验证是否完成
*/
constructor(page, human, siteName, mode = 'manual') {
constructor(page, human, siteName, mode = 'manual', customCheck = null) {
this.page = page;
this.human = human;
this.siteName = siteName;
this.mode = mode; // 'auto' 或 'manual'
this.customCheck = customCheck; // 自定义检测函数
}
/**
@ -183,15 +185,25 @@ class CloudflareHandler {
}
}
// 方法4: 自定义检测(由网站自己定义)
let customCheckPassed = false;
if (this.customCheck) {
try {
customCheckPassed = await this.customCheck();
} catch (e) {
// 忽略错误
}
}
// 每15秒输出一次状态
if (attempts % 15 === 0) {
const minutes = Math.floor(attempts / 60);
const seconds = attempts % 60;
logger.info(this.siteName, `[Cloudflare] 等待中... (${minutes}${seconds}秒/${Math.floor(maxAttempts/60)}分钟)`);
logger.info(this.siteName, `[Cloudflare] 等待中... (${minutes}${seconds}秒/${Math.floor(maxAttempts/60)}分钟) - custom=${customCheckPassed}, iframe=${iframeSuccess}`);
}
// 判断验证完成
if (iframeSuccess || (!hasVerifyText && attempts > 3) || urlChanged) {
if (customCheckPassed || iframeSuccess || (!hasVerifyText && attempts > 3) || urlChanged) {
verified = true;
logger.success(this.siteName, '[Cloudflare] ✓✓✓ 检测到验证完成!');
break;