@fanboynz/network-scanner 2.0.4 → 2.0.5

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.
@@ -9,7 +9,7 @@ const { formatLogMessage, messageColors } = require('./colorize');
9
9
  // Window cleanup delay constant
10
10
  const WINDOW_CLEANUP_DELAY_MS = 15000;
11
11
  // window_clean REALTIME
12
- const REALTIME_CLEANUP_BUFFER_MS = 15000; // Additional buffer time after site delay. Delay increased to fix missing hits.
12
+ const REALTIME_CLEANUP_BUFFER_MS = 35000; // Additional buffer time after site delay (increased for Cloudflare)
13
13
  const REALTIME_CLEANUP_THRESHOLD = 8; // Default number of pages to keep
14
14
  const REALTIME_CLEANUP_MIN_PAGES = 3; // Minimum pages before cleanup kicks in
15
15
 
@@ -270,14 +270,14 @@ function updatePageUsage(page, isProcessing = false) {
270
270
 
271
271
  /**
272
272
  * Performs realtime window cleanup - removes oldest pages when threshold is exceeded
273
- * Waits for site delay + 3 seconds before cleanup to ensure delayed requests are captured
273
+ * Waits for site delay + buffer before cleanup, with extended buffer for Cloudflare sites
274
274
  * @param {import('puppeteer').Browser} browserInstance - Browser instance
275
275
  * @param {number} threshold - Maximum number of pages to keep (default: 8)
276
276
  * @param {boolean} forceDebug - Debug logging flag
277
- * @param {number} siteDelay - Current site's delay value in milliseconds (default: 4000)
277
+ * @param {number} totalDelay - Total delay including site delay and appropriate buffer (default: 4000 + 15000)
278
278
  * @returns {Promise<Object>} Cleanup results
279
279
  */
280
- async function performRealtimeWindowCleanup(browserInstance, threshold = REALTIME_CLEANUP_THRESHOLD, forceDebug, siteDelay = 4000) {
280
+ async function performRealtimeWindowCleanup(browserInstance, threshold = REALTIME_CLEANUP_THRESHOLD, forceDebug, totalDelay = 19000) {
281
281
  try {
282
282
  const allPages = await browserInstance.pages();
283
283
 
@@ -289,11 +289,11 @@ async function performRealtimeWindowCleanup(browserInstance, threshold = REALTIM
289
289
  return { success: true, closedCount: 0, totalPages: allPages.length, reason: 'below_threshold' };
290
290
  }
291
291
 
292
- // Calculate cleanup delay: site delay + 3 second buffer
293
- const cleanupDelay = siteDelay + REALTIME_CLEANUP_BUFFER_MS;
292
+ // Use the provided total delay (already includes appropriate buffer)
293
+ const cleanupDelay = totalDelay;
294
294
 
295
295
  if (forceDebug) {
296
- console.log(formatLogMessage('debug', `[realtime_cleanup] Waiting ${cleanupDelay}ms (site delay: ${siteDelay}ms + ${REALTIME_CLEANUP_BUFFER_MS}ms buffer) before cleanup (threshold: ${threshold})`));
296
+ console.log(formatLogMessage('debug', `[realtime_cleanup] Waiting ${cleanupDelay}ms before cleanup (threshold: ${threshold})`));
297
297
  }
298
298
  await new Promise(resolve => setTimeout(resolve, cleanupDelay));
299
299
 
@@ -999,4 +999,4 @@ if (originalPageClose) {
999
999
  }
1000
1000
  return originalPageClose.apply(this, args);
1001
1001
  };
1002
- }
1002
+ }
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.6.2 - Further detached Frame fixes
3
4
  * Version: 2.6.1 - timeoutId is not defined & race condition fix
4
5
  * Version: 2.6.0 - Memory leak fixes and timeout cleanup
5
6
  * Version: 2.5.0 - Fix Frame Lifecycle issue, Timing and Race condition
@@ -26,11 +27,11 @@ const CLOUDFLARE_MODULE_VERSION = '2.6.1';
26
27
  * All values tuned for maximum scanning speed while maintaining functionality
27
28
  */
28
29
  const TIMEOUTS = {
29
- PAGE_EVALUATION: 8000, // Standard page evaluation timeout
30
- PAGE_EVALUATION_SAFE: 10000, // Safe page evaluation with extra buffer
30
+ PAGE_EVALUATION: 12000, // Standard page evaluation timeout
31
+ PAGE_EVALUATION_SAFE: 12000, // Safe page evaluation with extra buffer
31
32
  PHISHING_CLICK: 3000, // Timeout for clicking phishing continue button
32
33
  PHISHING_NAVIGATION: 8000, // Wait for navigation after phishing bypass
33
- JS_CHALLENGE_BUFFER: 30000, // JS challenge with safety buffer
34
+ JS_CHALLENGE_BUFFER: 26000, // JS challenge with safety buffer
34
35
  TURNSTILE_COMPLETION: 20000, // Turnstile completion check
35
36
  TURNSTILE_COMPLETION_BUFFER: 25000, // Turnstile completion with buffer
36
37
  CLICK_TIMEOUT: 5000, // Standard click operation timeout
@@ -50,13 +51,13 @@ const TIMEOUTS = {
50
51
 
51
52
  // Fast timeout constants - optimized for speed
52
53
  const FAST_TIMEOUTS = {
53
- QUICK_DETECTION: 2000, // Fast Cloudflare detection
54
+ QUICK_DETECTION: 4000, // Fast Cloudflare detection
54
55
  PHISHING_WAIT: 1000, // Fast phishing check
55
56
  CHALLENGE_WAIT: 500, // Fast challenge detection
56
57
  ELEMENT_INTERACTION_DELAY: 250, // Fast element interactions
57
- SELECTOR_WAIT: 1500, // Fast selector waits
58
+ SELECTOR_WAIT: 3000, // Fast selector waits
58
59
  TURNSTILE_OPERATION: 6000, // Fast Turnstile operations
59
- JS_CHALLENGE: 22000, // Fast JS challenge completion
60
+ JS_CHALLENGE: 19000, // Fast JS challenge completion
60
61
  CHALLENGE_SOLVING: 30000, // Fast overall challenge solving
61
62
  CHALLENGE_COMPLETION: 8000 // Fast completion check
62
63
  };
@@ -323,19 +324,64 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
323
324
  let timeoutId = null;
324
325
 
325
326
  try {
326
- // Validate page state before evaluation
327
+ // Multi-layered page state validation
327
328
  if (page.isClosed()) {
328
- throw new Error('Page is closed');
329
+ throw new Error('Page is closed or invalid');
329
330
  }
330
331
 
332
+ // Check if page is still navigating or has valid context
333
+ let currentUrl;
334
+ try {
335
+ currentUrl = await page.url();
336
+ if (!currentUrl || currentUrl === 'about:blank') {
337
+ throw new Error('Page URL is invalid or blank');
338
+ }
339
+ } catch (urlError) {
340
+ throw new Error('Page URL access failed - likely detached');
341
+ }
342
+
343
+ // Quick execution context validation with timeout
344
+ const contextValid = await Promise.race([
345
+ page.evaluate(() => {
346
+ try {
347
+ // Quick context validation
348
+ if (typeof window === 'undefined' || !document) {
349
+ return false;
350
+ }
351
+ // Check if document is ready for interaction
352
+ if (document.readyState === 'uninitialized') {
353
+ return false;
354
+ }
355
+ return true;
356
+ } catch (e) {
357
+ return false;
358
+ }
359
+ }),
360
+ new Promise((_, reject) => {
361
+ setTimeout(() => reject(new Error('Context validation timeout')), 3500);
362
+ })
363
+ ]).catch(() => false);
364
+
365
+ if (!contextValid) {
366
+ throw new Error('Page execution context is invalid');
367
+ }
331
368
 
332
369
  const result = await Promise.race([
333
370
  page.evaluate(() => {
334
- // Validate execution context inside evaluation to prevent race
335
- if (typeof window === 'undefined' || !document) {
336
- throw new Error('Execution context invalid');
371
+ // Additional runtime validation inside evaluation
372
+ try {
373
+ if (typeof window === 'undefined' || !document) {
374
+ throw new Error('Execution context invalid during evaluation');
375
+ }
376
+ return func();
377
+ } catch (evalError) {
378
+ // Return error info instead of throwing to avoid unhandled promise rejections
379
+ return {
380
+ __evaluation_error: true,
381
+ message: evalError.message,
382
+ type: 'evaluation_error'
383
+ };
337
384
  }
338
- return (func)();
339
385
  }),
340
386
  new Promise((_, reject) => {
341
387
  timeoutId = setTimeout(() => reject(new Error('Page evaluation timeout')), timeout);
@@ -346,7 +392,12 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
346
392
  if (timeoutId) {
347
393
  clearTimeout(timeoutId);
348
394
  }
349
-
395
+
396
+ // Check if evaluation returned an error
397
+ if (result && result.__evaluation_error) {
398
+ throw new Error(`Evaluation failed: ${result.message}`);
399
+ }
400
+
350
401
  if (forceDebug && attempt > 1) {
351
402
  console.log(formatLogMessage('cloudflare', `Page evaluation succeeded on attempt ${attempt}`));
352
403
  }
@@ -370,23 +421,19 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
370
421
  if (forceDebug) {
371
422
  console.warn(formatLogMessage('cloudflare', `Detached frame detected on attempt ${attempt}/${maxRetries} - using longer delay`));
372
423
  }
373
- // For detached frames, wait longer and don't retry as aggressively
374
- await new Promise(resolve => setTimeout(resolve, 2000)); // Longer delay
424
+ // For detached frames, wait longer
425
+ await new Promise(resolve => setTimeout(resolve, 3000)); // Longer delay
426
+
427
+ // For detached frames, only retry once more
428
+ if (attempt >= 2) {
429
+ break;
430
+ }
375
431
  continue;
376
432
  }
377
433
 
378
434
  // Don't retry if error type is not retryable or if it's the last attempt
379
435
  if (!RETRY_CONFIG.retryableErrors.includes(errorType) || attempt === maxRetries) {
380
- return {
381
- isChallengePresent: false,
382
- isPhishingWarning: false,
383
- isTurnstile: false,
384
- isJSChallenge: false,
385
- isChallengeCompleted: false,
386
- error: error.message,
387
- errorType: errorType,
388
- attempts: attempt
389
- };
436
+ break;
390
437
  }
391
438
 
392
439
  // Wait before retrying with exponential backoff
@@ -394,19 +441,7 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
394
441
  }
395
442
  }
396
443
 
397
- // If all retries failed due to detached frames, return safe defaults
398
- if (lastError?.message.includes('detached Frame') || lastError?.message.includes('Attempted to use detached')) {
399
- return {
400
- isChallengePresent: false,
401
- isPhishingWarning: false,
402
- isTurnstile: false,
403
- isJSChallenge: false,
404
- isChallengeCompleted: false,
405
- error: 'Frame detached - skipping evaluation',
406
- errorType: ERROR_TYPES.DETACHED_FRAME,
407
- attempts: maxRetries
408
- };
409
- }
444
+ // Return safe defaults if all retries failed
410
445
 
411
446
  return {
412
447
  isChallengePresent: false,
@@ -1845,4 +1880,4 @@ module.exports = {
1845
1880
  detectChallengeLoop,
1846
1881
  // Memory management
1847
1882
  cleanup
1848
- };
1883
+ };
package/nwss.js CHANGED
@@ -1,4 +1,4 @@
1
- // === Network scanner script (nwss.js) v2.0.4 ===
1
+ // === Network scanner script (nwss.js) v2.0.5 ===
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
@@ -127,7 +127,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
127
127
  const { monitorBrowserHealth, isBrowserHealthy, isQuicklyResponsive, performGroupWindowCleanup, performRealtimeWindowCleanup, trackPageForRealtime, updatePageUsage } = require('./lib/browserhealth');
128
128
 
129
129
  // --- Script Configuration & Constants ---
130
- const VERSION = '2.0.4'; // Script version
130
+ const VERSION = '2.0.5'; // Script version
131
131
 
132
132
  // get startTime
133
133
  const startTime = Date.now();
@@ -1541,10 +1541,17 @@ function setupFrameHandling(page, forceDebug) {
1541
1541
  ? siteConfig.window_cleanup_threshold
1542
1542
  : REALTIME_CLEANUP_THRESHOLD;
1543
1543
 
1544
- // Get the site's delay value for cleanup timing
1544
+ // Calculate appropriate delay based on site configuration
1545
1545
  const siteDelay = siteConfig.delay || 4000;
1546
+ const hasCloudflareConfig = siteConfig.cloudflare_bypass || siteConfig.cloudflare_phish;
1547
+ const bufferTime = hasCloudflareConfig ? 23000 : REALTIME_CLEANUP_BUFFER_MS; // 23s for Cloudflare, 15s for normal
1548
+ const totalDelay = siteDelay + bufferTime;
1546
1549
 
1547
- const realtimeResult = await performRealtimeWindowCleanup(browserInstance, threshold, forceDebug, siteDelay);
1550
+ if (forceDebug && hasCloudflareConfig) {
1551
+ console.log(formatLogMessage('debug', `[realtime_cleanup] Using extended delay for Cloudflare site: ${totalDelay}ms (${siteDelay}ms + ${bufferTime}ms CF buffer)`));
1552
+ }
1553
+
1554
+ const realtimeResult = await performRealtimeWindowCleanup(browserInstance, threshold, forceDebug, totalDelay);
1548
1555
  if (realtimeResult.success && realtimeResult.closedCount > 0 && forceDebug) {
1549
1556
  console.log(formatLogMessage('debug', `[realtime_cleanup] Cleaned ${realtimeResult.closedCount} old pages, ${realtimeResult.remainingPages} remaining`));
1550
1557
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanboynz/network-scanner",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
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": {