@fanboynz/network-scanner 1.0.96 → 1.0.97
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/README.md +1 -1
- package/lib/browserhealth.js +131 -0
- package/nwss.js +37 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ Example:
|
|
|
151
151
|
| `blocked` | Array | - | Domains or regexes to block during scanning |
|
|
152
152
|
| `even_blocked` | Boolean | `false` | Add matching rules even if requests are blocked |
|
|
153
153
|
| `bypass_cache` | Boolean | `false` | Skip all caching for this site's URLs |
|
|
154
|
-
|
|
154
|
+
| `window_cleanup` | Boolean | `false` | Close extra browser windows/tabs after entire URL group completes with 16s delay |
|
|
155
155
|
|
|
156
156
|
### Redirect Handling Options
|
|
157
157
|
|
package/lib/browserhealth.js
CHANGED
|
@@ -5,6 +5,136 @@
|
|
|
5
5
|
|
|
6
6
|
const { formatLogMessage, messageColors } = require('./colorize');
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
// Window cleanup delay constant
|
|
10
|
+
const WINDOW_CLEANUP_DELAY_MS = 16000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Performs group-level window cleanup after all URLs in a site group complete
|
|
14
|
+
* Closes all extra windows except the main browser window
|
|
15
|
+
* @param {import('puppeteer').Browser} browserInstance - Browser instance
|
|
16
|
+
* @param {string} groupDescription - Description of the group for logging
|
|
17
|
+
* @param {boolean} forceDebug - Debug logging flag
|
|
18
|
+
* @returns {Promise<Object>} Cleanup results
|
|
19
|
+
*/
|
|
20
|
+
async function performGroupWindowCleanup(browserInstance, groupDescription, forceDebug) {
|
|
21
|
+
try {
|
|
22
|
+
// Wait before cleanup to allow any final operations to complete
|
|
23
|
+
if (forceDebug) {
|
|
24
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Waiting ${WINDOW_CLEANUP_DELAY_MS}ms before cleanup for group: ${groupDescription}`));
|
|
25
|
+
}
|
|
26
|
+
await new Promise(resolve => setTimeout(resolve, WINDOW_CLEANUP_DELAY_MS));
|
|
27
|
+
|
|
28
|
+
const allPages = await browserInstance.pages();
|
|
29
|
+
const mainPage = allPages[0]; // Always keep the first page as main
|
|
30
|
+
const extraPages = allPages.slice(1); // All other pages can be closed
|
|
31
|
+
|
|
32
|
+
if (extraPages.length === 0) {
|
|
33
|
+
if (forceDebug) {
|
|
34
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] No extra windows to close for group: ${groupDescription}`));
|
|
35
|
+
}
|
|
36
|
+
return { success: true, closedCount: 0, totalPages: allPages.length, estimatedMemoryFreed: 0 };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Estimate memory usage before closing
|
|
40
|
+
let totalEstimatedMemory = 0;
|
|
41
|
+
const pageMemoryEstimates = [];
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < extraPages.length; i++) {
|
|
44
|
+
const page = extraPages[i];
|
|
45
|
+
let pageMemoryEstimate = 0;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
if (!page.isClosed()) {
|
|
49
|
+
// Get page metrics if available
|
|
50
|
+
const metrics = await Promise.race([
|
|
51
|
+
page.metrics(),
|
|
52
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('metrics timeout')), 1000))
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
// Calculate memory estimate based on page metrics
|
|
56
|
+
if (metrics) {
|
|
57
|
+
// Puppeteer metrics provide various memory-related values
|
|
58
|
+
pageMemoryEstimate = (
|
|
59
|
+
(metrics.JSHeapUsedSize || 0) + // JavaScript heap
|
|
60
|
+
(metrics.JSHeapTotalSize || 0) * 0.1 + // Estimated overhead
|
|
61
|
+
(metrics.Nodes || 0) * 100 + // DOM nodes (rough estimate)
|
|
62
|
+
(metrics.JSEventListeners || 0) * 50 // Event listeners
|
|
63
|
+
);
|
|
64
|
+
} else {
|
|
65
|
+
// Fallback: rough estimate based on page complexity
|
|
66
|
+
pageMemoryEstimate = 8 * 1024 * 1024; // 8MB default estimate per page
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch (metricsErr) {
|
|
70
|
+
// Fallback estimate if metrics fail
|
|
71
|
+
pageMemoryEstimate = 8 * 1024 * 1024; // 8MB default
|
|
72
|
+
if (forceDebug) {
|
|
73
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Could not get metrics for page ${i + 1}, using default estimate: ${metricsErr.message}`));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
pageMemoryEstimates.push(pageMemoryEstimate);
|
|
78
|
+
totalEstimatedMemory += pageMemoryEstimate;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Close all extra pages since the entire group is complete
|
|
82
|
+
const closePromises = extraPages.map(async (page, index) => {
|
|
83
|
+
try {
|
|
84
|
+
if (!page.isClosed()) {
|
|
85
|
+
await page.close();
|
|
86
|
+
return { success: true, url: page.url() || `page-${index}`, estimatedMemory: pageMemoryEstimates[index] };
|
|
87
|
+
}
|
|
88
|
+
return { success: false, reason: 'already_closed', estimatedMemory: 0 };
|
|
89
|
+
} catch (closeErr) {
|
|
90
|
+
if (forceDebug) {
|
|
91
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Failed to close page ${index + 1}: ${closeErr.message}`));
|
|
92
|
+
}
|
|
93
|
+
return { success: false, error: closeErr.message, estimatedMemory: 0 };
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const closeResults = await Promise.all(closePromises);
|
|
98
|
+
const successfulCloses = closeResults.filter(result => result.success === true).length;
|
|
99
|
+
const actualMemoryFreed = closeResults
|
|
100
|
+
.filter(result => result.success === true)
|
|
101
|
+
.reduce((sum, result) => sum + (result.estimatedMemory || 0), 0);
|
|
102
|
+
|
|
103
|
+
// Format memory for human readability
|
|
104
|
+
const formatMemory = (bytes) => {
|
|
105
|
+
if (bytes >= 1024 * 1024 * 1024) {
|
|
106
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
|
|
107
|
+
} else if (bytes >= 1024 * 1024) {
|
|
108
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
109
|
+
} else if (bytes >= 1024) {
|
|
110
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
111
|
+
} else {
|
|
112
|
+
return `${bytes}B`;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (forceDebug) {
|
|
117
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Closed ${successfulCloses}/${extraPages.length} windows for completed group: ${groupDescription} after ${WINDOW_CLEANUP_DELAY_MS}ms delay`));
|
|
118
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Estimated memory freed: ${formatMemory(actualMemoryFreed)}`));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
closedCount: successfulCloses,
|
|
124
|
+
totalPages: allPages.length,
|
|
125
|
+
mainPageKept: !mainPage.isClosed(),
|
|
126
|
+
delayUsed: WINDOW_CLEANUP_DELAY_MS,
|
|
127
|
+
estimatedMemoryFreed: actualMemoryFreed,
|
|
128
|
+
estimatedMemoryFreedFormatted: formatMemory(actualMemoryFreed)
|
|
129
|
+
};
|
|
130
|
+
} catch (cleanupErr) {
|
|
131
|
+
if (forceDebug) {
|
|
132
|
+
console.log(formatLogMessage('debug', `[group_window_cleanup] Group cleanup failed for ${groupDescription}: ${cleanupErr.message}`));
|
|
133
|
+
}
|
|
134
|
+
return { success: false, error: cleanupErr.message, estimatedMemoryFreed: 0 };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
8
138
|
/**
|
|
9
139
|
* Quick browser responsiveness test for use during page setup
|
|
10
140
|
* Designed to catch browser degradation between operations
|
|
@@ -541,6 +671,7 @@ module.exports = {
|
|
|
541
671
|
checkBrowserHealth,
|
|
542
672
|
checkBrowserMemory,
|
|
543
673
|
testBrowserConnectivity,
|
|
674
|
+
performGroupWindowCleanup,
|
|
544
675
|
testNetworkCapability,
|
|
545
676
|
isQuicklyResponsive,
|
|
546
677
|
performHealthAssessment,
|
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v1.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v1.0.97 ===
|
|
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
|
|
@@ -64,7 +64,7 @@ const TIMEOUTS = {
|
|
|
64
64
|
EMERGENCY_RESTART_DELAY: 2000,
|
|
65
65
|
BROWSER_STABILIZE_DELAY: 1000,
|
|
66
66
|
CURL_HANDLER_DELAY: 3000,
|
|
67
|
-
PROTOCOL_TIMEOUT:
|
|
67
|
+
PROTOCOL_TIMEOUT: 120000,
|
|
68
68
|
REDIRECT_JS_TIMEOUT: 5000
|
|
69
69
|
};
|
|
70
70
|
|
|
@@ -122,10 +122,10 @@ function detectPuppeteerVersion() {
|
|
|
122
122
|
// Enhanced redirect handling
|
|
123
123
|
const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/redirect');
|
|
124
124
|
// Ensure web browser is working correctly
|
|
125
|
-
const { monitorBrowserHealth, isBrowserHealthy, isQuicklyResponsive } = require('./lib/browserhealth');
|
|
125
|
+
const { monitorBrowserHealth, isBrowserHealthy, isQuicklyResponsive, performGroupWindowCleanup } = require('./lib/browserhealth');
|
|
126
126
|
|
|
127
127
|
// --- Script Configuration & Constants ---
|
|
128
|
-
const VERSION = '1.0.
|
|
128
|
+
const VERSION = '1.0.97'; // Script version
|
|
129
129
|
|
|
130
130
|
// get startTime
|
|
131
131
|
const startTime = Date.now();
|
|
@@ -571,6 +571,8 @@ Advanced Options:
|
|
|
571
571
|
dig_subdomain: true/false Use subdomain for dig lookup instead of root domain (default: false)
|
|
572
572
|
digRecordType: "A" DNS record type for dig (default: A)
|
|
573
573
|
|
|
574
|
+
window_cleanup: true/false Close extra browser windows/tabs after entire URL group completes with 5s delay (default: false)
|
|
575
|
+
|
|
574
576
|
Referrer Header Options:
|
|
575
577
|
referrer_headers: "https://google.com" Single referrer URL
|
|
576
578
|
referrer_headers: ["url1", "url2"] Random selection from array
|
|
@@ -3230,9 +3232,21 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3230
3232
|
}, 30000); // Check every 30 seconds
|
|
3231
3233
|
|
|
3232
3234
|
// Process URLs in batches to maintain concurrency while allowing browser restarts
|
|
3235
|
+
let siteGroupIndex = 0;
|
|
3233
3236
|
for (let batchStart = 0; batchStart < totalUrls; batchStart += RESOURCE_CLEANUP_INTERVAL) {
|
|
3234
3237
|
const batchEnd = Math.min(batchStart + RESOURCE_CLEANUP_INTERVAL, totalUrls);
|
|
3235
3238
|
const currentBatch = allTasks.slice(batchStart, batchEnd);
|
|
3239
|
+
|
|
3240
|
+
|
|
3241
|
+
// Group tasks by their source site configuration for window cleanup
|
|
3242
|
+
const tasksBySite = new Map();
|
|
3243
|
+
currentBatch.forEach(task => {
|
|
3244
|
+
const siteKey = `site_${sites.indexOf(task.config)}`;
|
|
3245
|
+
if (!tasksBySite.has(siteKey)) {
|
|
3246
|
+
tasksBySite.set(siteKey, []);
|
|
3247
|
+
}
|
|
3248
|
+
tasksBySite.get(siteKey).push(task);
|
|
3249
|
+
});
|
|
3236
3250
|
|
|
3237
3251
|
// IMPROVED: Only check health if we have indicators of problems
|
|
3238
3252
|
let healthCheck = { shouldRestart: false, reason: null };
|
|
@@ -3386,6 +3400,25 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3386
3400
|
}
|
|
3387
3401
|
|
|
3388
3402
|
results.push(...batchResults);
|
|
3403
|
+
|
|
3404
|
+
// Perform group window cleanup for completed sites
|
|
3405
|
+
for (const [siteKey, siteTasks] of tasksBySite) {
|
|
3406
|
+
const siteConfig = siteTasks[0].config; // All tasks in group have same config
|
|
3407
|
+
|
|
3408
|
+
if (siteConfig.window_cleanup === true) {
|
|
3409
|
+
const urlCount = siteTasks.length;
|
|
3410
|
+
const groupDescription = `${urlCount} URLs from site group ${++siteGroupIndex}`;
|
|
3411
|
+
|
|
3412
|
+
try {
|
|
3413
|
+
const groupCleanupResult = await performGroupWindowCleanup(browser, groupDescription, forceDebug);
|
|
3414
|
+
if (!silentMode && groupCleanupResult.success && groupCleanupResult.closedCount > 0) {
|
|
3415
|
+
console.log(`🗑️ Group cleanup: ${groupCleanupResult.closedCount} windows closed after completing ${groupDescription}`);
|
|
3416
|
+
}
|
|
3417
|
+
} catch (groupCleanupErr) {
|
|
3418
|
+
if (forceDebug) console.log(formatLogMessage('debug', `Group window cleanup failed: ${groupCleanupErr.message}`));
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3389
3422
|
|
|
3390
3423
|
processedUrlCount += batchSize;
|
|
3391
3424
|
urlsSinceLastCleanup += batchSize;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.97",
|
|
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": {
|