GeminiBot
commited on
Commit
·
c98a3e7
1
Parent(s):
5a61756
Robust env mocks and fallback strategy for challenge solver
Browse files- 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 |
-
//
|
| 32 |
-
|
| 33 |
-
get: function() { return window.document; },
|
| 34 |
-
configurable: true
|
| 35 |
-
});
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
//
|
| 43 |
-
const originalGetElementById =
|
| 44 |
-
|
| 45 |
const el = originalGetElementById.call(this, id);
|
| 46 |
if (el) return el;
|
| 47 |
-
|
| 48 |
-
return window.document.createElement('div');
|
| 49 |
};
|
| 50 |
|
| 51 |
-
const originalQuerySelector =
|
| 52 |
-
|
| 53 |
try {
|
| 54 |
const el = originalQuerySelector.call(this, selector);
|
| 55 |
if (el) return el;
|
| 56 |
} catch(e) {}
|
| 57 |
-
return
|
| 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 |
-
//
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 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}`);
|