GeminiBot commited on
Commit
adb9567
·
1 Parent(s): 387c337

Ultra-deep browser simulation with Canvas mock

Browse files
Files changed (2) hide show
  1. package.json +3 -2
  2. src/duckai.ts +43 -39
package.json CHANGED
@@ -4,6 +4,7 @@
4
  "main": "src/server.ts",
5
  "dependencies": {
6
  "jsdom": "^25.0.1",
7
- "user-agents": "^1.1.0"
 
8
  }
9
- }
 
4
  "main": "src/server.ts",
5
  "dependencies": {
6
  "jsdom": "^25.0.1",
7
+ "user-agents": "^1.1.0",
8
+ "canvas": "^2.11.2"
9
  }
10
+ }
src/duckai.ts CHANGED
@@ -7,35 +7,57 @@ export class DuckAI {
7
  try {
8
  const jsScript = Buffer.from(vqdHash, 'base64').toString('utf-8');
9
 
10
- // Создаем максимально детальную симуляцию браузера
11
- const dom = new JSDOM(`<!DOCTYPE html><html><head></head><body><div id="app"></div></body></html>`, {
12
  url: "https://duckduckgo.com/",
13
  referrer: "https://duckduckgo.com/",
14
- contentType: "text/html",
15
  runScripts: "dangerously",
16
  resources: "usable"
17
  });
18
 
19
- // Эмулируем Navigator и другие свойства
20
- Object.defineProperty(dom.window, 'navigator', {
21
- value: {
22
- userAgent: ua,
23
- platform: 'Win32',
24
- languages: ['en-US', 'en'],
25
- deviceMemory: 8,
26
- hardwareConcurrency: 8
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  });
29
 
30
- // Установка обязательных переменных DDG
31
  dom.window.top.__DDG_BE_VERSION__ = 1;
32
  dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
33
 
34
- // Выполняем скрипт
35
  const result = await dom.window.eval(jsScript) as any;
36
 
37
  if (!result || !result.client_hashes) {
38
- throw new Error("Challenge script returned invalid result");
39
  }
40
 
41
  result.client_hashes[0] = ua;
@@ -56,39 +78,23 @@ export class DuckAI {
56
  const headers: any = {
57
  "User-Agent": ua,
58
  "Accept": "text/event-stream",
59
- "Accept-Language": "en-US,en;q=0.9",
60
- "Referer": "https://duckduckgo.com/",
61
- "Origin": "https://duckduckgo.com",
62
  "x-vqd-accept": "1"
63
  };
64
 
65
  try {
66
- // 1. Получаем статус
67
  const statusRes = await fetch("https://duckduckgo.com/duckchat/v1/status?q=1", { headers });
68
- if (!statusRes.ok) throw new Error(`DDG Status Fail: ${statusRes.status}`);
69
-
70
  const hashHeader = statusRes.headers.get("x-vqd-hash-1");
71
- if (!hashHeader) throw new Error("Missing x-vqd-hash-1 header");
72
 
73
  const solvedVqd = await this.solveChallenge(hashHeader, ua);
74
 
75
- // 2. Делаем запрос в чат
76
- const chatRes = await fetch("https://duckduckgo.com/duckchat/v1/chat", {
77
  method: "POST",
78
- headers: {
79
- ...headers,
80
- "x-vqd-hash-1": solvedVqd,
81
- "Content-Type": "application/json"
82
- },
83
  body: JSON.stringify(request)
84
  });
85
 
86
- if (!chatRes.ok) {
87
- const errText = await chatRes.text();
88
- throw new Error(`DDG Chat Fail: ${chatRes.status} - ${errText.substring(0, 100)}`);
89
- }
90
-
91
- const text = await chatRes.text();
92
  let llmResponse = "";
93
  const lines = text.split("\n");
94
  for (const line of lines) {
@@ -99,11 +105,9 @@ export class DuckAI {
99
  } catch (e) {}
100
  }
101
  }
102
- return llmResponse.trim() || "⚠️ Пустой ответ от DDG.";
103
-
104
  } catch (error: any) {
105
- console.error("Scraping Detail:", error.message);
106
  return `⚠️ Ошибка бэкенда: ${error.message}`;
107
  }
108
  }
109
- }
 
7
  try {
8
  const jsScript = Buffer.from(vqdHash, 'base64').toString('utf-8');
9
 
10
+ const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`, {
 
11
  url: "https://duckduckgo.com/",
12
  referrer: "https://duckduckgo.com/",
 
13
  runScripts: "dangerously",
14
  resources: "usable"
15
  });
16
 
17
+ const window = dom.window as any;
18
+
19
+ // ГЛУБОКАЯ ЭМУЛЯЦИЯ
20
+ Object.defineProperties(window.navigator, {
21
+ userAgent: { value: ua },
22
+ platform: { value: 'Win32' },
23
+ webdriver: { value: false },
24
+ languages: { value: ['en-US', 'en'] }
25
+ });
26
+
27
+ window.screen = { width: 1920, height: 1080, availWidth: 1920, availHeight: 1080 };
28
+ window.chrome = { runtime: {} };
29
+
30
+ // Заглушка для Canvas (часто ищут её)
31
+ window.HTMLCanvasElement.prototype.getContext = () => ({
32
+ fillRect: () => {},
33
+ clearRect: () => {},
34
+ getImageData: () => ({ data: new Uint8ClampedArray(4) }),
35
+ putImageData: () => {},
36
+ createImageData: () => ({ data: new Uint8ClampedArray(4) }),
37
+ setTransform: () => {},
38
+ drawImage: () => {},
39
+ save: () => {},
40
+ restore: () => {},
41
+ beginPath: () => {},
42
+ moveTo: () => {},
43
+ lineTo: () => {},
44
+ closePath: () => {},
45
+ stroke: () => {},
46
+ translate: () => {},
47
+ scale: () => {},
48
+ rotate: () => {},
49
+ arc: () => {},
50
+ fill: () => {},
51
+ measureText: () => ({ width: 0 })
52
  });
53
 
 
54
  dom.window.top.__DDG_BE_VERSION__ = 1;
55
  dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
56
 
 
57
  const result = await dom.window.eval(jsScript) as any;
58
 
59
  if (!result || !result.client_hashes) {
60
+ throw new Error("Invalid Challenge Response");
61
  }
62
 
63
  result.client_hashes[0] = ua;
 
78
  const headers: any = {
79
  "User-Agent": ua,
80
  "Accept": "text/event-stream",
 
 
 
81
  "x-vqd-accept": "1"
82
  };
83
 
84
  try {
 
85
  const statusRes = await fetch("https://duckduckgo.com/duckchat/v1/status?q=1", { headers });
 
 
86
  const hashHeader = statusRes.headers.get("x-vqd-hash-1");
87
+ if (!hashHeader) throw new Error("Missing x-vqd-hash-1");
88
 
89
  const solvedVqd = await this.solveChallenge(hashHeader, ua);
90
 
91
+ const response = await fetch("https://duckduckgo.com/duckchat/v1/chat", {
 
92
  method: "POST",
93
+ headers: { ...headers, "x-vqd-hash-1": solvedVqd, "Content-Type": "application/json" },
 
 
 
 
94
  body: JSON.stringify(request)
95
  });
96
 
97
+ const text = await response.text();
 
 
 
 
 
98
  let llmResponse = "";
99
  const lines = text.split("\n");
100
  for (const line of lines) {
 
105
  } catch (e) {}
106
  }
107
  }
108
+ return llmResponse.trim() || "⚠️ Ошибка потока.";
 
109
  } catch (error: any) {
 
110
  return `⚠️ Ошибка бэкенда: ${error.message}`;
111
  }
112
  }
113
+ }