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 CardGenerator = require('../../card-generator/generator');
|
||||||
const database = require('../../database');
|
const database = require('../../database');
|
||||||
const CapSolverAPI = require('../utils/capsolver-api');
|
const CapSolverAPI = require('../utils/capsolver-api');
|
||||||
|
const BrowserManager = require('../utils/browser-manager');
|
||||||
|
|
||||||
class WindsurfRegister {
|
class WindsurfRegister {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
@ -28,14 +29,17 @@ class WindsurfRegister {
|
|||||||
this.human = new HumanBehavior();
|
this.human = new HumanBehavior();
|
||||||
this.emailService = new EmailVerificationService();
|
this.emailService = new EmailVerificationService();
|
||||||
this.capsolver = new CapSolverAPI();
|
this.capsolver = new CapSolverAPI();
|
||||||
|
|
||||||
|
// 浏览器管理器(支持多profile并发)
|
||||||
|
this.browserManager = new BrowserManager({
|
||||||
|
profileId: options.adspowerUserId || process.env.ADSPOWER_USER_ID,
|
||||||
|
siteName: this.siteName
|
||||||
|
});
|
||||||
this.browser = null;
|
this.browser = null;
|
||||||
this.page = null;
|
this.page = null;
|
||||||
this.currentStep = 0;
|
this.currentStep = 0;
|
||||||
this.accountData = null;
|
this.accountData = null;
|
||||||
|
|
||||||
// AdsPower配置(支持多profile并发)
|
|
||||||
this.adspowerUserId = options.adspowerUserId || process.env.ADSPOWER_USER_ID;
|
|
||||||
|
|
||||||
// 记录注册时间和额外信息
|
// 记录注册时间和额外信息
|
||||||
this.registrationTime = null;
|
this.registrationTime = null;
|
||||||
this.quotaInfo = null;
|
this.quotaInfo = null;
|
||||||
@ -190,114 +194,22 @@ class WindsurfRegister {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化浏览器 - 使用 AdsPower 指纹浏览器
|
* 初始化浏览器
|
||||||
*/
|
*/
|
||||||
async initBrowser(options = {}) {
|
async initBrowser() {
|
||||||
const puppeteer = require('puppeteer');
|
const result = await this.browserManager.launch();
|
||||||
const axios = require('axios');
|
this.browser = result.browser;
|
||||||
|
this.page = result.page;
|
||||||
|
|
||||||
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
|
logger.info(this.siteName, '等待浏览器完全准备...');
|
||||||
|
await this.human.randomDelay(2000, 3000);
|
||||||
// 检查 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');
|
|
||||||
|
|
||||||
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() {
|
async closeBrowser() {
|
||||||
if (this.browser) {
|
await this.browserManager.close();
|
||||||
await this.browser.close();
|
|
||||||
logger.info(this.siteName, '浏览器已关闭');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1417,49 +1329,7 @@ class WindsurfRegister {
|
|||||||
logger.info(this.siteName, `[步骤 9/${this.getTotalSteps()}] 清理并关闭浏览器`);
|
logger.info(this.siteName, `[步骤 9/${this.getTotalSteps()}] 清理并关闭浏览器`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 清除所有浏览器数据(类似 Ctrl+Shift+Delete)
|
await this.browserManager.clearAndClose();
|
||||||
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, ' → ✓ 浏览器已关闭');
|
|
||||||
|
|
||||||
this.currentStep = 9;
|
this.currentStep = 9;
|
||||||
logger.success(this.siteName, `步骤 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