github-actions[bot] commited on
Commit
2496079
·
1 Parent(s): 7eb49d7

Update from GitHub Actions

Browse files
Files changed (1) hide show
  1. src/index.ts +134 -105
src/index.ts CHANGED
@@ -11,7 +11,10 @@ const app = new Hono()
11
  let browser: Browser | null = null
12
  let gensparkContext: BrowserContext | null = null
13
 
14
- 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';
 
 
 
15
  // 初始化浏览器
16
  async function initBrowser() {
17
  if (!browser) {
@@ -29,12 +32,12 @@ async function initBrowser() {
29
  }
30
 
31
  // 初始化genspark页面
32
- async function initGensparkPage(cookies?: any[]) {
33
  const browser = await initBrowser()
34
 
35
  if (!gensparkContext) {
36
  gensparkContext = await browser.newContext({
37
- userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
38
  viewport: { width: 1920, height: 1080 },
39
  deviceScaleFactor: 1,
40
  hasTouch: false,
@@ -48,12 +51,8 @@ async function initGensparkPage(cookies?: any[]) {
48
  acceptDownloads: true,
49
  })
50
  }
51
- if (cookies && cookies.length > 0) {
52
- await gensparkContext.clearCookies()
53
- await gensparkContext.addCookies(cookies);
54
- }
55
- const gensparkPage = await gensparkContext.newPage()
56
- return gensparkPage
57
  }
58
 
59
  // 验证响应头值是否有效
@@ -65,6 +64,29 @@ function isValidHeaderValue(value: string): boolean {
65
  return true;
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  // 处理请求转发
69
  async function handleRequest(url: string, method: string, headers: any, body?: any) {
70
  const browser = await initBrowser()
@@ -72,103 +94,108 @@ async function handleRequest(url: string, method: string, headers: any, body?: a
72
 
73
  try {
74
  // 只移除确实需要移除的请求头
75
- delete headers['host']
76
- delete headers['connection']
77
- delete headers['content-length']
78
- delete headers['accept-encoding']
79
- // 移除cf相关的头
80
- delete headers['cdn-loop']
81
- delete headers['cf-connecting-ip']
82
- delete headers['cf-connecting-o2o']
83
- delete headers['cf-ew-via']
84
- delete headers['cf-ray']
85
- delete headers['cf-visitor']
86
- delete headers['cf-worker']
87
-
88
- //移除其他无效的请求头
89
- delete headers['x-direct-url']
90
- delete headers['x-forwarded-for']
91
- delete headers['x-forwarded-port']
92
- delete headers['x-forwarded-proto']
93
-
94
- headers['user-agent'] = userAgent
95
-
96
- console.log('处理请求:', method, url, headers, body)
97
  // 设置请求拦截器
98
  await page.route('**/*', async (route: Route) => {
99
- const request = route.request()
100
  if (request.url() === url) {
101
  await route.continue({
102
  method: method,
103
  headers: {
104
  ...request.headers(),
105
- ...headers
106
  },
107
  postData: body
108
- })
109
  } else {
110
  // 允许其他资源加载
111
- await route.continue()
112
  }
113
- })
114
 
115
  // 配置页面请求选项
116
  const response = await page.goto(url, {
117
  waitUntil: 'domcontentloaded', // 改为更快的加载策略
118
- timeout: 600000
119
- })
120
 
121
  if (!response) {
122
- throw new Error('未收到响应')
123
  }
124
 
125
- // 等待页面加载完成
126
  await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {
127
- console.log('等待页面加载超时,继续处理')
128
- })
129
 
130
  // 获取响应数据
131
- const status = response.status()
132
- const responseHeaders = response.headers()
133
 
134
  // 确保移除可能导致解码问题的响应头
135
- delete responseHeaders['content-encoding']
136
- delete responseHeaders['content-length']
137
 
138
  // 过滤无效的响应头
139
- const validHeaders: Record<string, string> = {}
140
  for (const [key, value] of Object.entries(responseHeaders)) {
141
  if (isValidHeaderValue(value as string)) {
142
- validHeaders[key] = value as string
143
  } else {
144
- console.warn(`跳过无效的响应头: ${key}: ${value}`)
145
  }
146
  }
147
 
148
  // 直接获取响应体的二进制数据
149
- const responseBody = await response.body()
150
 
151
- console.log('请求处理完成:', status, responseBody.toString())
152
 
153
- await page.close()
154
 
155
  return {
156
  status,
157
  headers: validHeaders,
158
  body: responseBody
159
- }
160
  } catch (error: any) {
161
- await page.close()
162
- console.error('请求处理错误:', error)
163
- throw new Error(`请求失败: ${error.message}`)
164
  }
165
  }
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
  // 添加静态文件服务
169
  app.use('/public/*', serveStatic({ root: './' }))
170
 
171
- // 修改点 1: 处理根路由直接返回 index.html 内容,而不是重定向
172
  app.get('/', async (c) => {
173
  try {
174
  const htmlContent = fs.readFileSync('./index.html', 'utf-8')
@@ -179,65 +206,67 @@ app.get('/', async (c) => {
179
  }
180
  })
181
 
182
- // 修改点 2: 添加 /genspark 路由来获取reCAPTCHA令牌
183
  app.get('/genspark', async (c) => {
184
-
185
- const headers = Object.fromEntries(c.req.raw.headers)
186
- // Get the cookie string from headers
187
  const cookieString = headers.cookie || '';
188
- // Parse cookies into an array of objects with name and value properties
189
- const cookies = cookieString.split(';').map(cookie => {
190
- const [name, value] = cookie.trim().split('=');
191
- return { name, value, domain: 'www.genspark.ai', path: '/' };
192
- }).filter(cookie => cookie.name && cookie.value);
193
 
194
- const gensparkPage = await initGensparkPage(cookies)
195
  try {
196
- await gensparkPage.waitForTimeout(1000)
197
- //刷新页面以确保获取新令牌
198
- await gensparkPage.goto('https://www.genspark.ai/agents?type=moa_chat', {
 
 
 
 
 
 
 
 
 
199
  waitUntil: 'networkidle',
200
- timeout: 3600000
201
- })
202
- await gensparkPage.waitForTimeout(1000)
203
- // 执行脚本获取令牌
204
- const token = await gensparkPage.evaluate(() => {
205
- return new Promise((resolve, reject) => {
206
- // @ts-ignore
207
- window.grecaptcha.ready(function () {
208
- // @ts-ignore
209
- grecaptcha.execute(
210
- "6Leq7KYqAAAAAGdd1NaUBJF9dHTPAKP7DcnaRc66",
211
- { action: 'copilot' },
212
- ).then(function (token: string) {
213
- resolve(token)
214
- }).catch(function (error: Error) {
215
- reject(error)
216
- });
217
- });
218
 
219
- // 设置超时
220
- setTimeout(() => reject(new Error("获取令牌超时")), 10000);
221
- });
222
- }).catch(error => {
223
- return c.json({ code: 500, message: '获取令牌失败' })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  });
 
 
 
 
225
 
226
- return c.json({ code: 200, message: '获取令牌成功', token: token })
227
- }
228
- catch (error) {
229
- console.error('获取令牌失败:', error)
230
- if (gensparkContext) {
231
  await gensparkContext.close().catch(() => { });
232
  gensparkContext = null;
233
  }
234
  }
235
- finally {
236
- await gensparkPage.close().catch(() => { });
237
- }
238
-
239
- return c.json({ code: 500, message: '获取令牌失败' })
240
- })
241
 
242
  // 处理所有 HTTP 方法
243
  app.all('*', async (c) => {
@@ -293,7 +322,7 @@ process.on('SIGINT', cleanup)
293
  process.on('SIGTERM', cleanup)
294
 
295
  const port = Number(process.env.PORT || '7860');
296
- console.log(`Server is running on port http://localhost:${port}`)
297
 
298
  // 启动服务器
299
  serve({
 
11
  let browser: Browser | null = null
12
  let gensparkContext: BrowserContext | null = null
13
 
14
+ const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
15
+ const RECAPTCHA_SITE_KEY = "6Leq7KYqAAAAAGdd1NaUBJF9dHTPAKP7DcnaRc66";
16
+ const GENSPARK_URL = 'https://www.genspark.ai/agents?type=moa_chat';
17
+
18
  // 初始化浏览器
19
  async function initBrowser() {
20
  if (!browser) {
 
32
  }
33
 
34
  // 初始化genspark页面
35
+ async function initGensparkContext() {
36
  const browser = await initBrowser()
37
 
38
  if (!gensparkContext) {
39
  gensparkContext = await browser.newContext({
40
+ userAgent,
41
  viewport: { width: 1920, height: 1080 },
42
  deviceScaleFactor: 1,
43
  hasTouch: false,
 
51
  acceptDownloads: true,
52
  })
53
  }
54
+
55
+ return gensparkContext
 
 
 
 
56
  }
57
 
58
  // 验证响应头值是否有效
 
64
  return true;
65
  }
66
 
67
+ // 获取reCAPTCHA令牌
68
+ async function getReCaptchaToken(page: Page): Promise<string> {
69
+ return page.evaluate(() => {
70
+ return new Promise<string>((resolve, reject) => {
71
+ // @ts-ignore
72
+ window.grecaptcha.ready(function () {
73
+ // @ts-ignore
74
+ grecaptcha.execute(
75
+ "6Leq7KYqAAAAAGdd1NaUBJF9dHTPAKP7DcnaRc66",
76
+ { action: 'copilot' },
77
+ ).then(function (token: string) {
78
+ resolve(token)
79
+ }).catch(function (error: Error) {
80
+ reject(error)
81
+ });
82
+ });
83
+
84
+ // 设置超时
85
+ setTimeout(() => reject(new Error("获取令牌超时")), 10000);
86
+ });
87
+ });
88
+ }
89
+
90
  // 处理请求转发
91
  async function handleRequest(url: string, method: string, headers: any, body?: any) {
92
  const browser = await initBrowser()
 
94
 
95
  try {
96
  // 只移除确实需要移除的请求头
97
+ const filteredHeaders = { ...headers };
98
+ const headersToRemove = [
99
+ 'host', 'connection', 'content-length', 'accept-encoding',
100
+ 'cdn-loop', 'cf-connecting-ip', 'cf-connecting-o2o', 'cf-ew-via',
101
+ 'cf-ray', 'cf-visitor', 'cf-worker', 'x-direct-url',
102
+ 'x-forwarded-for', 'x-forwarded-port', 'x-forwarded-proto'
103
+ ];
104
+
105
+ headersToRemove.forEach(header => delete filteredHeaders[header]);
106
+ filteredHeaders['user-agent'] = userAgent;
107
+
108
+ console.log('处理请求:', method, url, filteredHeaders, body);
109
+
 
 
 
 
 
 
 
 
 
110
  // 设置请求拦截器
111
  await page.route('**/*', async (route: Route) => {
112
+ const request = route.request();
113
  if (request.url() === url) {
114
  await route.continue({
115
  method: method,
116
  headers: {
117
  ...request.headers(),
118
+ ...filteredHeaders
119
  },
120
  postData: body
121
+ });
122
  } else {
123
  // 允许其他资源加载
124
+ await route.continue();
125
  }
126
+ });
127
 
128
  // 配置页面请求选项
129
  const response = await page.goto(url, {
130
  waitUntil: 'domcontentloaded', // 改为更快的加载策略
131
+ timeout: 600000 // 60秒超时,更合理的值
132
+ });
133
 
134
  if (!response) {
135
+ throw new Error('未收到响应');
136
  }
137
 
138
+ // 等待页面加载完成,使用更短的超时时间
139
  await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {
140
+ console.log('等待页面加载超时,继续处理');
141
+ });
142
 
143
  // 获取响应数据
144
+ const status = response.status();
145
+ const responseHeaders = response.headers();
146
 
147
  // 确保移除可能导致解码问题的响应头
148
+ delete responseHeaders['content-encoding'];
149
+ delete responseHeaders['content-length'];
150
 
151
  // 过滤无效的响应头
152
+ const validHeaders: Record<string, string> = {};
153
  for (const [key, value] of Object.entries(responseHeaders)) {
154
  if (isValidHeaderValue(value as string)) {
155
+ validHeaders[key] = value as string;
156
  } else {
157
+ console.warn(`跳过无效的响应头: ${key}: ${value}`);
158
  }
159
  }
160
 
161
  // 直接获取响应体的二进制数据
162
+ const responseBody = await response.body();
163
 
164
+ console.log('请求处理完成:', status);
165
 
166
+ await page.close();
167
 
168
  return {
169
  status,
170
  headers: validHeaders,
171
  body: responseBody
172
+ };
173
  } catch (error: any) {
174
+ await page.close();
175
+ console.error('请求处理错误:', error);
176
+ throw new Error(`请求失败: ${error.message}`);
177
  }
178
  }
179
 
180
+ // 解析cookie字符串为对象数组
181
+ function parseCookies(cookieString: string) {
182
+ return cookieString.split(';')
183
+ .map(cookie => {
184
+ const [name, value] = cookie.trim().split('=');
185
+ return {
186
+ name,
187
+ value,
188
+ domain: 'www.genspark.ai',
189
+ path: '/'
190
+ };
191
+ })
192
+ .filter(cookie => cookie.name && cookie.value);
193
+ }
194
 
195
  // 添加静态文件服务
196
  app.use('/public/*', serveStatic({ root: './' }))
197
 
198
+ // 处理根路由直接返回 index.html 内容,而不是重定向
199
  app.get('/', async (c) => {
200
  try {
201
  const htmlContent = fs.readFileSync('./index.html', 'utf-8')
 
206
  }
207
  })
208
 
209
+ // 获取reCAPTCHA令牌的路由
210
  app.get('/genspark', async (c) => {
211
+ const headers = Object.fromEntries(c.req.raw.headers);
 
 
212
  const cookieString = headers.cookie || '';
213
+ const cookies = parseCookies(cookieString);
214
+
215
+ let page = null;
216
+ let error = null;
 
217
 
 
218
  try {
219
+ gensparkContext = await initGensparkContext();
220
+
221
+ // 设置cookies
222
+ if (cookies.length > 0) {
223
+ await gensparkContext.clearCookies();
224
+ await gensparkContext.addCookies(cookies);
225
+ }
226
+
227
+ page = await gensparkContext.newPage();
228
+
229
+ // 导航到Genspark页面
230
+ await page.goto(GENSPARK_URL, {
231
  waitUntil: 'networkidle',
232
+ timeout: 30000 // 30秒超时,更合理
233
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
 
235
+ // 等待页面加载完成
236
+ await page.waitForTimeout(1000);
237
+
238
+ // 获取reCAPTCHA令牌
239
+ const token = await getReCaptchaToken(page);
240
+
241
+ if (!token) {
242
+ return c.json({ code: 500, message: '获取令牌失败:令牌为空' });
243
+ }
244
+
245
+ return c.json({
246
+ code: 200,
247
+ message: '获取令牌成功',
248
+ token: token
249
+ });
250
+ } catch (e) {
251
+ error = e
252
+ console.error('获取令牌失败:', e);
253
+ return c.json({
254
+ code: 500,
255
+ message: `获取令牌失败: ${e instanceof Error ? e.message : '未知错误'}`
256
  });
257
+ } finally {
258
+ if (page) {
259
+ await page.close().catch(() => { });
260
+ }
261
 
262
+ // 不要在每次请求后关闭上下文,保持它以便重用
263
+ // 只有在出错时才重置上下文
264
+ if (error && gensparkContext) {
 
 
265
  await gensparkContext.close().catch(() => { });
266
  gensparkContext = null;
267
  }
268
  }
269
+ });
 
 
 
 
 
270
 
271
  // 处理所有 HTTP 方法
272
  app.all('*', async (c) => {
 
322
  process.on('SIGTERM', cleanup)
323
 
324
  const port = Number(process.env.PORT || '7860');
325
+ console.log(`Server is running on port http://localhost:${port}`)
326
 
327
  // 启动服务器
328
  serve({