@fanboynz/network-scanner 2.0.59 → 2.0.60

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/nwss.js CHANGED
@@ -32,7 +32,7 @@ const { shouldIgnoreSimilarDomain, calculateSimilarity } = require('./lib/ignore
32
32
  // Graceful exit
33
33
  const { handleBrowserExit, cleanupChromeTempFiles } = require('./lib/browserexit');
34
34
  // Whois & Dig
35
- const { createNetToolsHandler, createEnhancedDryRunCallback, validateWhoisAvailability, validateDigAvailability } = require('./lib/nettools');
35
+ const { createNetToolsHandler, createEnhancedDryRunCallback, validateWhoisAvailability, validateDigAvailability, enableDiskCache, getDnsCacheStats } = require('./lib/nettools');
36
36
  // File compare
37
37
  const { loadComparisonRules, filterUniqueRules } = require('./lib/compare');
38
38
  // CDP functionality
@@ -208,6 +208,12 @@ if (localhostIndex !== -1) {
208
208
  localhostIP = args[localhostIndex].includes('=') ? args[localhostIndex].split('=')[1] : '127.0.0.1';
209
209
  }
210
210
  const keepBrowserOpen = args.includes('--keep-open');
211
+ const loadExtensionPaths = [];
212
+ args.forEach((arg, idx) => {
213
+ if (arg === '--load-extension' && args[idx + 1] && !args[idx + 1].startsWith('--')) {
214
+ loadExtensionPaths.push(path.resolve(args[idx + 1]));
215
+ }
216
+ });
211
217
  const disableInteract = args.includes('--no-interact');
212
218
  const globalGhostCursor = args.includes('--ghost-cursor');
213
219
  const plainOutput = args.includes('--plain');
@@ -229,6 +235,8 @@ let cleanRules = args.includes('--clean-rules');
229
235
  const clearCache = args.includes('--clear-cache');
230
236
  const ignoreCache = args.includes('--ignore-cache');
231
237
  const cacheRequests = args.includes('--cache-requests');
238
+ const dnsCacheMode = args.includes('--dns-cache');
239
+ if (dnsCacheMode) enableDiskCache();
232
240
 
233
241
  let validateRulesFile = null;
234
242
  const validateRulesIndex = args.findIndex(arg => arg === '--validate-rules');
@@ -499,22 +507,38 @@ if (validateRules || validateRulesFile) {
499
507
  }
500
508
  }
501
509
 
502
- // Parse --block-ads argument for request-level ad blocking
510
+ // Parse --block-ads argument for request-level ad blocking (supports comma-separated lists)
503
511
  const blockAdsIndex = args.findIndex(arg => arg.startsWith('--block-ads'));
504
512
  if (blockAdsIndex !== -1) {
505
- const rulesFile = args[blockAdsIndex].includes('=')
506
- ? args[blockAdsIndex].split('=')[1]
513
+ const rulesArg = args[blockAdsIndex].includes('=')
514
+ ? args[blockAdsIndex].split('=')[1]
507
515
  : args[blockAdsIndex + 1];
508
-
509
- if (!rulesFile || !fs.existsSync(rulesFile)) {
510
- console.log(`Error: Adblock rules file not found: ${rulesFile || '(not specified)'}`);
516
+
517
+ if (!rulesArg) {
518
+ console.log('Error: No adblock rules file specified');
511
519
  process.exit(1);
512
520
  }
513
-
521
+
522
+ const rulesFiles = rulesArg.split(',').map(f => f.trim()).filter(f => f);
523
+ for (const file of rulesFiles) {
524
+ if (!fs.existsSync(file)) {
525
+ console.log(`Error: Adblock rules file not found: ${file}`);
526
+ process.exit(1);
527
+ }
528
+ }
529
+
530
+ // Concatenate multiple lists into a single temp file for the parser
531
+ let rulesFile = rulesFiles[0];
532
+ if (rulesFiles.length > 1) {
533
+ rulesFile = path.join(os.tmpdir(), `nwss-adblock-combined-${Date.now()}.txt`);
534
+ const combined = rulesFiles.map(f => fs.readFileSync(f, 'utf-8')).join('\n');
535
+ fs.writeFileSync(rulesFile, combined);
536
+ }
537
+
514
538
  adblockEnabled = true;
515
539
  adblockMatcher = parseAdblockRules(rulesFile, { enableLogging: forceDebug });
516
540
  const stats = adblockMatcher.getStats();
517
- if (!silentMode) console.log(messageColors.success(`Adblock enabled: Loaded ${stats.total} blocking rules from ${rulesFile}`));
541
+ if (!silentMode) console.log(messageColors.success(`Adblock enabled: Loaded ${stats.total} blocking rules from ${rulesFiles.length} list${rulesFiles.length > 1 ? 's' : ''}`));
518
542
  }
519
543
 
520
544
  if (args.includes('--help') || args.includes('-h')) {
@@ -556,6 +580,7 @@ General Options:
556
580
  --headful Launch browser with GUI (not headless)
557
581
  --keep-open Keep browser open after scan completes (use with --headful)
558
582
  --use-puppeteer-core Use puppeteer-core with system Chrome instead of bundled Chromium
583
+ --load-extension <path> Load unpacked Chrome extension from directory
559
584
  --cdp Enable Chrome DevTools Protocol logging (now per-page if enabled)
560
585
  --remove-dupes Remove duplicate domains from output (only with -o)
561
586
  --eval-on-doc Globally enable evaluateOnNewDocument() for Fetch/XHR interception
@@ -567,6 +592,7 @@ General Options:
567
592
 
568
593
  Validation Options:
569
594
  --cache-requests Cache HTTP requests to avoid re-requesting same URLs within scan
595
+ --dns-cache Persist dig/whois results to disk between runs (3hr/4hr TTL)
570
596
  --validate-config Validate config.json file and exit
571
597
  --validate-rules [file] Validate rule file format (uses --output/--compare files if no file specified)
572
598
  --clean-rules [file] Clean rule files by removing invalid lines and optionally duplicates (uses --output/--compare files if no file specified)
@@ -583,6 +609,7 @@ Global config.json options:
583
609
  ignore_similar_ignored_domains: true/false Ignore domains similar to ignoreDomains list (default: true)
584
610
  max_concurrent_sites: 8 Maximum concurrent site processing (1-50, default: 8)
585
611
  resource_cleanup_interval: 80 Browser restart interval in URLs processed (1-1000, default: 80)
612
+ disable_ad_tagging: true/false Disable Chrome AdTagging to prevent ad frame throttling (default: true)
586
613
 
587
614
  Per-site config.json options:
588
615
  url: "site" or ["site1", "site2"] Single URL or list of URLs
@@ -748,7 +775,8 @@ const {
748
775
  whois_server_mode = 'random',
749
776
  ignore_similar = true,
750
777
  ignore_similar_threshold = 80,
751
- ignore_similar_ignored_domains = true,
778
+ ignore_similar_ignored_domains = true,
779
+ disable_ad_tagging = true,
752
780
  max_concurrent_sites = 6,
753
781
  resource_cleanup_interval = 80,
754
782
  comments: globalComments,
@@ -1460,7 +1488,7 @@ function setupFrameHandling(page, forceDebug) {
1460
1488
  '--disable-blink-features=AutomationControlled',
1461
1489
  '--no-first-run',
1462
1490
  '--disable-default-apps',
1463
- '--disable-component-extensions-with-background-pages',
1491
+ ...(keepBrowserOpen ? [] : ['--disable-component-extensions-with-background-pages']),
1464
1492
  // HIGH IMPACT: Normal Chrome behavior simulation
1465
1493
  '--password-store=basic',
1466
1494
  '--use-mock-keychain',
@@ -1474,30 +1502,29 @@ function setupFrameHandling(page, forceDebug) {
1474
1502
  '--disable-background-downloads',
1475
1503
  // DISK I/O REDUCTION: Eliminate unnecessary Chrome disk writes
1476
1504
  '--disable-breakpad', // No crash dump files
1477
- '--disable-component-update', // No component update downloads
1505
+ ...(keepBrowserOpen ? [] : ['--disable-component-update']), // No component update downloads
1478
1506
  '--disable-logging', // No Chrome internal log files
1479
1507
  '--log-level=3', // Fatal errors only (suppresses verbose disk logging)
1480
1508
  '--no-service-autorun', // No background service disk activity
1481
1509
  '--disable-domain-reliability', // No reliability monitor disk writes
1482
- // PERFORMANCE: Enhanced Puppeteer 23.x optimizations
1483
- '--disable-features=AudioServiceOutOfProcess,VizDisplayCompositor',
1484
- '--disable-features=TranslateUI,BlinkGenPropertyTrees,Translate',
1485
- '--disable-features=BackForwardCache,AcceptCHFrame',
1510
+ // PERFORMANCE: Disable non-essential Chrome features in a single flag
1511
+ // IMPORTANT: Chrome only reads the LAST --disable-features flag, so combine all into one
1512
+ `--disable-features=AudioServiceOutOfProcess,VizDisplayCompositor,TranslateUI,BlinkGenPropertyTrees,Translate,BackForwardCache,AcceptCHFrame,SafeBrowsing,HttpsFirstBalancedModeAutoEnable,site-per-process,PaintHolding${disable_ad_tagging ? ',AdTagging' : ''}`,
1486
1513
  '--disable-ipc-flooding-protection',
1487
1514
  '--aggressive-cache-discard',
1488
1515
  '--memory-pressure-off',
1489
1516
  '--max_old_space_size=2048', // V8 heap limit
1490
1517
  '--disable-prompt-on-repost', // Fixes form popup on page reload
1491
- '--disable-background-networking',
1518
+ ...(keepBrowserOpen ? [] : ['--disable-background-networking']),
1492
1519
  '--no-sandbox',
1493
1520
  '--disable-setuid-sandbox',
1494
- '--disable-features=SafeBrowsing',
1495
1521
  '--disable-dev-shm-usage',
1496
- '--disable-sync',
1522
+ ...(keepBrowserOpen ? [] : ['--disable-sync']),
1497
1523
  '--mute-audio',
1498
1524
  '--disable-translate',
1499
1525
  '--window-size=1920,1080',
1500
- '--disable-extensions',
1526
+ ...(keepBrowserOpen ? [] : ['--disable-extensions', '--disable-component-update']),
1527
+ ...(loadExtensionPaths.length ? [`--load-extension=${loadExtensionPaths.join(',')}`, '--enable-extensions'] : []),
1501
1528
  '--no-default-browser-check',
1502
1529
  '--safebrowsing-disable-auto-update',
1503
1530
  '--ignore-ssl-errors',
@@ -1506,18 +1533,15 @@ function setupFrameHandling(page, forceDebug) {
1506
1533
  '--ignore-certificate-errors-ca-list',
1507
1534
  '--disable-web-security',
1508
1535
  '--allow-running-insecure-content',
1509
- '--disable-features=HttpsFirstBalancedModeAutoEnable',
1510
1536
  // Puppeteer 23.x: Enhanced performance and stability args
1511
1537
  '--disable-renderer-backgrounding',
1512
1538
  '--disable-backgrounding-occluded-windows',
1513
1539
  '--disable-background-timer-throttling',
1514
- '--disable-features=site-per-process', // Better for single-site scanning
1515
1540
  '--no-zygote', // Better process isolation
1516
1541
  // PERFORMANCE: Process and memory reduction for high concurrency
1517
1542
  '--renderer-process-limit=10', // Cap renderer processes (default: unlimited)
1518
1543
  '--disable-accelerated-2d-canvas', // Software canvas only (we spoof it anyway)
1519
1544
  '--disable-hang-monitor', // Remove per-renderer hang check overhead
1520
- '--disable-features=PaintHolding', // Don't hold frames in renderer memory
1521
1545
  '--js-flags=--max-old-space-size=512', // Cap V8 heap per renderer to 512MB
1522
1546
  ...extraArgs,
1523
1547
  ],
@@ -4601,9 +4625,19 @@ function setupFrameHandling(page, forceDebug) {
4601
4625
  // Keep browser open if --keep-open flag is set (useful with --headful for inspection)
4602
4626
  if (keepBrowserOpen && !launchHeadless) {
4603
4627
  console.log(messageColors.info('Browser kept open.') + ' Close the browser window or press Ctrl+C to exit.');
4628
+ const cleanup = async () => {
4629
+ try {
4630
+ if (browser.isConnected()) await browser.close();
4631
+ } catch {}
4632
+ process.exit(0);
4633
+ };
4634
+ process.on('SIGINT', cleanup);
4635
+ process.on('SIGTERM', cleanup);
4604
4636
  await new Promise((resolve) => {
4605
4637
  browser.on('disconnected', resolve);
4606
4638
  });
4639
+ process.removeListener('SIGINT', cleanup);
4640
+ process.removeListener('SIGTERM', cleanup);
4607
4641
  }
4608
4642
 
4609
4643
  // Perform comprehensive final cleanup using enhanced browserexit module
@@ -4680,6 +4714,24 @@ function setupFrameHandling(page, forceDebug) {
4680
4714
  if (ignoreCache && forceDebug) {
4681
4715
  console.log(messageColors.info('Cache:') + ` Smart caching was disabled`);
4682
4716
  }
4717
+ // DNS cache statistics
4718
+ const dnsStats = getDnsCacheStats();
4719
+ if (dnsStats.digHits + dnsStats.digMisses > 0 || dnsStats.whoisHits + dnsStats.whoisMisses > 0) {
4720
+ const parts = [];
4721
+ if (dnsStats.digHits + dnsStats.digMisses > 0) {
4722
+ parts.push(`${messageColors.success(dnsStats.digHits)} dig cached, ${messageColors.timing(dnsStats.digMisses)} fresh`);
4723
+ }
4724
+ if (dnsStats.whoisHits + dnsStats.whoisMisses > 0) {
4725
+ parts.push(`${messageColors.success(dnsStats.whoisHits)} whois cached, ${messageColors.timing(dnsStats.whoisMisses)} fresh`);
4726
+ }
4727
+ console.log(messageColors.info('DNS cache:') + ` ${parts.join(' | ')}`);
4728
+ if (dnsStats.freshDig.length > 0) {
4729
+ console.log(messageColors.info(' Fresh dig:') + ` ${dnsStats.freshDig.join(', ')}`);
4730
+ }
4731
+ if (dnsStats.freshWhois.length > 0) {
4732
+ console.log(messageColors.info(' Fresh whois:') + ` ${dnsStats.freshWhois.join(', ')}`);
4733
+ }
4734
+ }
4683
4735
  }
4684
4736
 
4685
4737
  // Clean process termination
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanboynz/network-scanner",
3
- "version": "2.0.59",
3
+ "version": "2.0.60",
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": {