@fanboynz/network-scanner 1.0.80 → 1.0.82
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/cloudflare.js +364 -110
- package/lib/colorize.js +10 -3
- package/nwss.js +153 -45
- package/package.json +1 -1
package/lib/colorize.js
CHANGED
|
@@ -40,7 +40,10 @@ const colors = {
|
|
|
40
40
|
brightBlue: enableColors ? '\x1b[94m' : '',
|
|
41
41
|
brightMagenta: enableColors ? '\x1b[95m' : '',
|
|
42
42
|
brightCyan: enableColors ? '\x1b[96m' : '',
|
|
43
|
-
brightWhite: enableColors ? '\x1b[97m' : ''
|
|
43
|
+
brightWhite: enableColors ? '\x1b[97m' : '',
|
|
44
|
+
|
|
45
|
+
// Custom orange colors (using 256-color palette)
|
|
46
|
+
orange: enableColors ? '\x1b[38;5;208m' : ''
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
/**
|
|
@@ -79,7 +82,10 @@ const messageColors = {
|
|
|
79
82
|
|
|
80
83
|
// File operations
|
|
81
84
|
fileOp: (text) => colorize(text, colors.magenta),
|
|
82
|
-
compression: (text) => colorize(text, colors.cyan)
|
|
85
|
+
compression: (text) => colorize(text, colors.cyan),
|
|
86
|
+
|
|
87
|
+
// Cloudflare specific
|
|
88
|
+
cloudflare: (text) => colorize(text, colors.orange)
|
|
83
89
|
};
|
|
84
90
|
|
|
85
91
|
/**
|
|
@@ -102,7 +108,8 @@ const tags = {
|
|
|
102
108
|
warn: createTag('warn', colors.yellow),
|
|
103
109
|
error: createTag('error', colors.red),
|
|
104
110
|
match: createTag('match', colors.green),
|
|
105
|
-
compare: createTag('compare', colors.blue)
|
|
111
|
+
compare: createTag('compare', colors.blue),
|
|
112
|
+
cloudflare: createTag('cloudflare', colors.orange)
|
|
106
113
|
};
|
|
107
114
|
|
|
108
115
|
/**
|
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v1.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v1.0.82 ===
|
|
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
|
|
@@ -123,7 +123,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
|
|
|
123
123
|
const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
|
|
124
124
|
|
|
125
125
|
// --- Script Configuration & Constants ---
|
|
126
|
-
const VERSION = '1.0.
|
|
126
|
+
const VERSION = '1.0.82'; // Script version
|
|
127
127
|
|
|
128
128
|
// get startTime
|
|
129
129
|
const startTime = Date.now();
|
|
@@ -534,6 +534,8 @@ Cloudflare Protection Options:
|
|
|
534
534
|
cloudflare_parallel_detection: true/false Use parallel detection for faster Cloudflare checks (default: true)
|
|
535
535
|
cloudflare_max_retries: <number> Maximum retry attempts for Cloudflare operations (default: 3)
|
|
536
536
|
cloudflare_cache_ttl: <milliseconds> TTL for Cloudflare detection cache (default: 300000 - 5 minutes)
|
|
537
|
+
cloudflare_retry_on_error: true/false Enable retry logic for Cloudflare operations (default: true)
|
|
538
|
+
Note: Automatically detects and exits on redirect loops to prevent endless loading
|
|
537
539
|
cloudflare_retry_on_error: true/false Enable retry logic for Cloudflare operations (default: true)
|
|
538
540
|
|
|
539
541
|
FlowProxy Protection Options:
|
|
@@ -1348,10 +1350,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1348
1350
|
}
|
|
1349
1351
|
|
|
1350
1352
|
let siteCounter = 0;
|
|
1351
|
-
|
|
1352
|
-
const urls = Array.isArray(site.url) ? site.url.length : 1;
|
|
1353
|
-
return sum + urls;
|
|
1354
|
-
}, 0);
|
|
1353
|
+
// totalUrls now calculated from allTasks.length after URL flattening
|
|
1355
1354
|
|
|
1356
1355
|
// --- Global CDP (Chrome DevTools Protocol) Session --- [COMMENT RE-ADDED PREVIOUSLY, relevant to old logic]
|
|
1357
1356
|
// NOTE: This CDP session is attached to the initial browser page (e.g., about:blank).
|
|
@@ -1383,6 +1382,14 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1383
1382
|
const siteLocalhostAlt = siteConfig.localhost_0_0_0_0 === true;
|
|
1384
1383
|
const cloudflarePhishBypass = siteConfig.cloudflare_phish === true;
|
|
1385
1384
|
const cloudflareBypass = siteConfig.cloudflare_bypass === true;
|
|
1385
|
+
// Add redirect and same-page loop protection
|
|
1386
|
+
const MAX_REDIRECT_DEPTH = siteConfig.max_redirects || 10;
|
|
1387
|
+
const redirectHistory = new Set();
|
|
1388
|
+
let redirectCount = 0;
|
|
1389
|
+
const pageLoadHistory = new Map(); // Track same-page reloads
|
|
1390
|
+
const MAX_SAME_PAGE_LOADS = 3;
|
|
1391
|
+
let currentPageUrl = currentUrl;
|
|
1392
|
+
|
|
1386
1393
|
const sitePrivoxy = siteConfig.privoxy === true;
|
|
1387
1394
|
const sitePihole = siteConfig.pihole === true;
|
|
1388
1395
|
const flowproxyDetection = siteConfig.flowproxy_detection === true;
|
|
@@ -1564,6 +1571,31 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1564
1571
|
}
|
|
1565
1572
|
try {
|
|
1566
1573
|
await page.evaluateOnNewDocument(() => {
|
|
1574
|
+
// Prevent infinite reload loops
|
|
1575
|
+
let reloadCount = 0;
|
|
1576
|
+
const MAX_RELOADS = 2;
|
|
1577
|
+
const originalReload = window.location.reload;
|
|
1578
|
+
const originalReplace = window.location.replace;
|
|
1579
|
+
const originalAssign = window.location.assign;
|
|
1580
|
+
|
|
1581
|
+
window.location.reload = function() {
|
|
1582
|
+
if (++reloadCount > MAX_RELOADS) {
|
|
1583
|
+
console.log('[loop-protection] Blocked excessive reload attempt');
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
return originalReload.apply(this, arguments);
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
// Also protect against location.replace/assign to same URL
|
|
1590
|
+
const currentHref = window.location.href;
|
|
1591
|
+
window.location.replace = function(url) {
|
|
1592
|
+
if (url === currentHref && ++reloadCount > MAX_RELOADS) {
|
|
1593
|
+
console.log('[loop-protection] Blocked same-page replace attempt');
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
return originalReplace.apply(this, arguments);
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1567
1599
|
// This script intercepts and logs Fetch and XHR requests
|
|
1568
1600
|
// from within the page context at the earliest possible moment.
|
|
1569
1601
|
const originalFetch = window.fetch;
|
|
@@ -2542,11 +2574,44 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2542
2574
|
|
|
2543
2575
|
const { finalUrl, redirected, redirectChain, originalUrl, redirectDomains } = navigationResult;
|
|
2544
2576
|
|
|
2577
|
+
// Check for same-page reload loops BEFORE redirect processing
|
|
2578
|
+
const loadCount = pageLoadHistory.get(currentUrl) || 0;
|
|
2579
|
+
pageLoadHistory.set(currentUrl, loadCount + 1);
|
|
2580
|
+
|
|
2581
|
+
if (loadCount >= MAX_SAME_PAGE_LOADS) {
|
|
2582
|
+
const samePageError = `Same page loaded ${loadCount + 1} times: ${currentUrl}`;
|
|
2583
|
+
console.warn(`⚠ ${samePageError} - possible infinite reload loop`);
|
|
2584
|
+
throw new Error(`Same-page loop detected: ${samePageError}`);
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
currentPageUrl = finalUrl || currentUrl;
|
|
2588
|
+
|
|
2545
2589
|
// Handle redirect to new domain
|
|
2546
2590
|
if (redirected) {
|
|
2547
2591
|
const originalDomain = safeGetDomain(originalUrl);
|
|
2548
2592
|
const finalDomain = safeGetDomain(finalUrl);
|
|
2549
2593
|
|
|
2594
|
+
// Increment redirect counter
|
|
2595
|
+
redirectCount++;
|
|
2596
|
+
|
|
2597
|
+
// Check for redirect loops
|
|
2598
|
+
if (redirectHistory.has(finalUrl)) {
|
|
2599
|
+
const loopError = `Redirect loop detected: ${finalUrl} already visited in chain`;
|
|
2600
|
+
console.warn(`⚠ ${loopError} for ${currentUrl}`);
|
|
2601
|
+
throw new Error(loopError);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// Check redirect depth
|
|
2605
|
+
if (redirectCount > MAX_REDIRECT_DEPTH) {
|
|
2606
|
+
const depthError = `Maximum redirect depth (${MAX_REDIRECT_DEPTH}) exceeded`;
|
|
2607
|
+
console.warn(`⚠ ${depthError} for ${currentUrl}`);
|
|
2608
|
+
throw new Error(`${depthError}: ${redirectCount} redirects`);
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
// Add URLs to history
|
|
2612
|
+
redirectHistory.add(currentUrl);
|
|
2613
|
+
redirectHistory.add(finalUrl);
|
|
2614
|
+
|
|
2550
2615
|
// Add redirect destination to first-party domains immediately
|
|
2551
2616
|
if (finalDomain) {
|
|
2552
2617
|
firstPartyDomains.add(finalDomain);
|
|
@@ -2617,6 +2682,16 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2617
2682
|
|
|
2618
2683
|
// Handle all Cloudflare protections using the enhanced module
|
|
2619
2684
|
const cloudflareResult = await handleCloudflareProtection(page, currentUrl, siteConfig, forceDebug);
|
|
2685
|
+
|
|
2686
|
+
// Check if Cloudflare handling exceeded max retries and should terminate processing
|
|
2687
|
+
if (!cloudflareResult.overallSuccess &&
|
|
2688
|
+
(cloudflareResult.phishingWarning?.maxRetriesExceeded ||
|
|
2689
|
+
cloudflareResult.verificationChallenge?.maxRetriesExceeded ||
|
|
2690
|
+
cloudflareResult.phishingWarning?.loopDetected ||
|
|
2691
|
+
cloudflareResult.verificationChallenge?.loopDetected)) {
|
|
2692
|
+
throw new Error(`Cloudflare protection handling failed: ${cloudflareResult.errors.join('; ')}`);
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2620
2695
|
// Check for retry recommendations
|
|
2621
2696
|
if (cloudflareResult.errors && cloudflareResult.errors.length > 0) {
|
|
2622
2697
|
const hasRetryableErrors = cloudflareResult.errors.some(err =>
|
|
@@ -2628,6 +2703,11 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2628
2703
|
}
|
|
2629
2704
|
}
|
|
2630
2705
|
|
|
2706
|
+
// Log retry information if debug mode is enabled
|
|
2707
|
+
if (forceDebug && (cloudflareResult.phishingWarning?.attempts > 1 || cloudflareResult.verificationChallenge?.attempts > 1)) {
|
|
2708
|
+
console.log(formatLogMessage('debug', `[cloudflare] Total attempts - Phishing: ${cloudflareResult.phishingWarning?.attempts || 0}, Challenge: ${cloudflareResult.verificationChallenge?.attempts || 0}`));
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2631
2711
|
if (!cloudflareResult.overallSuccess) {
|
|
2632
2712
|
console.warn(`⚠ [cloudflare] Protection handling failed for ${currentUrl}:`);
|
|
2633
2713
|
cloudflareResult.errors.forEach(error => {
|
|
@@ -2917,57 +2997,72 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2917
2997
|
// Temporarily store the pLimit function
|
|
2918
2998
|
const originalLimit = limit;
|
|
2919
2999
|
|
|
2920
|
-
//
|
|
2921
|
-
const
|
|
2922
|
-
let currentUrlCount = 0;
|
|
2923
|
-
|
|
3000
|
+
// Create a flat list of all URL tasks with their site configs for true concurrency
|
|
3001
|
+
const allTasks = [];
|
|
2924
3002
|
for (const site of sites) {
|
|
2925
|
-
|
|
2926
3003
|
const urlsToProcess = Array.isArray(site.url) ? site.url : [site.url];
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
3004
|
+
urlsToProcess.forEach(url => {
|
|
3005
|
+
allTasks.push({
|
|
3006
|
+
url,
|
|
3007
|
+
config: site,
|
|
3008
|
+
taskId: allTasks.length // For tracking
|
|
3009
|
+
});
|
|
2930
3010
|
});
|
|
2931
|
-
currentUrlCount += urlsToProcess.length;
|
|
2932
|
-
}
|
|
2933
|
-
if (!silentMode && currentUrlCount > 0) {
|
|
2934
|
-
console.log(`\n${messageColors.processing('Processing')} ${currentUrlCount} URLs across ${siteGroups.length} sites with concurrency ${MAX_CONCURRENT_SITES}...`);
|
|
2935
|
-
if (currentUrlCount > RESOURCE_CLEANUP_INTERVAL) {
|
|
2936
|
-
console.log(messageColors.processing('Browser will restart every') + ` ~${RESOURCE_CLEANUP_INTERVAL} URLs to free resources`);
|
|
2937
|
-
}
|
|
2938
3011
|
}
|
|
3012
|
+
|
|
3013
|
+
const totalUrls = allTasks.length;
|
|
2939
3014
|
|
|
2940
3015
|
let results = [];
|
|
2941
3016
|
let processedUrlCount = 0;
|
|
2942
3017
|
let urlsSinceLastCleanup = 0;
|
|
2943
3018
|
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
3019
|
+
if (!silentMode && totalUrls > 0) {
|
|
3020
|
+
console.log(`\n${messageColors.processing('Processing')} ${totalUrls} URLs with TRUE concurrency ${MAX_CONCURRENT_SITES}...`);
|
|
3021
|
+
if (totalUrls > RESOURCE_CLEANUP_INTERVAL) {
|
|
3022
|
+
console.log(messageColors.processing('Browser will restart every') + ` ~${RESOURCE_CLEANUP_INTERVAL} URLs to free resources`);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
// Hang detection for debugging concurrency issues
|
|
3027
|
+
let currentBatchInfo = { batchStart: 0, batchSize: 0 };
|
|
3028
|
+
const hangDetectionInterval = setInterval(() => {
|
|
3029
|
+
const currentBatch = Math.floor(currentBatchInfo.batchStart / RESOURCE_CLEANUP_INTERVAL) + 1;
|
|
3030
|
+
const totalBatches = Math.ceil(totalUrls / RESOURCE_CLEANUP_INTERVAL);
|
|
3031
|
+
console.log(formatLogMessage('debug', `[HANG CHECK] Processed: ${processedUrlCount}/${totalUrls} URLs, Batch: ${currentBatch}/${totalBatches}, Current batch size: ${currentBatchInfo.batchSize}`));
|
|
3032
|
+
console.log(formatLogMessage('debug', `[HANG CHECK] URLs since cleanup: ${urlsSinceLastCleanup}, Recent failures: ${results.slice(-3).filter(r => !r.success).length}/3`));
|
|
3033
|
+
}, 30000); // Check every 30 seconds
|
|
3034
|
+
|
|
3035
|
+
// Process URLs in batches to maintain concurrency while allowing browser restarts
|
|
3036
|
+
for (let batchStart = 0; batchStart < totalUrls; batchStart += RESOURCE_CLEANUP_INTERVAL) {
|
|
3037
|
+
const batchEnd = Math.min(batchStart + RESOURCE_CLEANUP_INTERVAL, totalUrls);
|
|
3038
|
+
const currentBatch = allTasks.slice(batchStart, batchEnd);
|
|
2947
3039
|
|
|
2948
3040
|
// Check browser health before processing each site
|
|
2949
3041
|
const healthCheck = await monitorBrowserHealth(browser, {}, {
|
|
2950
|
-
siteIndex,
|
|
2951
|
-
totalSites:
|
|
3042
|
+
siteIndex: Math.floor(batchStart / RESOURCE_CLEANUP_INTERVAL),
|
|
3043
|
+
totalSites: Math.ceil(totalUrls / RESOURCE_CLEANUP_INTERVAL),
|
|
2952
3044
|
urlsSinceCleanup: urlsSinceLastCleanup,
|
|
2953
3045
|
cleanupInterval: RESOURCE_CLEANUP_INTERVAL,
|
|
2954
3046
|
forceDebug,
|
|
2955
3047
|
silentMode
|
|
2956
3048
|
});
|
|
2957
3049
|
|
|
2958
|
-
//
|
|
3050
|
+
// Check if browser was unhealthy during recent processing
|
|
2959
3051
|
const recentResults = results.slice(-3);
|
|
2960
3052
|
const hasRecentFailures = recentResults.filter(r => !r.success).length >= 2;
|
|
2961
|
-
const shouldRestartFromFailures = hasRecentFailures && urlsSinceLastCleanup > 3;
|
|
3053
|
+
const shouldRestartFromFailures = hasRecentFailures && urlsSinceLastCleanup > 3;
|
|
2962
3054
|
|
|
2963
|
-
const
|
|
3055
|
+
const batchSize = currentBatch.length;
|
|
2964
3056
|
|
|
3057
|
+
// Update hang detection info
|
|
3058
|
+
currentBatchInfo = { batchStart, batchSize };
|
|
3059
|
+
|
|
2965
3060
|
// Check if processing this entire site would exceed cleanup interval OR health check suggests restart
|
|
2966
|
-
const wouldExceedLimit = urlsSinceLastCleanup +
|
|
2967
|
-
const
|
|
3061
|
+
const wouldExceedLimit = urlsSinceLastCleanup + batchSize >= Math.min(RESOURCE_CLEANUP_INTERVAL, 100);
|
|
3062
|
+
const isNotLastBatch = batchEnd < totalUrls;
|
|
2968
3063
|
|
|
2969
3064
|
// Restart browser if we've processed enough URLs, health check suggests it, and this isn't the last site
|
|
2970
|
-
if ((wouldExceedLimit || healthCheck.shouldRestart || shouldRestartFromFailures) && urlsSinceLastCleanup > 0 &&
|
|
3065
|
+
if ((wouldExceedLimit || healthCheck.shouldRestart || shouldRestartFromFailures) && urlsSinceLastCleanup > 0 && isNotLastBatch) {
|
|
2971
3066
|
|
|
2972
3067
|
let restartReason = 'Unknown';
|
|
2973
3068
|
if (healthCheck.shouldRestart) {
|
|
@@ -3023,7 +3118,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3023
3118
|
|
|
3024
3119
|
// Create new browser for next batch
|
|
3025
3120
|
browser = await createBrowser();
|
|
3026
|
-
if (forceDebug) console.log(formatLogMessage('debug', `New browser instance created for
|
|
3121
|
+
if (forceDebug) console.log(formatLogMessage('debug', `New browser instance created for batch ${Math.floor(batchStart / RESOURCE_CLEANUP_INTERVAL) + 1}`));
|
|
3027
3122
|
|
|
3028
3123
|
// Reset cleanup counter and add delay
|
|
3029
3124
|
urlsSinceLastCleanup = 0;
|
|
@@ -3031,19 +3126,29 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3031
3126
|
}
|
|
3032
3127
|
|
|
3033
3128
|
if (forceDebug) {
|
|
3034
|
-
console.log(formatLogMessage('debug', `Processing
|
|
3129
|
+
console.log(formatLogMessage('debug', `Processing batch ${Math.floor(batchStart / RESOURCE_CLEANUP_INTERVAL) + 1}: ${batchSize} URL(s) (total processed: ${processedUrlCount})`));
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
// Log start of concurrent processing for hang detection
|
|
3133
|
+
if (forceDebug) {
|
|
3134
|
+
console.log(formatLogMessage('debug', `[CONCURRENCY] Starting ${batchSize} concurrent tasks with limit ${MAX_CONCURRENT_SITES}`));
|
|
3035
3135
|
}
|
|
3036
3136
|
|
|
3037
|
-
// Create tasks with current browser instance and process them
|
|
3038
|
-
const
|
|
3039
|
-
const
|
|
3137
|
+
// Create tasks with current browser instance and process them with TRUE concurrency
|
|
3138
|
+
const batchTasks = currentBatch.map(task => originalLimit(() => processUrl(task.url, task.config, browser)));
|
|
3139
|
+
const batchResults = await Promise.all(batchTasks);
|
|
3040
3140
|
|
|
3041
3141
|
// Check if any results indicate immediate restart is needed
|
|
3042
|
-
const needsImmediateRestart =
|
|
3142
|
+
const needsImmediateRestart = batchResults.some(r => r.needsImmediateRestart);
|
|
3143
|
+
|
|
3144
|
+
// Log completion of concurrent processing
|
|
3145
|
+
if (forceDebug) {
|
|
3146
|
+
console.log(formatLogMessage('debug', `[CONCURRENCY] Completed ${batchSize} concurrent tasks, ${batchResults.filter(r => r.success).length} successful`));
|
|
3147
|
+
}
|
|
3043
3148
|
|
|
3044
3149
|
// Enhanced error reporting for Puppeteer 23.x
|
|
3045
3150
|
if (forceDebug) {
|
|
3046
|
-
const errorSummary =
|
|
3151
|
+
const errorSummary = batchResults.reduce((acc, result) => {
|
|
3047
3152
|
if (!result.success && result.errorType) {
|
|
3048
3153
|
acc[result.errorType] = (acc[result.errorType] || 0) + 1;
|
|
3049
3154
|
}
|
|
@@ -3051,20 +3156,20 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3051
3156
|
}, {});
|
|
3052
3157
|
|
|
3053
3158
|
if (Object.keys(errorSummary).length > 0) {
|
|
3054
|
-
console.log(formatLogMessage('debug', `
|
|
3159
|
+
console.log(formatLogMessage('debug', `Batch ${Math.floor(batchStart / RESOURCE_CLEANUP_INTERVAL) + 1} error summary:`));
|
|
3055
3160
|
Object.entries(errorSummary).forEach(([errorType, count]) => {
|
|
3056
3161
|
console.log(formatLogMessage('debug', ` ${errorType}: ${count} error(s)`));
|
|
3057
3162
|
});
|
|
3058
3163
|
}
|
|
3059
3164
|
}
|
|
3060
3165
|
|
|
3061
|
-
results.push(...
|
|
3166
|
+
results.push(...batchResults);
|
|
3062
3167
|
|
|
3063
|
-
processedUrlCount +=
|
|
3064
|
-
urlsSinceLastCleanup +=
|
|
3168
|
+
processedUrlCount += batchSize;
|
|
3169
|
+
urlsSinceLastCleanup += batchSize;
|
|
3065
3170
|
|
|
3066
3171
|
// Force browser restart if any URL had critical errors
|
|
3067
|
-
if (needsImmediateRestart &&
|
|
3172
|
+
if (needsImmediateRestart && isNotLastBatch) {
|
|
3068
3173
|
if (!silentMode) {
|
|
3069
3174
|
console.log(`\n${messageColors.fileOp('🔄 Emergency browser restart:')} Critical browser errors detected`);
|
|
3070
3175
|
}
|
|
@@ -3084,7 +3189,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3084
3189
|
try {
|
|
3085
3190
|
// Enhanced emergency restart for Puppeteer 23.x
|
|
3086
3191
|
if (forceDebug) {
|
|
3087
|
-
console.log(formatLogMessage('debug', `Emergency restart triggered by errors: ${
|
|
3192
|
+
console.log(formatLogMessage('debug', `Emergency restart triggered by errors: ${batchResults.filter(r => r.needsImmediateRestart).map(r => r.error).join(', ')}`));
|
|
3088
3193
|
}
|
|
3089
3194
|
|
|
3090
3195
|
// Try to gracefully close all pages first
|
|
@@ -3113,6 +3218,9 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3113
3218
|
}
|
|
3114
3219
|
}
|
|
3115
3220
|
|
|
3221
|
+
// Clear hang detection interval
|
|
3222
|
+
clearInterval(hangDetectionInterval);
|
|
3223
|
+
|
|
3116
3224
|
// === POST-SCAN PROCESSING ===
|
|
3117
3225
|
// Clean up first-party domains and validate results
|
|
3118
3226
|
if (!dryRunMode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.82",
|
|
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": {
|