granclaw 0.0.1-beta.22 → 0.0.1-beta.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -217,4 +217,52 @@
|
|
|
217
217
|
return result.replace(/at .*puppeteer_evaluation_script.*\n?/g, '');
|
|
218
218
|
};
|
|
219
219
|
});
|
|
220
|
+
|
|
221
|
+
// ── 10. navigator.userAgent — strip HeadlessChrome ─────────────────────
|
|
222
|
+
// Headless Chrome embeds "HeadlessChrome/" in the UA string instead of
|
|
223
|
+
// "Chrome/". Strip it here so JS-readable UA matches a real user session.
|
|
224
|
+
// Network-level UA is handled at launch via --user-agent; this covers
|
|
225
|
+
// all runtime reads (navigator.userAgent, performance.getEntriesByType, etc.)
|
|
226
|
+
safe(() => {
|
|
227
|
+
const realUA = navigator.userAgent.replace('HeadlessChrome/', 'Chrome/');
|
|
228
|
+
Object.defineProperty(Navigator.prototype, 'userAgent', {
|
|
229
|
+
get: () => realUA,
|
|
230
|
+
configurable: true,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ── 11. navigator.userAgentData — Client Hints API ─────────────────────
|
|
235
|
+
// The modern Client Hints UA API also leaks "Headless" in its brand list.
|
|
236
|
+
// Patch brands to strip the "Headless" prefix so sites using getHighEntropyValues
|
|
237
|
+
// or brands directly see a normal Chrome brand string.
|
|
238
|
+
safe(() => {
|
|
239
|
+
if (typeof navigator.userAgentData === 'undefined') return;
|
|
240
|
+
const uad = navigator.userAgentData;
|
|
241
|
+
const brands = (uad.brands || []).map((b) => ({
|
|
242
|
+
brand: b.brand.replace(/^Headless/i, ''),
|
|
243
|
+
version: b.version,
|
|
244
|
+
}));
|
|
245
|
+
Object.defineProperty(Navigator.prototype, 'userAgentData', {
|
|
246
|
+
get: () => new Proxy(uad, {
|
|
247
|
+
get(target, prop) {
|
|
248
|
+
if (prop === 'brands') return brands;
|
|
249
|
+
if (prop === 'mobile') return false;
|
|
250
|
+
const val = Reflect.get(target, prop);
|
|
251
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
configurable: true,
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// ── 12. navigator.deviceMemory ──────────────────────────────────────────
|
|
259
|
+
// Headless Chrome may expose the host's actual RAM or a low default.
|
|
260
|
+
// Spoofing 8 GB matches the most common desktop tier and avoids leaking
|
|
261
|
+
// the container/VM memory footprint to fingerprinting scripts.
|
|
262
|
+
safe(() => {
|
|
263
|
+
Object.defineProperty(Navigator.prototype, 'deviceMemory', {
|
|
264
|
+
get: () => 8,
|
|
265
|
+
configurable: true,
|
|
266
|
+
});
|
|
267
|
+
});
|
|
220
268
|
})();
|
|
@@ -64,7 +64,10 @@ let cachedChromePath;
|
|
|
64
64
|
function detectChromePath() {
|
|
65
65
|
if (cachedChromePath !== undefined)
|
|
66
66
|
return cachedChromePath;
|
|
67
|
-
|
|
67
|
+
// GRANCLAW_CHROME_PATH takes priority; fall back to the agent-browser env
|
|
68
|
+
// var so Docker containers (which set AGENT_BROWSER_CHROME_PATH=/usr/bin/chromium)
|
|
69
|
+
// automatically point stealth at the same binary agent-browser will use.
|
|
70
|
+
const override = process.env.GRANCLAW_CHROME_PATH || process.env.AGENT_BROWSER_CHROME_PATH;
|
|
68
71
|
if (override && fs_1.default.existsSync(override)) {
|
|
69
72
|
cachedChromePath = override;
|
|
70
73
|
return override;
|
|
@@ -113,12 +116,9 @@ function detectChromePath() {
|
|
|
113
116
|
* const argv = ['--session', agentId, ...stealthArgv(), 'open', url];
|
|
114
117
|
*/
|
|
115
118
|
function stealthArgv() {
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
// Set GRANCLAW_STEALTH_ENABLED=1 to opt back in.
|
|
120
|
-
if (process.env.GRANCLAW_STEALTH_ENABLED !== '1')
|
|
121
|
-
return [];
|
|
119
|
+
// Re-enabled 2026-04-14: UA/deviceMemory patches added, AGENT_BROWSER_CHROME_PATH
|
|
120
|
+
// wired up so Docker containers automatically use the in-place Chromium.
|
|
121
|
+
// Set GRANCLAW_STEALTH_DISABLED=1 to opt out entirely.
|
|
122
122
|
if (process.env.GRANCLAW_STEALTH_DISABLED === '1')
|
|
123
123
|
return [];
|
|
124
124
|
const argv = [];
|