From 1a61f5c917b88628b8f6eb8a2447467830db2d81 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Mon, 17 Nov 2025 15:50:35 +0800 Subject: [PATCH] dasdasd --- .env | 5 + src/tools/account-register/sites/windsurf.js | 300 ++++++------------- 2 files changed, 104 insertions(+), 201 deletions(-) diff --git a/.env b/.env index 3427474..5479cf6 100644 --- a/.env +++ b/.env @@ -1,2 +1,7 @@ # CapSolver API Key CAPSOLVER_API_KEY=CAP-0FCDDA4906E87D9F4FF68EAECD34E320876FBA70E4F30EA1ADCD264EDB15E4BF + +# AdsPower 指纹浏览器配置 +ADSPOWER_USER_ID=k1728p8l +ADSPOWER_API_KEY=35de43696f6241f3df895f2f48777a99 +# ADSPOWER_API=http://local.adspower.net:50325 diff --git a/src/tools/account-register/sites/windsurf.js b/src/tools/account-register/sites/windsurf.js index 05d77cb..f1ade8f 100644 --- a/src/tools/account-register/sites/windsurf.js +++ b/src/tools/account-register/sites/windsurf.js @@ -30,7 +30,6 @@ class WindsurfRegister { this.page = null; this.currentStep = 0; this.accountData = null; - this.sessionData = null; // 会话数据(用于浏览器切换) // 初始化 CapSolver(自动解决 Cloudflare Turnstile) this.capsolverKey = process.env.CAPSOLVER_API_KEY || null; @@ -186,123 +185,113 @@ class WindsurfRegister { } /** - * 初始化浏览器 - * @param {Object} options - 选项 - * @param {boolean} options.skipExtension - 是否跳过扩展加载(用于支付步骤) + * 初始化浏览器 - 使用 AdsPower 指纹浏览器 */ async initBrowser(options = {}) { const puppeteer = require('puppeteer'); - const path = require('path'); + const axios = require('axios'); - const browserType = options.skipExtension ? '干净浏览器(无扩展)' : '浏览器(集成 CapSolver 扩展)'; - logger.info(this.siteName, `启动${browserType}...`); + logger.info(this.siteName, '启动 AdsPower 指纹浏览器...'); - // 随机视口大小 - const viewports = [ - { width: 1920, height: 1080 }, - { width: 1366, height: 768 }, - { width: 1536, height: 864 }, - { width: 1440, height: 900 } - ]; - const viewport = viewports[Math.floor(Math.random() * viewports.length)]; + // 检查 AdsPower 配置 + const adspowerUserId = process.env.ADSPOWER_USER_ID; + if (!adspowerUserId) { + logger.error(this.siteName, ''); + logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID'); + logger.error(this.siteName, ''); + logger.error(this.siteName, '请在 .env 文件中配置:'); + logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id'); + logger.error(this.siteName, ''); + throw new Error('未配置 AdsPower 用户ID'); + } - const launchOptions = { - headless: false, - args: [ - '--no-sandbox', - '--disable-setuid-sandbox', - `--window-size=${viewport.width},${viewport.height}` - ] - }; + const apiBase = process.env.ADSPOWER_API || 'http://local.adspower.net:50325'; + const apiKey = process.env.ADSPOWER_API_KEY; - // 如果配置了 CapSolver 且 不跳过扩展,加载扩展 - if (!options.skipExtension && this.capsolverKey) { - const fs = require('fs'); - const os = require('os'); + 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; - // 使用绝对路径:从当前文件向上找到项目根目录 - const projectRoot = path.resolve(__dirname, '../../../../'); - const extensionPath = path.join(projectRoot, 'extensions', 'capsolver'); - - if (fs.existsSync(extensionPath)) { - // 检查关键文件是否存在 - const manifestPath = path.join(extensionPath, 'manifest.json'); - const configPath = path.join(extensionPath, 'assets', 'config.js'); - - if (!fs.existsSync(manifestPath)) { - logger.error(this.siteName, '✗ manifest.json 不存在!扩展不完整'); - throw new Error('扩展文件不完整'); - } - - if (!fs.existsSync(configPath)) { - logger.error(this.siteName, '✗ assets/config.js 不存在!扩展不完整'); - throw new Error('扩展配置文件不存在'); - } - - logger.success(this.siteName, '✓ 扩展文件完整性检查通过'); - - // 关键修复:Windows上路径需要转换为正斜杠 - let normalizedPath = path.resolve(extensionPath); - if (process.platform === 'win32') { - // Windows: 将反斜杠转换为正斜杠(Chrome要求) - normalizedPath = normalizedPath.replace(/\\/g, '/'); - logger.info(this.siteName, `Windows平台:路径转换为正斜杠格式`); - } - - logger.info(this.siteName, `扩展路径: ${normalizedPath}`); - - // Windows特定:使用临时用户数据目录 - if (process.platform === 'win32') { - const tempUserDataDir = path.join(os.tmpdir(), 'chrome-capsolver-' + Date.now()); - launchOptions.userDataDir = tempUserDataDir; - logger.info(this.siteName, `临时用户数据目录: ${tempUserDataDir}`); - - // Windows必需参数 - launchOptions.args.push( - '--disable-features=RendererCodeIntegrity', - '--disable-blink-features=AutomationControlled' - ); - } - - launchOptions.args.push( - `--disable-extensions-except=${normalizedPath}`, - `--load-extension=${normalizedPath}` - ); - - logger.info(this.siteName, '✓ CapSolver 扩展配置完成'); - } else { - logger.warn(this.siteName, `⚠️ CapSolver 扩展未找到: ${extensionPath}`); - logger.warn(this.siteName, '请检查扩展目录是否存在'); + 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)}`); } - } else if (options.skipExtension) { - logger.info(this.siteName, '✓ 跳过扩展加载(避免干扰支付流程)'); - } - - this.browser = await puppeteer.launch(launchOptions); - - const pages = await this.browser.pages(); - this.page = pages[0] || await this.browser.newPage(); - - await this.page.setViewport(viewport); - await this.page.setExtraHTTPHeaders({ - 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' - }); - - logger.success(this.siteName, `✓ 浏览器启动成功 (${viewport.width}x${viewport.height})`); - - // API Key 应该已在 extensions/capsolver/assets/config.js 中配置 - if (launchOptions.args.some(arg => arg.includes('load-extension'))) { - logger.success(this.siteName, '✓ CapSolver 扩展将自动处理 Turnstile 验证'); - logger.info(this.siteName, '提示:请确保已在 extensions/capsolver/assets/config.js 中配置 API Key'); - } - - logger.info(this.siteName, '等待浏览器完全准备...'); - await this.human.randomDelay(2000, 3000); - - // 默认启用自动模式(如果配置了CapSolver) - if (this.capsolverKey) { - this.capsolverWorking = true; - logger.info(this.siteName, '✓ CapSolver自动模式已启用(如失败会降级到手动模式)'); + + // 获取 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'); + + // 提示:AdsPower 中需要手动安装 CapSolver 扩展 + if (this.capsolverKey) { + logger.info(this.siteName, ''); + logger.info(this.siteName, '💡 重要提示:'); + logger.info(this.siteName, ' 请在 AdsPower 配置中手动安装 CapSolver 扩展'); + logger.info(this.siteName, ' 扩展路径: extensions/capsolver'); + logger.info(this.siteName, ' 这样可以自动处理 Cloudflare Turnstile 验证'); + logger.info(this.siteName, ''); + } + + 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; } } @@ -316,91 +305,6 @@ class WindsurfRegister { } } - /** - * 保存会话数据(用于浏览器切换) - */ - async saveSession() { - logger.info(this.siteName, ' → 保存会话数据...'); - - this.sessionData = { - cookies: await this.page.cookies(), - localStorage: await this.page.evaluate(() => JSON.stringify(localStorage)), - sessionStorage: await this.page.evaluate(() => JSON.stringify(sessionStorage)), - url: this.page.url() - }; - - logger.success(this.siteName, ` → ✓ 会话数据已保存 (${this.sessionData.cookies.length} cookies)`); - } - - /** - * 恢复会话数据(用于浏览器切换) - */ - async restoreSession() { - if (!this.sessionData) { - throw new Error('没有可恢复的会话数据'); - } - - logger.info(this.siteName, ' → 恢复会话数据...'); - - // 1. 先访问域名(必须在同一域名下才能设置 cookies) - const url = new URL(this.sessionData.url); - await this.page.goto(url.origin, { waitUntil: 'networkidle2', timeout: 30000 }); - - // 2. 设置 cookies - await this.page.setCookie(...this.sessionData.cookies); - logger.info(this.siteName, ` → ✓ 已恢复 ${this.sessionData.cookies.length} 个 cookies`); - - // 3. 访问原始 URL - await this.page.goto(this.sessionData.url, { waitUntil: 'networkidle2', timeout: 30000 }); - - // 4. 恢复 localStorage 和 sessionStorage - await this.page.evaluate((ls, ss) => { - // 恢复 localStorage - const localData = JSON.parse(ls); - for (let key in localData) { - localStorage.setItem(key, localData[key]); - } - - // 恢复 sessionStorage - const sessionData = JSON.parse(ss); - for (let key in sessionData) { - sessionStorage.setItem(key, sessionData[key]); - } - }, this.sessionData.localStorage, this.sessionData.sessionStorage); - - // 5. 刷新页面以应用所有存储 - await this.page.reload({ waitUntil: 'networkidle2', timeout: 30000 }); - - logger.success(this.siteName, ' → ✓ 会话数据已恢复,登录状态保持'); - } - - /** - * 切换到干净的浏览器(无扩展) - */ - async switchBrowser() { - logger.info(this.siteName, ''); - logger.info(this.siteName, '┌─────────────────────────────────────────────────────┐'); - logger.info(this.siteName, '│ 🔄 切换到干净浏览器(避免扩展干扰支付) │'); - logger.info(this.siteName, '└─────────────────────────────────────────────────────┘'); - - // 1. 保存会话 - await this.saveSession(); - - // 2. 关闭当前浏览器 - logger.info(this.siteName, ' → 关闭带扩展的浏览器...'); - await this.browser.close(); - - // 3. 启动干净浏览器 - logger.info(this.siteName, ' → 启动干净浏览器(无扩展)...'); - await this.initBrowser({ skipExtension: true }); - - // 4. 恢复会话 - await this.restoreSession(); - - logger.success(this.siteName, '✓ 浏览器切换完成'); - logger.info(this.siteName, ''); - } - /** * 步骤1: 填写基本信息 */ @@ -1613,20 +1517,14 @@ class WindsurfRegister { this.currentStep = 5; logger.success(this.siteName, `步骤 5 完成 (共尝试 ${retryCount + 1} 次)`); - - // 保存会话数据(为步骤6的浏览器切换做准备) - await this.saveSession(); } /** - * 步骤6: 填写支付信息(在干净浏览器中完成) + * 步骤6: 填写支付信息 */ async step6_fillPayment() { logger.info(this.siteName, `[步骤 6/${this.getTotalSteps()}] 填写支付信息`); - // 切换到干净的浏览器(无扩展,避免干扰 Stripe) - await this.switchBrowser(); - try { // 等待页面加载 await this.human.readPage(3, 5);