import { Hono } from 'hono' import { serve } from '@hono/node-server' import { serveStatic } from '@hono/node-server/serve-static' import { chromium, type Browser, type BrowserContext, type Route, type Page } from 'playwright' import process from 'process' import fs from 'fs' const app = new Hono() // 浏览器实例 let browser: Browser | null = null let gensparkContext: BrowserContext | null = null // 为genspark保存的page实例 let gensparkPage: Page | null = null const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'; // 初始化浏览器 async function initBrowser() { if (!browser) { browser = await chromium.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-blink-features=AutomationControlled', '--disable-features=IsolateOrigins,site-per-process', '--disable-web-security', '--disable-site-isolation-trials', '--ignore-certificate-errors', '--window-size=1920,1080', '--start-maximized', '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36' ], executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, // 使用系统 Chromium }) } return browser } // 初始化genspark页面 async function initGensparkPage(cookies?: any[]) { const browser = await initBrowser() if (!gensparkContext) { gensparkContext = await browser.newContext({ viewport: { width: 1920, height: 1080 }, deviceScaleFactor: 1, hasTouch: false, javaScriptEnabled: true, locale: 'en-US', timezoneId: 'America/New_York', geolocation: { longitude: -74.006, latitude: 40.7128 }, // New York coordinates permissions: ['geolocation'], colorScheme: 'light', reducedMotion: 'no-preference', forcedColors: 'none', acceptDownloads: true, ignoreHTTPSErrors: true, bypassCSP: true, extraHTTPHeaders: { 'Accept-Language': 'en-US,en;q=0.9', 'DNT': '1', 'Upgrade-Insecure-Requests': '1', } }) } if (cookies && cookies.length > 0) { await gensparkContext.addCookies(cookies); } if (!gensparkPage) { gensparkPage = await gensparkContext.newPage() // 首次加载页面 await gensparkPage.goto('https://www.genspark.ai', { waitUntil: 'networkidle', timeout: 60000 }) // Override specific browser properties to avoid detection await gensparkPage.addInitScript(() => { // Override the navigator properties Object.defineProperty(navigator, 'webdriver', { get: () => false }); Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); // Add fake web audio and canvas fingerprints const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData; CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) { const imageData = originalGetImageData.call(this, x, y, w, h); // Add some noise to the canvas data for (let i = 0; i < imageData.data.length; i += 4) { imageData.data[i] = imageData.data[i] + Math.floor(Math.random() * 5); imageData.data[i+1] = imageData.data[i+1] + Math.floor(Math.random() * 5); imageData.data[i+2] = imageData.data[i+2] + Math.floor(Math.random() * 5); } return imageData; }; // Override Chrome-specific properties window.chrome = { runtime: {}, loadTimes: function() {}, csi: function() {}, app: {} }; // Spoof notification permissions if (navigator.permissions) { const originalQuery = navigator.permissions.query; navigator.permissions.query = function(parameters) { if (parameters.name === 'notifications') { return Promise.resolve({ state: Notification.permission }); } return originalQuery.call(this, parameters); }; } }); // Simulate human-like behavior await gensparkPage.addInitScript(() => { // Add random mouse movements let lastMove = Date.now(); document.addEventListener('mousemove', function() { lastMove = Date.now(); }, true); // Simulate scroll behavior window.addEventListener('scroll', function() { // Random scroll speed const scrollSpeed = Math.floor(Math.random() * 10) + 5; const scrollAmount = Math.floor(Math.random() * 100); setTimeout(() => { window.scrollBy(0, scrollAmount); }, scrollSpeed); }, true); }); console.log('GenSpark页面已初始化') } return gensparkPage } // 验证响应头值是否有效 function isValidHeaderValue(value: string): boolean { // 检查值是否为空或包含无效字符 if (!value || typeof value !== 'string') return false; // 检查是否包含换行符或回车符 if (/[\r\n]/.test(value)) return false; return true; } // 处理请求转发 async function handleRequest(url: string, method: string, headers: any, body?: any) { const browser = await initBrowser() const page = await browser.newPage() try { // 只移除确实需要移除的请求头 delete headers['host'] delete headers['connection'] delete headers['content-length'] delete headers['accept-encoding'] // 移除cf相关的头 delete headers['cdn-loop'] delete headers['cf-connecting-ip'] delete headers['cf-connecting-o2o'] delete headers['cf-ew-via'] delete headers['cf-ray'] delete headers['cf-visitor'] delete headers['cf-worker'] //移除其他无效的请求头 delete headers['x-direct-url'] delete headers['x-forwarded-for'] delete headers['x-forwarded-port'] delete headers['x-forwarded-proto'] headers['user-agent'] = userAgent console.log('处理请求:', method, url, headers, body) // 设置请求拦截器 await page.route('**/*', async (route: Route) => { const request = route.request() if (request.url() === url) { await route.continue({ method: method, headers: { ...request.headers(), ...headers }, postData: body }) } else { // 允许其他资源加载 await route.continue() } }) // 配置页面请求选项 const response = await page.goto(url, { waitUntil: 'domcontentloaded', // 改为更快的加载策略 timeout: 600000 }) if (!response) { throw new Error('未收到响应') } // 等待页面加载完成 await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => { console.log('等待页面加载超时,继续处理') }) // 获取响应数据 const status = response.status() const responseHeaders = response.headers() // 确保移除可能导致解码问题的响应头 delete responseHeaders['content-encoding'] delete responseHeaders['content-length'] // 过滤无效的响应头 const validHeaders: Record = {} for (const [key, value] of Object.entries(responseHeaders)) { if (isValidHeaderValue(value as string)) { validHeaders[key] = value as string } else { console.warn(`跳过无效的响应头: ${key}: ${value}`) } } // 直接获取响应体的二进制数据 const responseBody = await response.body() console.log('请求处理完成:', status, responseBody.toString()) await page.close() return { status, headers: validHeaders, body: responseBody } } catch (error: any) { await page.close() console.error('请求处理错误:', error) throw new Error(`请求失败: ${error.message}`) } } // 添加静态文件服务 app.use('/public/*', serveStatic({ root: './' })) // 修改点 1: 处理根路由直接返回 index.html 内容,而不是重定向 app.get('/', async (c) => { try { const htmlContent = fs.readFileSync('./index.html', 'utf-8') return c.html(htmlContent) } catch (error) { console.error('读取index.html失败:', error) return c.text('无法读取主页', 500) } }) // 修改点 2: 添加 /genspark 路由来获取reCAPTCHA令牌 app.get('/genspark', async (c) => { try { const headers = Object.fromEntries(c.req.raw.headers) // Get the cookie string from headers const cookieString = headers.cookie || ''; // Parse cookies into an array of objects with name and value properties const cookies = cookieString.split(';').map(cookie => { const [name, value] = cookie.trim().split('='); return { name, value, domain: 'www.genspark.ai', path: '/' }; }).filter(cookie => cookie.name && cookie.value); const gensparkPage = await initGensparkPage(cookies) //刷新页面以确保获取新令牌 await gensparkPage.goto('https://www.genspark.ai/agents?type=moa_chat', { waitUntil: 'networkidle', timeout: 3600000 }) // 执行脚本获取令牌 const token = await gensparkPage.evaluate(() => { return new Promise((resolve, reject) => { // @ts-ignore window.grecaptcha.ready(function () { // @ts-ignore grecaptcha.execute( "6Leq7KYqAAAAAGdd1NaUBJF9dHTPAKP7DcnaRc66", { action: 'copilot' }, ).then(function (token: string) { resolve(token) }).catch(function (error: Error) { reject(error) }); }); // 设置超时 setTimeout(() => reject(new Error("获取令牌超时")), 10000); }); }).catch(error => { return c.json({ code: 500, message: '获取令牌失败' }) }); return c.json({ code: 200, message: '获取令牌成功', token: token }) } catch (error) { console.error('获取令牌失败:', error) if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } return c.json({ code: 500, message: '获取令牌失败' }) } }) // 处理所有 HTTP 方法 app.all('*', async (c) => { const url = c.req.query('url') if (!url) { return c.text('Missing url parameter', 400) } try { const method = c.req.method const headers = Object.fromEntries(c.req.raw.headers) const body = method !== 'GET' ? await c.req.text() : undefined const result = await handleRequest(url, method, headers, body) // 创建标准响应 const response = new Response(result.body, { status: result.status, headers: new Headers({ ...result.headers, 'content-encoding': 'identity' // 显式设置不使用压缩 }) }) return response } catch (error) { console.error('Error:', error) return new Response('Internal Server Error', { status: 500, headers: new Headers({ 'content-type': 'text/plain' }) }) } }) // 清理函数 async function cleanup() { if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } if (browser) { await browser.close().catch(() => { }); browser = null; } process.exit(0) } // 监听进程退出信号 process.on('SIGINT', cleanup) process.on('SIGTERM', cleanup) initGensparkPage().catch(async () => { if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } }) const port = Number(process.env.PORT || '7860'); console.log(`Server is running on port http://localhost:${port}`) // 启动服务器 serve({ fetch: app.fetch, port: port })