dasdasd
This commit is contained in:
parent
82d62145f1
commit
13cd9fbb49
@ -19,6 +19,7 @@ const { DEFAULT_CONFIG } = require('../config');
|
||||
const CardGenerator = require('../../card-generator/generator');
|
||||
const database = require('../../database');
|
||||
const CapSolverAPI = require('../utils/capsolver-api');
|
||||
const BrowserManager = require('../utils/browser-manager');
|
||||
|
||||
class WindsurfRegister {
|
||||
constructor(options = {}) {
|
||||
@ -28,14 +29,17 @@ class WindsurfRegister {
|
||||
this.human = new HumanBehavior();
|
||||
this.emailService = new EmailVerificationService();
|
||||
this.capsolver = new CapSolverAPI();
|
||||
|
||||
// 浏览器管理器(支持多profile并发)
|
||||
this.browserManager = new BrowserManager({
|
||||
profileId: options.adspowerUserId || process.env.ADSPOWER_USER_ID,
|
||||
siteName: this.siteName
|
||||
});
|
||||
this.browser = null;
|
||||
this.page = null;
|
||||
this.currentStep = 0;
|
||||
this.accountData = null;
|
||||
|
||||
// AdsPower配置(支持多profile并发)
|
||||
this.adspowerUserId = options.adspowerUserId || process.env.ADSPOWER_USER_ID;
|
||||
|
||||
// 记录注册时间和额外信息
|
||||
this.registrationTime = null;
|
||||
this.quotaInfo = null;
|
||||
@ -190,114 +194,22 @@ class WindsurfRegister {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化浏览器 - 使用 AdsPower 指纹浏览器
|
||||
* 初始化浏览器
|
||||
*/
|
||||
async initBrowser(options = {}) {
|
||||
const puppeteer = require('puppeteer');
|
||||
const axios = require('axios');
|
||||
|
||||
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
|
||||
|
||||
// 检查 AdsPower 配置
|
||||
const adspowerUserId = this.adspowerUserId;
|
||||
if (!adspowerUserId) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID');
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '请在 .env 文件中配置或传入 options.adspowerUserId:');
|
||||
logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id');
|
||||
logger.error(this.siteName, '');
|
||||
throw new Error('未配置 AdsPower 用户ID');
|
||||
}
|
||||
|
||||
const apiBase = process.env.ADSPOWER_API || 'http://local.adspower.net:50325';
|
||||
const apiKey = process.env.ADSPOWER_API_KEY;
|
||||
|
||||
const startUrl = `${apiBase}/api/v1/browser/start?user_id=${encodeURIComponent(adspowerUserId)}`;
|
||||
|
||||
// 配置请求头
|
||||
const headers = {};
|
||||
if (apiKey && apiKey.trim()) {
|
||||
headers['Authorization'] = `Bearer ${apiKey}`;
|
||||
logger.info(this.siteName, '✓ 使用 API Key 认证');
|
||||
}
|
||||
|
||||
logger.info(this.siteName, ` → 启动 AdsPower 配置: ${adspowerUserId}`);
|
||||
|
||||
try {
|
||||
const response = await axios.get(startUrl, { headers });
|
||||
const data = response.data;
|
||||
|
||||
if (data.code !== 0) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, `AdsPower API 返回错误: ${JSON.stringify(data)}`);
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '解决方案:');
|
||||
logger.error(this.siteName, '1. 确保 AdsPower 应用已启动并登录');
|
||||
logger.error(this.siteName, '2. 检查配置文件 ID 是否正确: ' + adspowerUserId);
|
||||
logger.error(this.siteName, '3. 如果需要 API Key,请在 AdsPower 设置中生成');
|
||||
logger.error(this.siteName, '4. 尝试在 AdsPower 中手动打开一次浏览器配置');
|
||||
logger.error(this.siteName, '');
|
||||
throw new Error(`AdsPower 启动失败: ${data.msg || JSON.stringify(data)}`);
|
||||
}
|
||||
|
||||
// 获取 WebSocket 端点
|
||||
const wsEndpoint = data.data.ws && (
|
||||
data.data.ws.puppeteer ||
|
||||
data.data.ws.selenium ||
|
||||
data.data.ws.ws ||
|
||||
data.data.ws
|
||||
);
|
||||
|
||||
if (!wsEndpoint) {
|
||||
throw new Error('AdsPower 未返回 WebSocket 端点');
|
||||
}
|
||||
|
||||
logger.info(this.siteName, ` → WebSocket: ${wsEndpoint}`);
|
||||
|
||||
// 连接到 AdsPower 浏览器
|
||||
this.browser = await puppeteer.connect({
|
||||
browserWSEndpoint: wsEndpoint,
|
||||
defaultViewport: null
|
||||
});
|
||||
|
||||
// 获取已存在的页面
|
||||
const pages = await this.browser.pages();
|
||||
this.page = pages[0] || await this.browser.newPage();
|
||||
|
||||
// 关闭多余的标签页(AdsPower 需要至少保留一个)
|
||||
if (pages.length > 1) {
|
||||
for (let i = 1; i < pages.length; i++) {
|
||||
try {
|
||||
await pages[i].close();
|
||||
} catch (e) {
|
||||
// 忽略关闭失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.success(this.siteName, '✓ AdsPower 浏览器连接成功');
|
||||
logger.info(this.siteName, '✓ 使用真实指纹,可同时绕过 Cloudflare 和 Stripe');
|
||||
async initBrowser() {
|
||||
const result = await this.browserManager.launch();
|
||||
this.browser = result.browser;
|
||||
this.page = result.page;
|
||||
|
||||
logger.info(this.siteName, '等待浏览器完全准备...');
|
||||
await this.human.randomDelay(2000, 3000);
|
||||
|
||||
} catch (error) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, `❌ AdsPower 连接失败: ${error.message}`);
|
||||
logger.error(this.siteName, '');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭浏览器
|
||||
*/
|
||||
async closeBrowser() {
|
||||
if (this.browser) {
|
||||
await this.browser.close();
|
||||
logger.info(this.siteName, '浏览器已关闭');
|
||||
}
|
||||
await this.browserManager.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1417,49 +1329,7 @@ class WindsurfRegister {
|
||||
logger.info(this.siteName, `[步骤 9/${this.getTotalSteps()}] 清理并关闭浏览器`);
|
||||
|
||||
try {
|
||||
// 清除所有浏览器数据(类似 Ctrl+Shift+Delete)
|
||||
logger.info(this.siteName, ' → 清除所有浏览器数据(Cookies、Cache、Storage等)...');
|
||||
try {
|
||||
// 使用 Chrome DevTools Protocol 进行深度清理
|
||||
const client = await this.page.target().createCDPSession();
|
||||
|
||||
// 1. 清除浏览器 Cookies
|
||||
await client.send('Network.clearBrowserCookies');
|
||||
logger.success(this.siteName, ' → ✓ 已清除所有 Cookies');
|
||||
|
||||
// 2. 清除浏览器缓存
|
||||
await client.send('Network.clearBrowserCache');
|
||||
logger.success(this.siteName, ' → ✓ 已清除浏览器缓存');
|
||||
|
||||
// 3. 清除所有存储数据(localStorage, sessionStorage, IndexedDB, WebSQL, Cache Storage, Service Workers)
|
||||
await client.send('Storage.clearDataForOrigin', {
|
||||
origin: '*',
|
||||
storageTypes: 'all'
|
||||
});
|
||||
logger.success(this.siteName, ' → ✓ 已清除所有存储数据');
|
||||
|
||||
// 4. 额外清理:访问目标网站并清除其存储
|
||||
await this.page.goto('https://windsurf.com', { waitUntil: 'domcontentloaded' });
|
||||
await this.page.evaluate(() => {
|
||||
try {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
// 5. 关闭 CDP 会话
|
||||
await client.detach();
|
||||
|
||||
logger.success(this.siteName, ' → ✓ 浏览器数据清除完成(全新状态)');
|
||||
|
||||
} catch (e) {
|
||||
logger.warn(this.siteName, ` → 清除浏览器数据失败: ${e.message}`);
|
||||
}
|
||||
|
||||
// 关闭浏览器
|
||||
logger.info(this.siteName, ' → 关闭浏览器...');
|
||||
await this.closeBrowser();
|
||||
logger.success(this.siteName, ' → ✓ 浏览器已关闭');
|
||||
await this.browserManager.clearAndClose();
|
||||
|
||||
this.currentStep = 9;
|
||||
logger.success(this.siteName, `步骤 9 完成`);
|
||||
|
||||
214
src/tools/account-register/utils/browser-manager.js
Normal file
214
src/tools/account-register/utils/browser-manager.js
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Browser Manager - AdsPower 指纹浏览器管理器
|
||||
* 统一管理浏览器的启动、连接、关闭等操作
|
||||
*/
|
||||
|
||||
const puppeteer = require('puppeteer');
|
||||
const axios = require('axios');
|
||||
const logger = require('../../../shared/logger');
|
||||
|
||||
class BrowserManager {
|
||||
constructor(options = {}) {
|
||||
this.profileId = options.profileId || process.env.ADSPOWER_USER_ID;
|
||||
this.apiBase = options.apiBase || process.env.ADSPOWER_API || 'http://local.adspower.net:50325';
|
||||
this.apiKey = options.apiKey || process.env.ADSPOWER_API_KEY;
|
||||
this.siteName = options.siteName || 'Browser';
|
||||
|
||||
this.browser = null;
|
||||
this.page = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 AdsPower 浏览器
|
||||
*/
|
||||
async launch() {
|
||||
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
|
||||
|
||||
// 检查配置
|
||||
if (!this.profileId) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID');
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '请在 .env 文件中配置或传入 profileId:');
|
||||
logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id');
|
||||
logger.error(this.siteName, '');
|
||||
throw new Error('未配置 AdsPower 用户ID');
|
||||
}
|
||||
|
||||
const startUrl = `${this.apiBase}/api/v1/browser/start?user_id=${encodeURIComponent(this.profileId)}`;
|
||||
|
||||
// 配置请求头
|
||||
const headers = {};
|
||||
if (this.apiKey && this.apiKey.trim()) {
|
||||
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
||||
logger.info(this.siteName, '✓ 使用 API Key 认证');
|
||||
}
|
||||
|
||||
logger.info(this.siteName, ` → 启动 AdsPower 配置: ${this.profileId}`);
|
||||
|
||||
try {
|
||||
const response = await axios.get(startUrl, { headers });
|
||||
const data = response.data;
|
||||
|
||||
if (data.code !== 0) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, `AdsPower API 返回错误: ${JSON.stringify(data)}`);
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, '解决方案:');
|
||||
logger.error(this.siteName, '1. 确保 AdsPower 应用已启动并登录');
|
||||
logger.error(this.siteName, `2. 检查配置文件 ID 是否正确: ${this.profileId}`);
|
||||
logger.error(this.siteName, '3. 如果需要 API Key,请在 AdsPower 设置中生成');
|
||||
logger.error(this.siteName, '4. 尝试在 AdsPower 中手动打开一次浏览器配置');
|
||||
logger.error(this.siteName, '');
|
||||
throw new Error(`AdsPower 启动失败: ${data.msg || JSON.stringify(data)}`);
|
||||
}
|
||||
|
||||
// 获取 WebSocket 端点
|
||||
const wsEndpoint = data.data.ws && (
|
||||
data.data.ws.puppeteer ||
|
||||
data.data.ws.selenium ||
|
||||
data.data.ws.ws ||
|
||||
data.data.ws
|
||||
);
|
||||
|
||||
if (!wsEndpoint) {
|
||||
throw new Error('AdsPower 未返回 WebSocket 端点');
|
||||
}
|
||||
|
||||
logger.info(this.siteName, ` → WebSocket: ${wsEndpoint}`);
|
||||
|
||||
// 连接到 AdsPower 浏览器
|
||||
this.browser = await puppeteer.connect({
|
||||
browserWSEndpoint: wsEndpoint,
|
||||
defaultViewport: null
|
||||
});
|
||||
|
||||
// 获取已存在的页面
|
||||
const pages = await this.browser.pages();
|
||||
this.page = pages[0] || await this.browser.newPage();
|
||||
|
||||
// 关闭多余的标签页
|
||||
if (pages.length > 1) {
|
||||
for (let i = 1; i < pages.length; i++) {
|
||||
try {
|
||||
await pages[i].close();
|
||||
} catch (e) {
|
||||
// 忽略关闭失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.success(this.siteName, '✓ AdsPower 浏览器连接成功');
|
||||
logger.info(this.siteName, '✓ 使用真实指纹,可同时绕过 Cloudflare 和 Stripe');
|
||||
|
||||
return { browser: this.browser, page: this.page };
|
||||
|
||||
} catch (error) {
|
||||
logger.error(this.siteName, '');
|
||||
logger.error(this.siteName, `❌ AdsPower 连接失败: ${error.message}`);
|
||||
logger.error(this.siteName, '');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前页面
|
||||
*/
|
||||
getPage() {
|
||||
if (!this.page) {
|
||||
throw new Error('浏览器页面未初始化,请先调用 launch()');
|
||||
}
|
||||
return this.page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器实例
|
||||
*/
|
||||
getBrowser() {
|
||||
if (!this.browser) {
|
||||
throw new Error('浏览器未初始化,请先调用 launch()');
|
||||
}
|
||||
return this.browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除浏览器数据
|
||||
*/
|
||||
async clearData() {
|
||||
if (!this.page) {
|
||||
logger.warn(this.siteName, '页面未初始化,跳过清除数据');
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(this.siteName, ' → 清除所有浏览器数据(Cookies、Cache、Storage等)...');
|
||||
|
||||
try {
|
||||
const client = await this.page.target().createCDPSession();
|
||||
|
||||
// 1. 清除浏览器 Cookies
|
||||
await client.send('Network.clearBrowserCookies');
|
||||
logger.success(this.siteName, ' → ✓ 已清除所有 Cookies');
|
||||
|
||||
// 2. 清除浏览器缓存
|
||||
await client.send('Network.clearBrowserCache');
|
||||
logger.success(this.siteName, ' → ✓ 已清除浏览器缓存');
|
||||
|
||||
// 3. 清除所有存储数据
|
||||
await client.send('Storage.clearDataForOrigin', {
|
||||
origin: '*',
|
||||
storageTypes: 'all'
|
||||
});
|
||||
logger.success(this.siteName, ' → ✓ 已清除所有存储数据');
|
||||
|
||||
// 4. 额外清理:访问目标网站并清除其存储
|
||||
const currentUrl = this.page.url();
|
||||
if (currentUrl && currentUrl.startsWith('http')) {
|
||||
await this.page.evaluate(() => {
|
||||
try {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
// 5. 关闭 CDP 会话
|
||||
await client.detach();
|
||||
|
||||
logger.success(this.siteName, ' → ✓ 浏览器数据清除完成(全新状态)');
|
||||
|
||||
} catch (e) {
|
||||
logger.warn(this.siteName, ` → 清除浏览器数据失败: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭浏览器
|
||||
*/
|
||||
async close() {
|
||||
if (!this.browser) {
|
||||
logger.warn(this.siteName, '浏览器未初始化,无需关闭');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info(this.siteName, ' → 关闭浏览器...');
|
||||
await this.browser.disconnect();
|
||||
this.browser = null;
|
||||
this.page = null;
|
||||
logger.success(this.siteName, ' → ✓ 浏览器已关闭');
|
||||
} catch (error) {
|
||||
logger.error(this.siteName, `关闭浏览器失败: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除数据并关闭浏览器
|
||||
*/
|
||||
async clearAndClose() {
|
||||
await this.clearData();
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BrowserManager;
|
||||
Loading…
Reference in New Issue
Block a user