auto-register-verdent/emailModule.js
2025-11-13 14:31:44 +08:00

242 lines
8.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { config } from './config.js';
/**
* 设置临时邮箱并获取验证码
* @param {Page} page - Playwright 页面对象
* @returns {Promise<{email: string, code: string}>}
*/
export async function setupTempMail(page) {
console.log('📧 开始设置临时邮箱...');
// 访问 tempmail.plus增加超时时间因为网络较慢
await page.goto(config.tempmail.url, {
waitUntil: 'domcontentloaded', // 改为 domcontentloaded不等待所有网络请求
timeout: 60000 // 60秒超时
});
await page.waitForTimeout(3000); // 等待页面稳定
// 输入邮箱用户名(固定为配置的 qichen111
console.log('输入邮箱用户名:', config.tempmail.username);
await page.fill('#pre_button', config.tempmail.username);
// 点击页面其他位置或按回车来确认输入,触发邮箱地址更新
console.log('确认邮箱用户名...');
await page.click('body'); // 点击页面空白处
await page.waitForTimeout(2000);
// 检查 PIN 码弹窗是否已经显示
console.log('[LOG] 检查 PIN 码弹窗状态...');
const pinModal = page.locator('#modal-verify');
await page.waitForTimeout(2000); // 等待页面稳定
const initialModalClass = await pinModal.getAttribute('class');
console.log('[LOG] 弹窗 class:', initialModalClass);
// 判断弹窗是否已经显示(包含 "show" class
const isModalShown = initialModalClass && initialModalClass.includes('show');
console.log('[LOG] 弹窗是否已显示:', isModalShown);
if (!isModalShown) {
// 如果弹窗未显示,才需要点击 PIN 保护元素
console.log('[LOG] 弹窗未显示,点击 PIN 码保护元素...');
const pinProtectSpan = page.locator('span.pin-text[data-tr="box_protected"]');
await pinProtectSpan.waitFor({ state: 'visible', timeout: 15000 });
await pinProtectSpan.click({ force: true });
console.log('[LOG] ✅ 已点击 PIN 保护元素');
await page.waitForTimeout(2000);
} else {
console.log('[LOG] ✅ 弹窗已自动显示,无需点击');
}
// 查找 PIN 码输入框
console.log('[LOG] 查找 PIN 码输入框...');
const pinInput = page.locator('#pin');
const pinInputCount = await pinInput.count();
console.log('[LOG] 找到 PIN 输入框数量:', pinInputCount);
if (pinInputCount > 0) {
// 检查输入框是否可见
const isVisible = await pinInput.isVisible();
console.log('[LOG] PIN 输入框是否可见:', isVisible);
// 输入 PIN 码
console.log('[LOG] 输入 PIN 码:', config.tempmail.pinCode);
await pinInput.fill(config.tempmail.pinCode);
console.log('[LOG] ✅ PIN 码已输入');
await page.waitForTimeout(500);
// 查找提交按钮
console.log('[LOG] 查找提交按钮 #verify...');
const verifyButton = page.locator('#verify');
const verifyButtonCount = await verifyButton.count();
console.log('[LOG] 找到提交按钮数量:', verifyButtonCount);
if (verifyButtonCount > 0) {
const buttonText = await verifyButton.textContent();
console.log('[LOG] 按钮文本:', buttonText);
console.log('[LOG] 点击提交按钮...');
await verifyButton.click();
console.log('[LOG] ✅ 已点击提交按钮');
} else {
console.log('[LOG] ⚠️ 未找到提交按钮,尝试按回车');
await pinInput.press('Enter');
}
// 等待验证完成
await page.waitForTimeout(2000);
console.log('[LOG] ✅ PIN 码验证流程完成');
} else {
console.log('[LOG] ❌ 未找到 PIN 输入框!');
throw new Error('未找到 PIN 码输入框');
}
// 等待弹窗关闭后获取邮箱地址
await page.waitForTimeout(2000);
console.log('[LOG] 获取生成的邮箱地址...');
// 尝试多个可能的邮箱地址元素
let emailAddress = '';
// 方法 1: 查找特定的邮箱显示元素
const emailDisplay = page.locator('#email-address, #mail, .email-address, [id*="email"]').first();
if (await emailDisplay.count() > 0 && await emailDisplay.isVisible()) {
const text = await emailDisplay.textContent();
const match = text.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
if (match) {
emailAddress = match[0];
}
}
// 方法 2: 如果没找到,尝试从页面中提取所有包含 @ 的文本
if (!emailAddress) {
const pageContent = await page.content();
const emailMatches = pageContent.match(/qichen111@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
if (emailMatches && emailMatches.length > 0) {
emailAddress = emailMatches[0];
}
}
// 方法 3: 查找复制按钮附近的文本
if (!emailAddress) {
const copyButton = page.locator('button:has-text("复制")').first();
if (await copyButton.count() > 0) {
const parent = copyButton.locator('..');
const text = await parent.textContent();
const match = text.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
if (match) {
emailAddress = match[0];
}
}
}
console.log('[LOG] 提取到的邮箱地址:', emailAddress);
if (!emailAddress || !emailAddress.includes('@')) {
console.log('[LOG] ⚠️ 未能正确获取邮箱地址,尝试使用默认格式');
emailAddress = `${config.tempmail.username}@mailto.plus`;
}
console.log('✅ 邮箱地址:', emailAddress);
return { inboxReady: true, page };
}
/**
* 等待并获取验证码
* @param {Page} page - Playwright 页面对象
* @returns {Promise<string>} 验证码
*/
export async function waitForVerificationCode(page, sentAfterMs) {
console.log('⏳ 等待接收验证码邮件...');
console.log('[LOG] 不会刷新页面,只等待新邮件出现...');
const maxWaitTime = 120000; // 最多等待 120 秒
const checkInterval = 1000; // 每 1 秒检查一次
let elapsed = 0;
async function extractCodeFromOpenedMail() {
// 1) 优先从特定内容区域读取
const contentLoc = page.locator('.mail-content, .email-body, #mail-body, [class*="mail-content"], .pm-text, .view, .message-body').first();
if (await contentLoc.count() > 0) {
const text = await contentLoc.textContent();
const code = /\b(\d{6})\b/.exec(text || '');
if (code) return code[1];
}
// 2) 遍历所有 iframe 提取文本
const frames = page.frames();
console.log(`[LOG] 当前 frame 数量: ${frames.length}`);
for (const f of frames) {
try {
const body = await f.$('body');
if (!body) continue;
const text = await f.evaluate(() => document.body.innerText || '');
const m = /\b(\d{6})\b/.exec(text);
if (m) return m[1];
} catch {}
}
// 3) 退化为整页文本
const all = await page.textContent('body');
const m = /\b(\d{6})\b/.exec(all || '');
return m ? m[1] : null;
}
while (elapsed < maxWaitTime) {
await page.waitForTimeout(checkInterval);
elapsed += checkInterval;
console.log(`[LOG] 检查邮件... (已等待 ${elapsed / 1000} 秒)`);
// 邮件列表行(兼容多种结构)
const emailRows = page.locator('.inbox-dataList .mail-item, .inbox-dataList > div, div.row.no-gutters');
const emailCount = await emailRows.count();
console.log(`[LOG] 当前邮件数量: ${emailCount}`);
if (emailCount > 0) {
console.log('📬 发现邮件,尝试读取...');
// 遍历所有邮件,优先读取发送之后的邮件(按顺序尝试)
for (let i = 0; i < emailCount; i++) {
const emailRow = emailRows.nth(i);
// 过滤发送时间之前的旧邮件(根据 data-date
try {
const timeSpan = emailRow.locator('span[data-date]').first();
if (await timeSpan.count() > 0) {
const dateStr = await timeSpan.getAttribute('data-date');
if (dateStr) {
const parsed = Date.parse(dateStr.replace(' ', 'T')) || new Date(dateStr).getTime();
if (sentAfterMs && parsed && parsed < sentAfterMs) {
console.log(`[LOG] 跳过旧邮件 ${dateStr}`);
continue;
}
}
}
} catch {}
try {
// 点击打开邮件(有些需要双击/再次点击切换到详情)
await emailRow.click({ timeout: 5000 });
await page.waitForTimeout(500);
try { await emailRow.dblclick({ timeout: 1000 }); } catch {}
// 等待内容区域或 iframe 加载
await page.waitForTimeout(1500);
const code = await extractCodeFromOpenedMail();
if (code) {
console.log('✅ 获取到验证码:', code);
return code;
}
console.log(`[LOG] 邮件 ${i + 1} 中未找到验证码`);
} catch (error) {
console.log(`[LOG] 读取邮件 ${i + 1} 失败:`, error.message);
}
}
console.log('⚠️ 所有邮件中未找到验证码,继续等待...');
}
}
throw new Error('超时:未能在规定时间内收到验证码');
}