GeminiBot commited on
Commit
c98a3e7
·
1 Parent(s): 5a61756

Robust env mocks and fallback strategy for challenge solver

Browse files
Files changed (1) hide show
  1. src/duckai.ts +48 -115
src/duckai.ts CHANGED
@@ -28,132 +28,41 @@ export class DuckAI {
28
  window.chrome = { runtime: {} };
29
 
30
  // Fix for 'Cannot read properties of null (reading 'contentDocument')'
31
- // Aggressive Patch: Modify the prototype directly
32
- Object.defineProperty(window.HTMLIFrameElement.prototype, 'contentDocument', {
33
- get: function() { return window.document; },
34
- configurable: true
35
- });
36
 
37
- Object.defineProperty(window.HTMLIFrameElement.prototype, 'contentWindow', {
38
- get: function() { return window; },
39
- configurable: true
40
- });
41
-
42
- // IMMORTAL DOM Strategy: Never return null
43
- const originalGetElementById = window.document.getElementById;
44
- window.document.getElementById = function(id: string) {
45
  const el = originalGetElementById.call(this, id);
46
  if (el) return el;
47
- // Return a dummy div if not found to prevent crash
48
- return window.document.createElement('div');
49
  };
50
 
51
- const originalQuerySelector = window.document.querySelector;
52
- window.document.querySelector = function(selector: string) {
53
  try {
54
  const el = originalQuerySelector.call(this, selector);
55
  if (el) return el;
56
  } catch(e) {}
57
- return window.document.createElement('div');
58
- };
59
-
60
- // Also keep the createElement hook just in case
61
- const originalCreateElement = window.document.createElement;
62
- window.document.createElement = function(tagName: string) {
63
- const element = originalCreateElement.call(this, tagName);
64
- if (tagName.toLowerCase() === 'iframe') {
65
- try {
66
- // Ensure properties are set on the instance as well
67
- Object.defineProperty(element, 'contentDocument', {
68
- get: () => window.document,
69
- configurable: true
70
- });
71
- Object.defineProperty(element, 'contentWindow', {
72
- get: () => window,
73
- configurable: true
74
- });
75
- } catch (e) {}
76
- }
77
- return element;
78
  };
79
 
80
- // Robust Canvas Mock
81
- const originalGetContext = window.HTMLCanvasElement.prototype.getContext;
82
- window.HTMLCanvasElement.prototype.getContext = function (type: string, options?: any) {
83
- // 1. Try real canvas if available
84
- try {
85
- const ctx = originalGetContext.call(this, type, options);
86
- if (ctx) return ctx;
87
- } catch (e) {}
88
-
89
- // 2. Fallback Mock for missing canvas
90
- return {
91
- canvas: this,
92
- fillRect: () => {},
93
- clearRect: () => {},
94
- getImageData: (x: number, y: number, w: number, h: number) => ({
95
- data: new Uint8ClampedArray(w * h * 4),
96
- width: w,
97
- height: h
98
- }),
99
- putImageData: () => {},
100
- createImageData: () => ({ data: new Uint8ClampedArray(4) }),
101
- setTransform: () => {},
102
- drawImage: () => {},
103
- save: () => {},
104
- restore: () => {},
105
- beginPath: () => {},
106
- moveTo: () => {},
107
- lineTo: () => {},
108
- closePath: () => {},
109
- stroke: () => {},
110
- translate: () => {},
111
- scale: () => {},
112
- rotate: () => {},
113
- arc: () => {},
114
- fill: () => {},
115
- measureText: () => ({ width: 0, actualBoundingBoxAscent: 0, actualBoundingBoxDescent: 0 }),
116
- transform: () => {},
117
- rect: () => {},
118
- clip: () => {},
119
- createLinearGradient: () => ({ addColorStop: () => {} }),
120
- createRadialGradient: () => ({ addColorStop: () => {} }),
121
- createPattern: () => ({}),
122
- bezierCurveTo: () => {},
123
- quadraticCurveTo: () => {},
124
- fillText: () => {},
125
- strokeText: () => {},
126
-
127
- // Properties
128
- globalAlpha: 1,
129
- globalCompositeOperation: 'source-over',
130
- fillStyle: '#000000',
131
- strokeStyle: '#000000',
132
- lineWidth: 1,
133
- lineCap: 'butt',
134
- lineJoin: 'miter',
135
- miterLimit: 10,
136
- shadowOffsetX: 0,
137
- shadowOffsetY: 0,
138
- shadowBlur: 0,
139
- shadowColor: 'rgba(0, 0, 0, 0)',
140
- font: '10px sans-serif',
141
- textAlign: 'start',
142
- textBaseline: 'alphabetic'
143
- };
144
- } as any;
145
-
146
- // Mock toDataURL to prevent failures if canvas is missing
147
- const originalToDataURL = window.HTMLCanvasElement.prototype.toDataURL;
148
- window.HTMLCanvasElement.prototype.toDataURL = function(type?: string, quality?: any) {
149
- try {
150
- const result = originalToDataURL.call(this, type, quality);
151
- // If JSDOM implementation returns "data:," it means failure/not implemented in some versions
152
- if (result && result !== "data:,") return result;
153
- } catch(e) {}
154
- // Return a 1x1 transparent pixel base64
155
- return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
156
- };
157
 
158
  dom.window.top.__DDG_BE_VERSION__ = 1;
159
  dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
@@ -171,6 +80,30 @@ export class DuckAI {
171
  return hash.digest('base64');
172
  });
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  return btoa(JSON.stringify(result));
175
  } catch (e: any) {
176
  throw new Error(`Challenge Solver Error: ${e.message}`);
 
28
  window.chrome = { runtime: {} };
29
 
30
  // Fix for 'Cannot read properties of null (reading 'contentDocument')'
31
+ // Immortal DOM + Environment Mocks
32
+ const mockWindow = dom.window as any;
 
 
 
33
 
34
+ // Self-reference fixes
35
+ mockWindow.self = mockWindow;
36
+ mockWindow.parent = mockWindow;
37
+ mockWindow.top = mockWindow;
38
+
39
+ // Immortal DOM Strategy
40
+ const originalGetElementById = mockWindow.document.getElementById;
41
+ mockWindow.document.getElementById = function(id: string) {
42
  const el = originalGetElementById.call(this, id);
43
  if (el) return el;
44
+ return mockWindow.document.createElement('div');
 
45
  };
46
 
47
+ const originalQuerySelector = mockWindow.document.querySelector;
48
+ mockWindow.document.querySelector = function(selector: string) {
49
  try {
50
  const el = originalQuerySelector.call(this, selector);
51
  if (el) return el;
52
  } catch(e) {}
53
+ return mockWindow.document.createElement('div');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  };
55
 
56
+ // Aggressive Patch for iframe contentDocument
57
+ Object.defineProperty(mockWindow.HTMLIFrameElement.prototype, 'contentDocument', {
58
+ get: function() { return mockWindow.document; },
59
+ configurable: true
60
+ });
61
+
62
+ Object.defineProperty(mockWindow.HTMLIFrameElement.prototype, 'contentWindow', {
63
+ get: function() { return mockWindow; },
64
+ configurable: true
65
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  dom.window.top.__DDG_BE_VERSION__ = 1;
68
  dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
 
80
  return hash.digest('base64');
81
  });
82
 
83
+ return btoa(JSON.stringify(result));
84
+ } catch (e: any) {
85
+ console.error(`[DuckAI] Challenge Solver Failed: ${e.message}`);
86
+ // Fallback: Return the original hash (sometimes works if challenge is optional or server is lenient)
87
+ // or return a dummy base64 json.
88
+ console.log("[DuckAI] Attempting fallback with original VQD...");
89
+ return vqdHash; // Try returning the VQD itself as a fallback
90
+ }
91
+ }
92
+ dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
93
+
94
+ const result = await dom.window.eval(jsScript) as any;
95
+
96
+ if (!result || !result.client_hashes) {
97
+ throw new Error("Invalid Challenge Response");
98
+ }
99
+
100
+ result.client_hashes[0] = ua;
101
+ result.client_hashes = result.client_hashes.map((t: string) => {
102
+ const hash = createHash('sha256');
103
+ hash.update(t);
104
+ return hash.digest('base64');
105
+ });
106
+
107
  return btoa(JSON.stringify(result));
108
  } catch (e: any) {
109
  throw new Error(`Challenge Solver Error: ${e.message}`);