106 lines
3.8 KiB
JavaScript
106 lines
3.8 KiB
JavaScript
'use strict';
|
|
|
|
const path = require('path');
|
|
const { chromium } = require('playwright');
|
|
const db = require('../src/core/database');
|
|
const { openBrowserWithRetry, closeBrowser } = require('../src/core/bit_api');
|
|
const { createGmailAppPassword } = require('../src/services/gmail_app_password_service');
|
|
|
|
async function inspectPage(page, email) {
|
|
return page.evaluate(targetEmail => {
|
|
const visible = element => {
|
|
const style = window.getComputedStyle(element);
|
|
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
};
|
|
const clean = value => String(value || '')
|
|
.replace(new RegExp(targetEmail.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'ig'), '[email]')
|
|
.replace(/\s+/g, ' ')
|
|
.trim();
|
|
return {
|
|
title: document.title,
|
|
bodyText: clean(document.body && document.body.innerText).slice(0, 1200),
|
|
inputs: [...document.querySelectorAll('input')].filter(visible).map(input => ({
|
|
type: input.type,
|
|
name: input.name,
|
|
id: input.id,
|
|
ariaLabel: input.getAttribute('aria-label'),
|
|
placeholder: input.getAttribute('placeholder'),
|
|
hasValue: !!input.value,
|
|
})),
|
|
buttons: [...document.querySelectorAll('button, [role="button"]')].filter(visible)
|
|
.map(button => clean(button.innerText || button.getAttribute('aria-label')))
|
|
.filter(Boolean)
|
|
.slice(0, 30),
|
|
};
|
|
}, email).catch(() => ({ title: '', bodyText: '', inputs: [], buttons: [] }));
|
|
}
|
|
|
|
async function main() {
|
|
const email = String(process.argv[2] || '').trim();
|
|
if (!email) throw new Error('用法: node scripts/obtain_gmail_app_password.js <email>');
|
|
|
|
db.initDB();
|
|
const account = db.getAllAccounts().find(item => String(item.email || '').toLowerCase() === email.toLowerCase());
|
|
if (!account) throw new Error('数据库中不存在该邮箱');
|
|
if (!account.browser_id) throw new Error('该邮箱没有浏览器编号');
|
|
if (db.hasGmailAppPassword(email)) {
|
|
console.log(JSON.stringify({ ok: true, alreadySaved: true, email }));
|
|
return;
|
|
}
|
|
|
|
const opened = await openBrowserWithRetry(account.browser_id, {
|
|
email,
|
|
logCallback: message => console.log(message),
|
|
});
|
|
if (!opened || !opened.success || !opened.data || !opened.data.ws) {
|
|
throw new Error(`打开比特浏览器失败:${opened && opened.msg ? opened.msg : '无 ws 端点'}`);
|
|
}
|
|
|
|
let browser;
|
|
let page;
|
|
let succeeded = false;
|
|
try {
|
|
browser = await chromium.connectOverCDP(opened.data.ws);
|
|
const context = browser.contexts()[0];
|
|
page = await context.newPage();
|
|
await page.bringToFront().catch(() => {});
|
|
const result = await createGmailAppPassword(page, account, message => console.log(message), {
|
|
appName: 'zhaoqiaoqing2001',
|
|
timeoutMs: 60000,
|
|
captchaWaitMs: 5 * 60 * 1000,
|
|
});
|
|
|
|
if (result.ok && result.appPassword) {
|
|
db.upsertGmailAppPassword(email, result.appPassword);
|
|
succeeded = true;
|
|
console.log(JSON.stringify({ ok: true, saved: true, email, passwordLength: result.appPassword.length }));
|
|
return;
|
|
}
|
|
|
|
const inspection = await inspectPage(page, email);
|
|
const screenshotPath = path.join(
|
|
db.getDb().name ? path.dirname(db.getDb().name) : path.join(__dirname, '..', 'data'),
|
|
'screenshots',
|
|
`gmail_app_password_${email.replace(/[^a-z0-9]+/gi, '_')}.png`,
|
|
);
|
|
await page.screenshot({ path: screenshotPath, fullPage: true }).catch(() => {});
|
|
console.log(JSON.stringify({
|
|
ok: false,
|
|
email,
|
|
message: result.msg,
|
|
url: page.url(),
|
|
inspection,
|
|
screenshotPath,
|
|
}));
|
|
process.exitCode = 2;
|
|
} finally {
|
|
if (browser) await browser.close().catch(() => {});
|
|
if (succeeded) await closeBrowser(account.browser_id).catch(() => {});
|
|
}
|
|
}
|
|
|
|
main().catch(error => {
|
|
console.error(JSON.stringify({ ok: false, message: error.message }));
|
|
process.exitCode = 1;
|
|
});
|