cbrowser 16.17.0 → 17.0.0
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.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server-remote.d.ts.map +1 -1
- package/dist/mcp-server-remote.js +8 -336
- package/dist/mcp-server-remote.js.map +1 -1
- package/dist/personas.d.ts +7 -0
- package/dist/personas.d.ts.map +1 -1
- package/dist/personas.js +31 -6
- package/dist/personas.js.map +1 -1
- package/dist/values/index.d.ts +1 -1
- package/dist/values/index.d.ts.map +1 -1
- package/dist/values/index.js +1 -1
- package/dist/values/index.js.map +1 -1
- package/dist/values/persona-values.d.ts +7 -0
- package/dist/values/persona-values.d.ts.map +1 -1
- package/dist/values/persona-values.js +20 -0
- package/dist/values/persona-values.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export { CBrowser } from "./browser.js";
|
|
|
27
27
|
export { getDefaultConfig, getPaths, ensureDirectories, mergeConfig } from "./config.js";
|
|
28
28
|
export type { CBrowserConfig, CBrowserPaths, BrowserType } from "./config.js";
|
|
29
29
|
export * from "./types.js";
|
|
30
|
-
export { BUILTIN_PERSONAS } from "./personas.js";
|
|
30
|
+
export { BUILTIN_PERSONAS, registerPersonas } from "./personas.js";
|
|
31
31
|
export * from "./trait-reference.js";
|
|
32
32
|
export { startMcpServer, createMcpServer, connectMcpServer } from "./mcp-server.js";
|
|
33
33
|
export { startDaemon, stopDaemon, getDaemonStatus, isDaemonRunning, sendToDaemon, runDaemonServer } from "./daemon.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9E,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9E,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGnE,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAIvH,cAAc,mBAAmB,CAAC;AAGlC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,wBAAwB,CAAC;AAGvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG1E,cAAc,oBAAoB,CAAC;AAInC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,4BAA4B,CAAC;AAI3C,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
export { CBrowser } from "./browser.js";
|
|
27
27
|
export { getDefaultConfig, getPaths, ensureDirectories, mergeConfig } from "./config.js";
|
|
28
28
|
export * from "./types.js";
|
|
29
|
-
export { BUILTIN_PERSONAS } from "./personas.js";
|
|
29
|
+
export { BUILTIN_PERSONAS, registerPersonas } from "./personas.js";
|
|
30
30
|
// Trait Reference (v15.0.0) - Cognitive trait definitions and guidelines
|
|
31
31
|
export * from "./trait-reference.js";
|
|
32
32
|
export { startMcpServer, createMcpServer, connectMcpServer } from "./mcp-server.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzF,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzF,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnE,yEAAyE;AACzE,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvH,2BAA2B;AAC3B,wBAAwB;AACxB,cAAc,mBAAmB,CAAC;AAElC,iBAAiB;AACjB,cAAc,oBAAoB,CAAC;AAEnC,kBAAkB;AAClB,cAAc,qBAAqB,CAAC;AAEpC,qBAAqB;AACrB,cAAc,wBAAwB,CAAC;AAEvC,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE1E,2BAA2B;AAC3B,cAAc,oBAAoB,CAAC;AAEnC,6CAA6C;AAC7C,uDAAuD;AACvD,cAAc,oBAAoB,CAAC;AAEnC,sEAAsE;AACtE,cAAc,4BAA4B,CAAC;AAE3C,2EAA2E;AAC3E,oEAAoE;AACpE,cAAc,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server-remote.d.ts","sourceRoot":"","sources":["../src/mcp-server-remote.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AA6BH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-server-remote.d.ts","sourceRoot":"","sources":["../src/mcp-server-remote.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AA6BH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgwFpE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoM1F"}
|
|
@@ -60,13 +60,11 @@ import { capturePerformanceBaseline, detectPerformanceRegression, listPerformanc
|
|
|
60
60
|
import { getPersonaValues, PERSONA_VALUE_PROFILES, rankInfluencePatternsForProfile, INFLUENCE_PATTERNS, } from "./values/index.js";
|
|
61
61
|
// Version from package.json - single source of truth
|
|
62
62
|
import { VERSION } from "./version.js";
|
|
63
|
-
// Stealth/Enterprise loader (v16.2.0)
|
|
64
|
-
import { getEnforcer, isEnterpriseAvailable, getEnterpriseVersion, } from "./stealth/index.js";
|
|
65
63
|
// Shared browser instance
|
|
66
64
|
let browser = null;
|
|
67
65
|
// Stealth state (enterprise integration)
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const stealthEnforcer = null;
|
|
67
|
+
const stealthConfig = null;
|
|
70
68
|
async function getBrowser() {
|
|
71
69
|
if (!browser) {
|
|
72
70
|
// Pass proxy configuration from stealth config if available
|
|
@@ -307,47 +305,7 @@ function configureMcpTools(server) {
|
|
|
307
305
|
],
|
|
308
306
|
};
|
|
309
307
|
});
|
|
310
|
-
|
|
311
|
-
const b = await getBrowser();
|
|
312
|
-
const result = await b.detectCloudflareChallenge();
|
|
313
|
-
return {
|
|
314
|
-
content: [
|
|
315
|
-
{
|
|
316
|
-
type: "text",
|
|
317
|
-
text: JSON.stringify({
|
|
318
|
-
detected: result.detected,
|
|
319
|
-
challenge_type: result.type,
|
|
320
|
-
evidence: result.evidence,
|
|
321
|
-
message: result.detected
|
|
322
|
-
? `Cloudflare ${result.type} challenge detected. Use cloudflare_wait to wait for resolution.`
|
|
323
|
-
: "No Cloudflare challenge detected on current page.",
|
|
324
|
-
}, null, 2),
|
|
325
|
-
},
|
|
326
|
-
],
|
|
327
|
-
};
|
|
328
|
-
});
|
|
329
|
-
server.tool("cloudflare_wait", "Wait for a Cloudflare challenge to resolve. Use this after navigating to a page that shows a Cloudflare protection page. The tool will poll until the challenge completes or times out.", {
|
|
330
|
-
timeout: z.number().optional().describe("Maximum time to wait in milliseconds (default: 30000)"),
|
|
331
|
-
}, async ({ timeout }) => {
|
|
332
|
-
const b = await getBrowser();
|
|
333
|
-
const result = await b.waitForCloudflareResolution(timeout ?? 30000);
|
|
334
|
-
const screenshot = await b.screenshot();
|
|
335
|
-
return {
|
|
336
|
-
content: [
|
|
337
|
-
{
|
|
338
|
-
type: "text",
|
|
339
|
-
text: JSON.stringify({
|
|
340
|
-
resolved: result.resolved,
|
|
341
|
-
original_url: result.originalUrl,
|
|
342
|
-
final_url: result.finalUrl,
|
|
343
|
-
wait_time_ms: result.waitTime,
|
|
344
|
-
message: result.message,
|
|
345
|
-
screenshot,
|
|
346
|
-
}, null, 2),
|
|
347
|
-
},
|
|
348
|
-
],
|
|
349
|
-
};
|
|
350
|
-
});
|
|
308
|
+
// NOTE: cloudflare_detect and cloudflare_wait moved to Enterprise (v16.18.0)
|
|
351
309
|
// =========================================================================
|
|
352
310
|
// Interaction Tools
|
|
353
311
|
// =========================================================================
|
|
@@ -2320,298 +2278,12 @@ Begin the simulation now. Narrate your thoughts as this persona.
|
|
|
2320
2278
|
};
|
|
2321
2279
|
});
|
|
2322
2280
|
// ============================================================================
|
|
2323
|
-
//
|
|
2324
|
-
//
|
|
2325
|
-
//
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
const version = getEnterpriseVersion();
|
|
2329
|
-
const enabled = stealthConfig?.enabled ?? false;
|
|
2330
|
-
const proxyConfigured = !!stealthConfig?.proxy?.server;
|
|
2331
|
-
return {
|
|
2332
|
-
content: [
|
|
2333
|
-
{
|
|
2334
|
-
type: "text",
|
|
2335
|
-
text: JSON.stringify({
|
|
2336
|
-
enterprise_available: available,
|
|
2337
|
-
enterprise_version: version,
|
|
2338
|
-
stealth_enabled: enabled,
|
|
2339
|
-
stealth_config: enabled ? {
|
|
2340
|
-
authorized_domains: stealthConfig?.authorization?.authorizedDomains ?? [],
|
|
2341
|
-
blocked_domains: stealthConfig?.authorization?.blockedDomains ?? [],
|
|
2342
|
-
} : null,
|
|
2343
|
-
proxy_configured: proxyConfigured,
|
|
2344
|
-
proxy_server: proxyConfigured
|
|
2345
|
-
? stealthConfig?.proxy?.server?.replace(/:[^:@]*@/, ":****@") // Mask password
|
|
2346
|
-
: null,
|
|
2347
|
-
message: available
|
|
2348
|
-
? `Enterprise v${version} available. Stealth ${enabled ? "enabled" : "disabled"}.${proxyConfigured ? " Proxy active." : ""}`
|
|
2349
|
-
: "Enterprise not installed. Install cbrowser-enterprise for stealth capabilities.",
|
|
2350
|
-
}, null, 2),
|
|
2351
|
-
},
|
|
2352
|
-
],
|
|
2353
|
-
};
|
|
2354
|
-
});
|
|
2355
|
-
server.tool("stealth_enable", "Enable constitutional stealth mode for authorized domains. Requires cbrowser-enterprise. You must have authorization to test on the specified domains. Optionally configure a residential/datacenter proxy to bypass IP-based detection.", {
|
|
2356
|
-
authorized_domains: z.array(z.string()).describe("Domains you are authorized to test (e.g., ['*.mycompany.com', 'staging.example.com'])"),
|
|
2357
|
-
signed_by: z.string().describe("Your email or identifier confirming authorization"),
|
|
2358
|
-
proxy_server: z.string().optional().describe("Proxy server URL (e.g., 'http://proxy.example.com:8080' or 'socks5://proxy.example.com:1080'). Use residential proxies for best detection bypass."),
|
|
2359
|
-
proxy_username: z.string().optional().describe("Proxy authentication username (optional)"),
|
|
2360
|
-
proxy_password: z.string().optional().describe("Proxy authentication password (optional)"),
|
|
2361
|
-
}, async ({ authorized_domains, signed_by, proxy_server, proxy_username, proxy_password }) => {
|
|
2362
|
-
const available = await isEnterpriseAvailable();
|
|
2363
|
-
if (!available) {
|
|
2364
|
-
return {
|
|
2365
|
-
content: [
|
|
2366
|
-
{
|
|
2367
|
-
type: "text",
|
|
2368
|
-
text: JSON.stringify({
|
|
2369
|
-
success: false,
|
|
2370
|
-
error: "Enterprise not installed",
|
|
2371
|
-
message: "Stealth mode requires cbrowser-enterprise. Contact alexandria.shai.eden@gmail.com for access.",
|
|
2372
|
-
}, null, 2),
|
|
2373
|
-
},
|
|
2374
|
-
],
|
|
2375
|
-
};
|
|
2376
|
-
}
|
|
2377
|
-
// Create stealth config with acknowledgment
|
|
2378
|
-
stealthConfig = {
|
|
2379
|
-
enabled: true,
|
|
2380
|
-
authorization: {
|
|
2381
|
-
authorizedDomains: authorized_domains,
|
|
2382
|
-
blockedDomains: [],
|
|
2383
|
-
requireExplicitAuth: true,
|
|
2384
|
-
},
|
|
2385
|
-
acknowledgment: {
|
|
2386
|
-
ownershipConfirmed: true,
|
|
2387
|
-
authorizedTestingOnly: true,
|
|
2388
|
-
acceptsResponsibility: true,
|
|
2389
|
-
signedBy: signed_by,
|
|
2390
|
-
signedAt: new Date().toISOString(),
|
|
2391
|
-
},
|
|
2392
|
-
rateLimits: {
|
|
2393
|
-
requestsPerMinute: 30,
|
|
2394
|
-
formsPerMinute: 5,
|
|
2395
|
-
authAttemptsPerMinute: 3,
|
|
2396
|
-
},
|
|
2397
|
-
// Add proxy config if provided
|
|
2398
|
-
proxy: proxy_server ? {
|
|
2399
|
-
server: proxy_server,
|
|
2400
|
-
username: proxy_username,
|
|
2401
|
-
password: proxy_password,
|
|
2402
|
-
} : undefined,
|
|
2403
|
-
};
|
|
2404
|
-
// Get enforcer with config
|
|
2405
|
-
stealthEnforcer = await getEnforcer(stealthConfig);
|
|
2406
|
-
// Reset browser to apply stealth and proxy to new pages
|
|
2407
|
-
if (browser) {
|
|
2408
|
-
await browser.close();
|
|
2409
|
-
browser = null;
|
|
2410
|
-
}
|
|
2411
|
-
return {
|
|
2412
|
-
content: [
|
|
2413
|
-
{
|
|
2414
|
-
type: "text",
|
|
2415
|
-
text: JSON.stringify({
|
|
2416
|
-
success: true,
|
|
2417
|
-
message: "Stealth mode enabled",
|
|
2418
|
-
authorized_domains,
|
|
2419
|
-
signed_by,
|
|
2420
|
-
signed_at: stealthConfig.acknowledgment?.signedAt,
|
|
2421
|
-
rate_limits: stealthConfig.rateLimits,
|
|
2422
|
-
proxy_configured: !!proxy_server,
|
|
2423
|
-
proxy_server: proxy_server ? proxy_server.replace(/:[^:@]*@/, ":****@") : null, // Mask password in logs
|
|
2424
|
-
note: proxy_server
|
|
2425
|
-
? "Stealth measures and proxy will be applied to all new pages on authorized domains."
|
|
2426
|
-
: "Stealth measures will be applied to all new pages on authorized domains.",
|
|
2427
|
-
}, null, 2),
|
|
2428
|
-
},
|
|
2429
|
-
],
|
|
2430
|
-
};
|
|
2431
|
-
});
|
|
2432
|
-
server.tool("stealth_check", "Check if a stealth action is allowed on a specific URL. Returns whether the action can proceed and any restrictions.", {
|
|
2433
|
-
action: z.string().describe("Action to check (e.g., 'navigate', 'click', 'fill', 'submit')"),
|
|
2434
|
-
url: z.string().url().describe("URL where the action would occur"),
|
|
2435
|
-
}, async ({ action, url }) => {
|
|
2436
|
-
if (!stealthEnforcer) {
|
|
2437
|
-
return {
|
|
2438
|
-
content: [
|
|
2439
|
-
{
|
|
2440
|
-
type: "text",
|
|
2441
|
-
text: JSON.stringify({
|
|
2442
|
-
allowed: false,
|
|
2443
|
-
reason: "Stealth not enabled",
|
|
2444
|
-
suggestion: "Use stealth_enable to configure authorized domains first.",
|
|
2445
|
-
}, null, 2),
|
|
2446
|
-
},
|
|
2447
|
-
],
|
|
2448
|
-
};
|
|
2449
|
-
}
|
|
2450
|
-
const check = await stealthEnforcer.canExecuteWithStealth(action, url);
|
|
2451
|
-
return {
|
|
2452
|
-
content: [
|
|
2453
|
-
{
|
|
2454
|
-
type: "text",
|
|
2455
|
-
text: JSON.stringify({
|
|
2456
|
-
allowed: check.allowed,
|
|
2457
|
-
zone: check.zone,
|
|
2458
|
-
reason: check.reason,
|
|
2459
|
-
suggestion: check.suggestion,
|
|
2460
|
-
requires_confirmation: check.requiresConfirmation ?? false,
|
|
2461
|
-
}, null, 2),
|
|
2462
|
-
},
|
|
2463
|
-
],
|
|
2464
|
-
};
|
|
2465
|
-
});
|
|
2466
|
-
server.tool("stealth_disable", "Disable stealth mode and clear the enforcer. Browser state is preserved - no recovery needed.", {}, async () => {
|
|
2467
|
-
const wasEnabled = stealthConfig?.enabled ?? false;
|
|
2468
|
-
stealthEnforcer = null;
|
|
2469
|
-
stealthConfig = null;
|
|
2470
|
-
// Preserve browser state - don't close
|
|
2471
|
-
// User can call reset_browser explicitly if needed
|
|
2472
|
-
return {
|
|
2473
|
-
content: [
|
|
2474
|
-
{
|
|
2475
|
-
type: "text",
|
|
2476
|
-
text: JSON.stringify({
|
|
2477
|
-
success: true,
|
|
2478
|
-
was_enabled: wasEnabled,
|
|
2479
|
-
browser_preserved: true,
|
|
2480
|
-
message: wasEnabled
|
|
2481
|
-
? "Stealth mode disabled. Browser state preserved - continue using normally."
|
|
2482
|
-
: "Stealth was not enabled.",
|
|
2483
|
-
}, null, 2),
|
|
2484
|
-
},
|
|
2485
|
-
],
|
|
2486
|
-
};
|
|
2487
|
-
});
|
|
2488
|
-
// ============================================================================
|
|
2489
|
-
// STEALTH DIAGNOSTIC TOOL (v16.3.0)
|
|
2281
|
+
// NOTE: Stealth tools moved to Enterprise (v16.18.0)
|
|
2282
|
+
// The following tools are now Enterprise-only:
|
|
2283
|
+
// - stealth_status, stealth_enable, stealth_disable, stealth_check, stealth_diagnose
|
|
2284
|
+
// - cloudflare_detect, cloudflare_wait
|
|
2285
|
+
// Contact alexandria.shai.eden@gmail.com for Enterprise access.
|
|
2490
2286
|
// ============================================================================
|
|
2491
|
-
server.tool("stealth_diagnose", "Navigate to a URL and diagnose what bot detection methods the site uses. Returns analysis of fingerprint, IP, behavioral, and WAF/Cloudflare detection.", {
|
|
2492
|
-
url: z.string().url().describe("URL to diagnose for bot detection methods"),
|
|
2493
|
-
}, async ({ url }) => {
|
|
2494
|
-
const b = await getBrowser();
|
|
2495
|
-
const diagnosis = {
|
|
2496
|
-
url,
|
|
2497
|
-
detection_methods: {
|
|
2498
|
-
fingerprint: { detected: false, evidence: [] },
|
|
2499
|
-
ip_reputation: { likely: false, evidence: [] },
|
|
2500
|
-
behavioral: { detected: false, evidence: [] },
|
|
2501
|
-
waf_cloudflare: { detected: false, type: null, evidence: [] },
|
|
2502
|
-
},
|
|
2503
|
-
page_loaded: false,
|
|
2504
|
-
recommendations: [],
|
|
2505
|
-
};
|
|
2506
|
-
try {
|
|
2507
|
-
// Navigate with short timeout to detect blocks
|
|
2508
|
-
const navResult = await b.navigate(url);
|
|
2509
|
-
if (!navResult.success) {
|
|
2510
|
-
diagnosis.detection_methods.ip_reputation.likely = true;
|
|
2511
|
-
diagnosis.detection_methods.ip_reputation.evidence.push("Navigation failed: " + (navResult.errors?.join(", ") || "unknown error"));
|
|
2512
|
-
diagnosis.recommendations.push("Site may block datacenter IPs. Consider residential proxy.");
|
|
2513
|
-
return {
|
|
2514
|
-
content: [{ type: "text", text: JSON.stringify(diagnosis, null, 2) }],
|
|
2515
|
-
};
|
|
2516
|
-
}
|
|
2517
|
-
diagnosis.page_loaded = true;
|
|
2518
|
-
// Check page content for detection indicators
|
|
2519
|
-
const page = await b.getPage();
|
|
2520
|
-
if (page) {
|
|
2521
|
-
const content = await page.content();
|
|
2522
|
-
const pageUrl = page.url();
|
|
2523
|
-
// Cloudflare detection
|
|
2524
|
-
if (content.includes("cf-browser-verification") || content.includes("cf_chl_opt")) {
|
|
2525
|
-
diagnosis.detection_methods.waf_cloudflare.detected = true;
|
|
2526
|
-
diagnosis.detection_methods.waf_cloudflare.type = "Cloudflare Challenge";
|
|
2527
|
-
diagnosis.detection_methods.waf_cloudflare.evidence.push("Found cf-browser-verification in page");
|
|
2528
|
-
diagnosis.recommendations.push("Cloudflare challenge detected. Stealth may help with browser checks.");
|
|
2529
|
-
}
|
|
2530
|
-
if (content.includes("turnstile") || content.includes("challenges.cloudflare.com")) {
|
|
2531
|
-
diagnosis.detection_methods.waf_cloudflare.detected = true;
|
|
2532
|
-
diagnosis.detection_methods.waf_cloudflare.type = "Cloudflare Turnstile";
|
|
2533
|
-
diagnosis.detection_methods.waf_cloudflare.evidence.push("Found Turnstile widget");
|
|
2534
|
-
diagnosis.recommendations.push("Turnstile CAPTCHA present. May pass with stealth, but IP reputation affects success.");
|
|
2535
|
-
}
|
|
2536
|
-
// Reddit-style IP blocking - v16.7.2: More specific patterns to reduce false positives
|
|
2537
|
-
const blockPatterns = [
|
|
2538
|
-
/you.{0,20}(have been|are|'ve been) blocked/i,
|
|
2539
|
-
/your.{0,20}(ip|access).{0,20}(blocked|denied)/i,
|
|
2540
|
-
/access.{0,10}(to this|has been).{0,10}denied/i,
|
|
2541
|
-
/request.{0,15}blocked/i,
|
|
2542
|
-
/temporarily blocked/i,
|
|
2543
|
-
/ip.{0,10}(address|range).{0,15}blocked/i,
|
|
2544
|
-
];
|
|
2545
|
-
const isBlocked = blockPatterns.some(p => p.test(content)) ||
|
|
2546
|
-
pageUrl.includes("/blocked") ||
|
|
2547
|
-
pageUrl.includes("access-denied");
|
|
2548
|
-
if (isBlocked) {
|
|
2549
|
-
diagnosis.detection_methods.ip_reputation.likely = true;
|
|
2550
|
-
diagnosis.detection_methods.ip_reputation.evidence.push("Page indicates access/IP blocking");
|
|
2551
|
-
diagnosis.recommendations.push("IP-based blocking detected. Requires residential proxy.");
|
|
2552
|
-
}
|
|
2553
|
-
// Check for common bot detection scripts
|
|
2554
|
-
const botDetectors = [
|
|
2555
|
-
{ name: "PerimeterX", pattern: /px-captcha|human-challenge/ },
|
|
2556
|
-
{ name: "DataDome", pattern: /datadome|dd\.js/ },
|
|
2557
|
-
{ name: "Akamai Bot Manager", pattern: /akamai.*bot|_abck/ },
|
|
2558
|
-
{ name: "Shape Security", pattern: /shape.*security/ },
|
|
2559
|
-
{ name: "Imperva/Incapsula", pattern: /incap_ses|visid_incap/ },
|
|
2560
|
-
{ name: "Distil Networks", pattern: /distil|d\.js/ },
|
|
2561
|
-
];
|
|
2562
|
-
for (const detector of botDetectors) {
|
|
2563
|
-
if (detector.pattern.test(content)) {
|
|
2564
|
-
diagnosis.detection_methods.fingerprint.detected = true;
|
|
2565
|
-
diagnosis.detection_methods.fingerprint.evidence.push(`Found ${detector.name} signatures`);
|
|
2566
|
-
}
|
|
2567
|
-
}
|
|
2568
|
-
// Check for navigator.webdriver detection - v16.7.2: Only in JS context
|
|
2569
|
-
// Patterns that indicate actual detection code, not just documentation
|
|
2570
|
-
const webdriverPatterns = [
|
|
2571
|
-
/navigator\s*\.\s*webdriver/,
|
|
2572
|
-
/window\s*\.\s*navigator\s*\.\s*webdriver/,
|
|
2573
|
-
/\.webdriver\s*[=!]/, // Assignment or comparison
|
|
2574
|
-
/webdriver.*true|true.*webdriver/i, // Boolean check context
|
|
2575
|
-
];
|
|
2576
|
-
if (webdriverPatterns.some(p => p.test(content))) {
|
|
2577
|
-
diagnosis.detection_methods.fingerprint.detected = true;
|
|
2578
|
-
diagnosis.detection_methods.fingerprint.evidence.push("Page checks navigator.webdriver");
|
|
2579
|
-
diagnosis.recommendations.push("Enable stealth to patch navigator.webdriver.");
|
|
2580
|
-
}
|
|
2581
|
-
// Check for automation tool detection - v16.7.2: Only in detection context
|
|
2582
|
-
const automationDetectionPatterns = [
|
|
2583
|
-
/window\s*\.\s*(?:__)?(?:puppeteer|playwright|selenium)/i,
|
|
2584
|
-
/navigator\s*\.\s*(?:__)?(?:puppeteer|playwright|selenium)/i,
|
|
2585
|
-
/typeof\s+(?:puppeteer|playwright|selenium)/i,
|
|
2586
|
-
/["'](?:puppeteer|playwright|selenium)["']\s*in\s*window/i,
|
|
2587
|
-
];
|
|
2588
|
-
if (automationDetectionPatterns.some(p => p.test(content))) {
|
|
2589
|
-
diagnosis.detection_methods.fingerprint.detected = true;
|
|
2590
|
-
diagnosis.detection_methods.fingerprint.evidence.push("Page checks for automation tools");
|
|
2591
|
-
}
|
|
2592
|
-
// Summary recommendations
|
|
2593
|
-
if (diagnosis.detection_methods.fingerprint.detected && !diagnosis.detection_methods.ip_reputation.likely) {
|
|
2594
|
-
diagnosis.recommendations.push("Browser fingerprint detection found. Stealth mode should help.");
|
|
2595
|
-
}
|
|
2596
|
-
if (diagnosis.detection_methods.ip_reputation.likely) {
|
|
2597
|
-
diagnosis.recommendations.push("IP reputation is the primary block. Stealth alone won't solve this.");
|
|
2598
|
-
}
|
|
2599
|
-
if (!diagnosis.detection_methods.fingerprint.detected &&
|
|
2600
|
-
!diagnosis.detection_methods.ip_reputation.likely &&
|
|
2601
|
-
!diagnosis.detection_methods.waf_cloudflare.detected) {
|
|
2602
|
-
diagnosis.recommendations.push("No obvious bot detection found. Site should work without stealth.");
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
catch (error) {
|
|
2607
|
-
diagnosis.detection_methods.ip_reputation.likely = true;
|
|
2608
|
-
diagnosis.detection_methods.ip_reputation.evidence.push("Error: " + String(error));
|
|
2609
|
-
diagnosis.recommendations.push("Navigation error - likely IP-based blocking.");
|
|
2610
|
-
}
|
|
2611
|
-
return {
|
|
2612
|
-
content: [{ type: "text", text: JSON.stringify(diagnosis, null, 2) }],
|
|
2613
|
-
};
|
|
2614
|
-
});
|
|
2615
2287
|
}
|
|
2616
2288
|
/**
|
|
2617
2289
|
* Create a configured MCP server instance
|