@fanboynz/network-scanner 1.0.85 → 1.0.87
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/lib/browserhealth.js +121 -8
- package/lib/cloudflare.js +7 -6
- package/nwss.js +73 -5
- package/package.json +1 -1
package/lib/browserhealth.js
CHANGED
|
@@ -5,6 +5,89 @@
|
|
|
5
5
|
|
|
6
6
|
const { formatLogMessage, messageColors } = require('./colorize');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Quick browser responsiveness test for use during page setup
|
|
10
|
+
* Designed to catch browser degradation between operations
|
|
11
|
+
* @param {import('puppeteer').Browser} browserInstance - Puppeteer browser instance
|
|
12
|
+
* @param {number} timeout - Timeout in milliseconds (default: 3000)
|
|
13
|
+
* @returns {Promise<boolean>} True if browser responds quickly, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
async function isQuicklyResponsive(browserInstance, timeout = 3000) {
|
|
16
|
+
try {
|
|
17
|
+
await Promise.race([
|
|
18
|
+
browserInstance.version(), // Quick responsiveness test
|
|
19
|
+
new Promise((_, reject) =>
|
|
20
|
+
setTimeout(() => reject(new Error('Quick responsiveness timeout')), timeout)
|
|
21
|
+
)
|
|
22
|
+
]);
|
|
23
|
+
return true;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Tests if browser can handle network operations (like Network.enable)
|
|
31
|
+
* Creates a test page and attempts basic network setup
|
|
32
|
+
* @param {import('puppeteer').Browser} browserInstance - Puppeteer browser instance
|
|
33
|
+
* @param {number} timeout - Timeout in milliseconds (default: 10000)
|
|
34
|
+
* @returns {Promise<object>} Network capability test result
|
|
35
|
+
*/
|
|
36
|
+
async function testNetworkCapability(browserInstance, timeout = 10000) {
|
|
37
|
+
const result = {
|
|
38
|
+
capable: false,
|
|
39
|
+
error: null,
|
|
40
|
+
responseTime: 0
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
let testPage = null;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// Create test page
|
|
48
|
+
testPage = await Promise.race([
|
|
49
|
+
browserInstance.newPage(),
|
|
50
|
+
new Promise((_, reject) =>
|
|
51
|
+
setTimeout(() => reject(new Error('Test page creation timeout')), timeout)
|
|
52
|
+
)
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
// Test network operations (the critical operation that's failing)
|
|
56
|
+
await Promise.race([
|
|
57
|
+
testPage.setRequestInterception(true),
|
|
58
|
+
new Promise((_, reject) =>
|
|
59
|
+
setTimeout(() => reject(new Error('Network.enable test timeout')), timeout)
|
|
60
|
+
)
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
// Turn off interception and close
|
|
64
|
+
await testPage.setRequestInterception(false);
|
|
65
|
+
result.capable = true;
|
|
66
|
+
result.responseTime = Date.now() - startTime;
|
|
67
|
+
|
|
68
|
+
} catch (error) {
|
|
69
|
+
result.error = error.message;
|
|
70
|
+
result.responseTime = Date.now() - startTime;
|
|
71
|
+
|
|
72
|
+
// Classify the error type
|
|
73
|
+
if (error.message.includes('Network.enable') ||
|
|
74
|
+
error.message.includes('timed out') ||
|
|
75
|
+
error.message.includes('Protocol error')) {
|
|
76
|
+
result.error = `Network capability test failed: ${error.message}`;
|
|
77
|
+
}
|
|
78
|
+
} finally {
|
|
79
|
+
if (testPage && !testPage.isClosed()) {
|
|
80
|
+
try {
|
|
81
|
+
await testPage.close();
|
|
82
|
+
} catch (closeErr) {
|
|
83
|
+
/* ignore cleanup errors */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
8
91
|
/**
|
|
9
92
|
* Checks if browser instance is still responsive
|
|
10
93
|
* @param {import('puppeteer').Browser} browserInstance - Puppeteer browser instance
|
|
@@ -18,7 +101,8 @@ async function checkBrowserHealth(browserInstance, timeout = 8000) {
|
|
|
18
101
|
error: null,
|
|
19
102
|
responseTime: 0,
|
|
20
103
|
recommendations: [],
|
|
21
|
-
criticalError: false
|
|
104
|
+
criticalError: false,
|
|
105
|
+
networkCapable: false
|
|
22
106
|
};
|
|
23
107
|
|
|
24
108
|
const startTime = Date.now();
|
|
@@ -82,13 +166,25 @@ async function checkBrowserHealth(browserInstance, timeout = 8000) {
|
|
|
82
166
|
return healthResult;
|
|
83
167
|
}
|
|
84
168
|
|
|
85
|
-
// Test 5:
|
|
169
|
+
// Test 5: Network capability test (critical for Network.enable issues)
|
|
170
|
+
const networkTest = await testNetworkCapability(browserInstance, Math.min(timeout, 5000));
|
|
171
|
+
healthResult.networkCapable = networkTest.capable;
|
|
172
|
+
|
|
173
|
+
if (!networkTest.capable) {
|
|
174
|
+
healthResult.recommendations.push(`Network operations failing: ${networkTest.error}`);
|
|
175
|
+
if (networkTest.error && networkTest.error.includes('Network.enable')) {
|
|
176
|
+
healthResult.criticalError = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Test 6: Check response time performance
|
|
86
181
|
if (healthResult.responseTime > 5000) {
|
|
87
182
|
healthResult.recommendations.push('Slow browser response - consider restart');
|
|
88
183
|
}
|
|
89
184
|
|
|
90
|
-
// If all tests pass
|
|
91
|
-
healthResult.healthy =
|
|
185
|
+
// If all tests pass (including network capability)
|
|
186
|
+
healthResult.healthy = networkTest.capable; // Network capability is now critical for health
|
|
187
|
+
|
|
92
188
|
|
|
93
189
|
} catch (error) {
|
|
94
190
|
healthResult.error = error.message;
|
|
@@ -195,7 +291,11 @@ function isCriticalProtocolError(error) {
|
|
|
195
291
|
'Browser process exited',
|
|
196
292
|
'Navigation timeout of',
|
|
197
293
|
'Page crashed',
|
|
198
|
-
'Renderer process crashed'
|
|
294
|
+
'Renderer process crashed',
|
|
295
|
+
// Network-specific critical errors
|
|
296
|
+
'Network.enable timed out',
|
|
297
|
+
'Network.disable timed out',
|
|
298
|
+
'Network service not available'
|
|
199
299
|
];
|
|
200
300
|
|
|
201
301
|
return criticalErrors.some(criticalError =>
|
|
@@ -413,14 +513,25 @@ async function monitorBrowserHealth(browserInstance, context = {}, options = {})
|
|
|
413
513
|
|
|
414
514
|
/**
|
|
415
515
|
* Simple health check function for quick integration
|
|
516
|
+
* Enhanced version that includes network capability testing
|
|
416
517
|
* @param {import('puppeteer').Browser} browserInstance - Puppeteer browser instance
|
|
518
|
+
* @param {boolean} includeNetworkTest - Whether to test network capabilities (default: true)
|
|
417
519
|
* @returns {Promise<boolean>} True if browser is healthy, false otherwise
|
|
418
520
|
*/
|
|
419
|
-
async function isBrowserHealthy(browserInstance) {
|
|
521
|
+
async function isBrowserHealthy(browserInstance, includeNetworkTest = true) {
|
|
420
522
|
try {
|
|
421
|
-
|
|
523
|
+
// Quick responsiveness test first (fastest check)
|
|
524
|
+
const quickCheck = await isQuicklyResponsive(browserInstance, 2500);
|
|
525
|
+
if (!quickCheck) return false;
|
|
526
|
+
|
|
527
|
+
// More comprehensive health check if quick test passes
|
|
528
|
+
const health = await checkBrowserHealth(browserInstance, includeNetworkTest ? 8000 : 5000);
|
|
422
529
|
const connectivity = await testBrowserConnectivity(browserInstance, 3000);
|
|
423
|
-
|
|
530
|
+
|
|
531
|
+
const baseHealth = health.healthy && connectivity.connected && connectivity.cdpResponsive;
|
|
532
|
+
|
|
533
|
+
// Include network capability in health assessment if requested
|
|
534
|
+
return includeNetworkTest ? (baseHealth && health.networkCapable) : baseHealth;
|
|
424
535
|
} catch (error) {
|
|
425
536
|
return false;
|
|
426
537
|
}
|
|
@@ -430,6 +541,8 @@ module.exports = {
|
|
|
430
541
|
checkBrowserHealth,
|
|
431
542
|
checkBrowserMemory,
|
|
432
543
|
testBrowserConnectivity,
|
|
544
|
+
testNetworkCapability,
|
|
545
|
+
isQuicklyResponsive,
|
|
433
546
|
performHealthAssessment,
|
|
434
547
|
monitorBrowserHealth,
|
|
435
548
|
isBrowserHealthy,
|
package/lib/cloudflare.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cloudflare bypass and challenge handling module - Optimized with smart detection and adaptive timeouts
|
|
3
|
+
* Version: 2.4.1 - Bump timeout values
|
|
3
4
|
* Version: 2.4.0 - Fix possible endless loops with retry logic and loop detection
|
|
4
5
|
* Version: 2.3.1 - Colorize CF
|
|
5
6
|
* Version: 2.3.0 - Support CF iframe challenges, and better error handling
|
|
@@ -26,9 +27,9 @@ const TIMEOUTS = {
|
|
|
26
27
|
PAGE_EVALUATION_SAFE: 10000, // Safe page evaluation with extra buffer
|
|
27
28
|
PHISHING_CLICK: 3000, // Timeout for clicking phishing continue button
|
|
28
29
|
PHISHING_NAVIGATION: 8000, // Wait for navigation after phishing bypass
|
|
29
|
-
JS_CHALLENGE_BUFFER:
|
|
30
|
-
TURNSTILE_COMPLETION:
|
|
31
|
-
TURNSTILE_COMPLETION_BUFFER:
|
|
30
|
+
JS_CHALLENGE_BUFFER: 30000, // JS challenge with safety buffer
|
|
31
|
+
TURNSTILE_COMPLETION: 20000, // Turnstile completion check
|
|
32
|
+
TURNSTILE_COMPLETION_BUFFER: 25000, // Turnstile completion with buffer
|
|
32
33
|
CLICK_TIMEOUT: 5000, // Standard click operation timeout
|
|
33
34
|
CLICK_TIMEOUT_BUFFER: 1000, // Click timeout safety buffer
|
|
34
35
|
NAVIGATION_TIMEOUT: 15000, // Standard navigation timeout
|
|
@@ -52,9 +53,9 @@ const FAST_TIMEOUTS = {
|
|
|
52
53
|
ELEMENT_INTERACTION_DELAY: 250, // Fast element interactions
|
|
53
54
|
SELECTOR_WAIT: 1500, // Fast selector waits
|
|
54
55
|
TURNSTILE_OPERATION: 6000, // Fast Turnstile operations
|
|
55
|
-
JS_CHALLENGE:
|
|
56
|
-
CHALLENGE_SOLVING:
|
|
57
|
-
CHALLENGE_COMPLETION:
|
|
56
|
+
JS_CHALLENGE: 22000, // Fast JS challenge completion
|
|
57
|
+
CHALLENGE_SOLVING: 30000, // Fast overall challenge solving
|
|
58
|
+
CHALLENGE_COMPLETION: 8000 // Fast completion check
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
/**
|
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v1.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v1.0.87 ===
|
|
2
2
|
|
|
3
3
|
// puppeteer for browser automation, fs for file system operations, psl for domain parsing.
|
|
4
4
|
// const pLimit = require('p-limit'); // Will be dynamically imported
|
|
@@ -120,10 +120,10 @@ function detectPuppeteerVersion() {
|
|
|
120
120
|
// Enhanced redirect handling
|
|
121
121
|
const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/redirect');
|
|
122
122
|
// Ensure web browser is working correctly
|
|
123
|
-
const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
|
|
123
|
+
const { monitorBrowserHealth, isBrowserHealthy, isQuicklyResponsive } = require('./lib/browserhealth');
|
|
124
124
|
|
|
125
125
|
// --- Script Configuration & Constants ---
|
|
126
|
-
const VERSION = '1.0.
|
|
126
|
+
const VERSION = '1.0.87'; // Script version
|
|
127
127
|
|
|
128
128
|
// get startTime
|
|
129
129
|
const startTime = Date.now();
|
|
@@ -1483,6 +1483,22 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1483
1483
|
if (!page || page.isClosed()) {
|
|
1484
1484
|
throw new Error('Failed to create valid page instance');
|
|
1485
1485
|
}
|
|
1486
|
+
|
|
1487
|
+
// Additional health check after page creation but before critical setup
|
|
1488
|
+
const stillHealthy = await isQuicklyResponsive(browserInstance, 3000);
|
|
1489
|
+
|
|
1490
|
+
if (!stillHealthy) {
|
|
1491
|
+
if (forceDebug) {
|
|
1492
|
+
console.log(formatLogMessage('debug', `Browser unresponsive during page setup for ${currentUrl} - triggering restart`));
|
|
1493
|
+
}
|
|
1494
|
+
return {
|
|
1495
|
+
url: currentUrl,
|
|
1496
|
+
rules: [],
|
|
1497
|
+
success: false,
|
|
1498
|
+
needsImmediateRestart: true,
|
|
1499
|
+
error: 'Browser became unresponsive during page setup - restart required'
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1486
1502
|
|
|
1487
1503
|
// Set aggressive timeouts for problematic operations
|
|
1488
1504
|
// Optimized timeouts for Puppeteer 23.x responsiveness
|
|
@@ -1572,6 +1588,22 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1572
1588
|
console.log(formatLogMessage('debug', `[evalOnDoc] Site-specific Fetch/XHR interception enabled for: ${currentUrl}`));
|
|
1573
1589
|
}
|
|
1574
1590
|
}
|
|
1591
|
+
// Quick browser health check before script injection
|
|
1592
|
+
let browserResponsive = false;
|
|
1593
|
+
try {
|
|
1594
|
+
await Promise.race([
|
|
1595
|
+
browserInstance.version(), // Quick responsiveness test
|
|
1596
|
+
new Promise((_, reject) =>
|
|
1597
|
+
setTimeout(() => reject(new Error('Browser health check timeout')), 5000)
|
|
1598
|
+
)
|
|
1599
|
+
]);
|
|
1600
|
+
browserResponsive = true;
|
|
1601
|
+
} catch (healthErr) {
|
|
1602
|
+
console.warn(formatLogMessage('warn', `[evalOnDoc] Browser unresponsive for ${currentUrl}: ${healthErr.message} - skipping script injection`));
|
|
1603
|
+
browserResponsive = false;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if (browserResponsive) {
|
|
1575
1607
|
try {
|
|
1576
1608
|
await page.evaluateOnNewDocument(() => {
|
|
1577
1609
|
// Prevent infinite reload loops
|
|
@@ -1636,7 +1668,16 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1636
1668
|
};
|
|
1637
1669
|
});
|
|
1638
1670
|
} catch (evalErr) {
|
|
1639
|
-
|
|
1671
|
+
if (evalErr.message.includes('timed out') || evalErr.message.includes('ProtocolError')) {
|
|
1672
|
+
console.warn(formatLogMessage('warn', `[evalOnDoc] Script injection protocol timeout for ${currentUrl} - continuing without XHR/Fetch interception`));
|
|
1673
|
+
} else {
|
|
1674
|
+
console.warn(formatLogMessage('warn', `[evalOnDoc] Failed to set up Fetch/XHR interception for ${currentUrl}: ${evalErr.message}`));
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
} else {
|
|
1678
|
+
if (forceDebug) {
|
|
1679
|
+
console.log(formatLogMessage('debug', `[evalOnDoc] Continuing ${currentUrl} without XHR/Fetch interception due to browser health`));
|
|
1680
|
+
}
|
|
1640
1681
|
}
|
|
1641
1682
|
}
|
|
1642
1683
|
// --- END: evaluateOnNewDocument for Fetch/XHR Interception ---
|
|
@@ -1683,7 +1724,34 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1683
1724
|
}
|
|
1684
1725
|
// --- End of Per-Page CDP Setup ---
|
|
1685
1726
|
|
|
1686
|
-
|
|
1727
|
+
// Protected request interception setup with timeout
|
|
1728
|
+
try {
|
|
1729
|
+
// Test if network operations are responsive before enabling request interception
|
|
1730
|
+
await Promise.race([
|
|
1731
|
+
page.setRequestInterception(true),
|
|
1732
|
+
new Promise((_, reject) =>
|
|
1733
|
+
setTimeout(() => reject(new Error('Network.enable timeout')), 10000)
|
|
1734
|
+
)
|
|
1735
|
+
]);
|
|
1736
|
+
|
|
1737
|
+
if (forceDebug) {
|
|
1738
|
+
console.log(formatLogMessage('debug', `Request interception enabled successfully for ${currentUrl}`));
|
|
1739
|
+
}
|
|
1740
|
+
} catch (networkErr) {
|
|
1741
|
+
if (networkErr.message.includes('timed out') ||
|
|
1742
|
+
networkErr.message.includes('Network.enable') ||
|
|
1743
|
+
networkErr.message.includes('timeout')) {
|
|
1744
|
+
console.warn(formatLogMessage('warn', `Network setup failed for ${currentUrl}: ${networkErr.message} - triggering browser restart`));
|
|
1745
|
+
return {
|
|
1746
|
+
url: currentUrl,
|
|
1747
|
+
rules: [],
|
|
1748
|
+
success: false,
|
|
1749
|
+
needsImmediateRestart: true,
|
|
1750
|
+
error: 'Network.enable timeout - browser restart required'
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
throw networkErr; // Re-throw other errors
|
|
1754
|
+
}
|
|
1687
1755
|
|
|
1688
1756
|
// Set up frame handling to suppress invalid URL errors
|
|
1689
1757
|
setupFrameHandling(page, forceDebug);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.87",
|
|
4
4
|
"description": "A Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features include fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, and multiple output formats.",
|
|
5
5
|
"main": "nwss.js",
|
|
6
6
|
"scripts": {
|