@fanboynz/network-scanner 2.0.13 → 2.0.15

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.
Files changed (3) hide show
  1. package/lib/fingerprint.js +464 -15
  2. package/nwss.js +31 -2
  3. package/package.json +1 -1
@@ -16,17 +16,17 @@ const BUILT_IN_PROPERTIES = new Set([
16
16
  // User agent collections with latest versions
17
17
  const USER_AGENT_COLLECTIONS = {
18
18
  chrome: [
19
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
20
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
21
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
19
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
20
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
21
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
22
22
  ],
23
23
  firefox: [
24
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
25
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0",
26
- "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"
24
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/20100101 Firefox/143.0",
25
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0",
26
+ "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0"
27
27
  ],
28
28
  safari: [
29
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15",
29
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15",
30
30
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
31
31
  ]
32
32
  };
@@ -387,6 +387,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
387
387
  }
388
388
 
389
389
  // Remove webdriver properties
390
+ //
390
391
  safeExecute(() => {
391
392
  try {
392
393
  delete navigator.webdriver;
@@ -395,10 +396,15 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
395
396
  }, 'webdriver removal');
396
397
 
397
398
  // Remove automation properties
399
+ //
398
400
  safeExecute(() => {
399
401
  const automationProps = [
400
402
  'callPhantom', '_phantom', '__nightmare', '_selenium', '__selenium_unwrapped',
401
403
  '__webdriver_evaluate', '__driver_evaluate', '__webdriver_script_function',
404
+ '__fxdriver_evaluate', '__fxdriver_unwrapped', '__webdriver_script_fn',
405
+ 'phantomjs', '_Selenium_IDE_Recorder', 'callSelenium', '_selenium',
406
+ '__phantomas', '__selenium_evaluate', '__driver_unwrapped',
407
+ 'webdriver-evaluate', '__webdriverFunc', 'driver-evaluate', '__driver-evaluate', '__selenium-evaluate',
402
408
  'spawn', 'emit', 'Buffer', 'domAutomation', 'domAutomationController'
403
409
  ];
404
410
 
@@ -413,6 +419,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
413
419
  }, 'automation properties removal');
414
420
 
415
421
  // Simulate Chrome runtime
422
+ //
416
423
  safeExecute(() => {
417
424
  if (!window.chrome?.runtime) {
418
425
  window.chrome = {
@@ -445,22 +452,59 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
445
452
  }, 'Chrome runtime simulation');
446
453
 
447
454
  // Spoof plugins based on user agent
455
+ //
448
456
  safeExecute(() => {
449
457
  let plugins = [];
450
458
  if (userAgent.includes('Chrome')) {
451
459
  plugins = [
452
- { name: 'Chrome PDF Plugin', description: 'Portable Document Format', filename: 'internal-pdf-viewer' },
453
- { name: 'Chrome PDF Viewer', description: 'PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai' }
460
+ {
461
+ name: 'Chrome PDF Plugin',
462
+ description: 'Portable Document Format',
463
+ filename: 'internal-pdf-viewer',
464
+ length: 1,
465
+ version: ''
466
+ },
467
+ {
468
+ name: 'Chrome PDF Viewer',
469
+ description: '',
470
+ filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
471
+ length: 1,
472
+ version: ''
473
+ }
454
474
  ];
455
475
  } else if (userAgent.includes('Firefox')) {
456
476
  plugins = [
457
- { name: 'PDF.js', description: 'Portable Document Format', filename: 'internal-pdf-js' }
477
+ {
478
+ name: 'PDF.js',
479
+ description: 'Portable Document Format',
480
+ filename: 'internal-pdf-js',
481
+ length: 2,
482
+ version: '5.4.70'
483
+ }
458
484
  ];
485
+ } else if (userAgent.includes('Safari')) {
486
+ // Safari typically has no plugins in modern versions
487
+ plugins = [];
459
488
  }
460
- safeDefinePropertyLocal(navigator, 'plugins', { get: () => plugins });
489
+ // Create proper array-like object with enumerable indices and length
490
+ const pluginsArray = {};
491
+ plugins.forEach((plugin, index) => {
492
+ pluginsArray[index] = plugin;
493
+ });
494
+
495
+ // Ensure length property is properly defined
496
+ Object.defineProperty(pluginsArray, 'length', {
497
+ value: plugins.length,
498
+ writable: false,
499
+ enumerable: false,
500
+ configurable: false
501
+ });
502
+
503
+ safeDefinePropertyLocal(navigator, 'plugins', { get: () => pluginsArray });
461
504
  }, 'plugins spoofing');
462
505
 
463
506
  // Spoof languages
507
+ //
464
508
  safeExecute(() => {
465
509
  const languages = ['en-US', 'en'];
466
510
  safeDefinePropertyLocal(navigator, 'languages', { get: () => languages });
@@ -468,6 +512,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
468
512
  }, 'language spoofing');
469
513
 
470
514
  // Spoof vendor information
515
+ //
471
516
  safeExecute(() => {
472
517
  let vendor = 'Google Inc.';
473
518
  let product = 'Gecko';
@@ -482,7 +527,80 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
482
527
  safeDefinePropertyLocal(navigator, 'product', { get: () => product });
483
528
  }, 'vendor/product spoofing');
484
529
 
530
+ // Enhanced OS fingerprinting protection based on actual user agent content
531
+ //
532
+ safeExecute(() => {
533
+ let osType = 'windows';
534
+ let browserType = 'chrome';
535
+
536
+ // Detect OS from user agent string patterns
537
+ if (userAgent.includes('Macintosh') || userAgent.includes('Mac OS X')) {
538
+ osType = 'mac';
539
+ } else if (userAgent.includes('X11; Linux') || userAgent.includes('Ubuntu')) {
540
+ osType = 'linux';
541
+ } else if (userAgent.includes('Windows NT')) {
542
+ osType = 'windows';
543
+ }
544
+
545
+ // Detect browser type
546
+ if (userAgent.includes('Firefox/')) {
547
+ browserType = 'firefox';
548
+ } else if (userAgent.includes('Safari/') && !userAgent.includes('Chrome/')) {
549
+ browserType = 'safari';
550
+ }
551
+
552
+ // Apply OS-specific navigator properties
553
+ if (osType === 'windows') {
554
+ if (browserType === 'firefox') {
555
+ safeDefinePropertyLocal(navigator, 'oscpu', { get: () => 'Windows NT 10.0; Win64; x64' });
556
+ safeDefinePropertyLocal(navigator, 'buildID', { get: () => '20100101' });
557
+ }
558
+ if (window.screen) {
559
+ safeDefinePropertyLocal(window.screen, 'fontSmoothingEnabled', { get: () => true });
560
+ }
561
+ } else if (osType === 'mac') {
562
+ if (browserType === 'firefox') {
563
+ safeDefinePropertyLocal(navigator, 'oscpu', { get: () => 'Intel Mac OS X 10.15' });
564
+ safeDefinePropertyLocal(navigator, 'buildID', { get: () => '20100101' });
565
+ }
566
+ } else if (osType === 'linux') {
567
+ if (browserType === 'firefox') {
568
+ safeDefinePropertyLocal(navigator, 'oscpu', { get: () => 'Linux x86_64' });
569
+ safeDefinePropertyLocal(navigator, 'buildID', { get: () => '20100101' });
570
+ }
571
+ }
572
+ }, 'enhanced OS fingerprinting protection');
573
+
574
+ // Hardware concurrency spoofing (universal coverage)
575
+ //
576
+ safeExecute(() => {
577
+ safeDefinePropertyLocal(navigator, 'hardwareConcurrency', { get: () => [4, 6, 8, 12][Math.floor(Math.random() * 4)] });
578
+ }, 'hardware concurrency spoofing');
579
+
580
+
581
+ // Screen resolution fingerprinting protection
582
+ //
583
+ safeExecute(() => {
584
+ // Common realistic resolutions to avoid fingerprinting
585
+ const commonResolutions = [
586
+ { width: 1920, height: 1080 },
587
+ { width: 2560, height: 1440 },
588
+ { width: 3840, height: 2160 },
589
+ { width: 1280, height: 720 },
590
+ { width: 1366, height: 768 },
591
+ { width: 1440, height: 900 },
592
+ { width: 1536, height: 864 }
593
+ ];
594
+ const resolution = commonResolutions[Math.floor(Math.random() * commonResolutions.length)];
595
+
596
+ safeDefinePropertyLocal(window.screen, 'width', { get: () => resolution.width });
597
+ safeDefinePropertyLocal(window.screen, 'height', { get: () => resolution.height });
598
+ safeDefinePropertyLocal(window.screen, 'availWidth', { get: () => resolution.width });
599
+ safeDefinePropertyLocal(window.screen, 'availHeight', { get: () => resolution.height - 40 });
600
+ }, 'screen resolution protection');
601
+
485
602
  // Spoof MIME types
603
+ //
486
604
  safeExecute(() => {
487
605
  let mimeTypes = [];
488
606
  if (userAgent.includes('Chrome')) {
@@ -556,18 +674,336 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
556
674
  }, 'fingerprinting mocks');
557
675
 
558
676
  // WebGL spoofing
677
+ //
559
678
  safeExecute(() => {
679
+ // Enhanced WebGL fingerprinting protection
680
+ const webglParams = {
681
+ 37445: 'Intel Inc.', // VENDOR
682
+ 37446: 'Intel(R) UHD Graphics 630', // RENDERER (more realistic)
683
+ 7936: 'WebGL 1.0 (OpenGL ES 2.0 Chromium)', // VERSION
684
+ 35724: 'WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.00 Chromium)', // SHADING_LANGUAGE_VERSION
685
+ 34076: 16384, // MAX_TEXTURE_SIZE
686
+ 34024: 16384, // MAX_CUBE_MAP_TEXTURE_SIZE
687
+ 34930: new Float32Array([1, 1]), // ALIASED_LINE_WIDTH_RANGE
688
+ 33901: new Float32Array([0, 1]), // ALIASED_POINT_SIZE_RANGE
689
+ 35660: 16, // MAX_VERTEX_ATTRIBS
690
+ 35661: 16, // MAX_VERTEX_UNIFORM_VECTORS
691
+ 35659: 16, // MAX_VARYING_VECTORS
692
+ 35663: 16, // MAX_FRAGMENT_UNIFORM_VECTORS
693
+ 36347: 4096, // MAX_RENDERBUFFER_SIZE
694
+ 34852: 32, // MAX_COMBINED_TEXTURE_IMAGE_UNITS
695
+ 2978: new Int32Array([0, 0, 1920, 1080]), // VIEWPORT
696
+ 3379: new Int32Array([0, 0, 1920, 1080]) // SCISSOR_BOX
697
+ };
698
+
560
699
  if (window.WebGLRenderingContext) {
561
700
  const getParameter = WebGLRenderingContext.prototype.getParameter;
562
701
  WebGLRenderingContext.prototype.getParameter = function(parameter) {
563
- if (parameter === 37445) return 'Intel Inc.';
564
- if (parameter === 37446) return 'Intel Iris OpenGL Engine';
702
+ if (webglParams.hasOwnProperty(parameter)) {
703
+ return webglParams[parameter];
704
+ }
565
705
  return getParameter.call(this, parameter);
566
706
  };
707
+ // Spoof supported extensions
708
+ const getSupportedExtensions = WebGLRenderingContext.prototype.getSupportedExtensions;
709
+ WebGLRenderingContext.prototype.getSupportedExtensions = function() {
710
+ return [
711
+ 'ANGLE_instanced_arrays',
712
+ 'EXT_blend_minmax',
713
+ 'EXT_color_buffer_half_float',
714
+ 'EXT_disjoint_timer_query',
715
+ 'EXT_float_blend',
716
+ 'EXT_frag_depth',
717
+ 'EXT_shader_texture_lod',
718
+ 'EXT_texture_compression_rgtc',
719
+ 'EXT_texture_filter_anisotropic',
720
+ 'WEBKIT_EXT_texture_filter_anisotropic',
721
+ 'EXT_sRGB',
722
+ 'OES_element_index_uint',
723
+ 'OES_fbo_render_mipmap',
724
+ 'OES_standard_derivatives',
725
+ 'OES_texture_float',
726
+ 'OES_texture_float_linear',
727
+ 'OES_texture_half_float',
728
+ 'OES_texture_half_float_linear',
729
+ 'OES_vertex_array_object',
730
+ 'WEBGL_color_buffer_float',
731
+ 'WEBGL_compressed_texture_s3tc',
732
+ 'WEBGL_debug_renderer_info',
733
+ 'WEBGL_debug_shaders',
734
+ 'WEBGL_depth_texture',
735
+ 'WEBGL_draw_buffers',
736
+ 'WEBGL_lose_context'
737
+ ];
738
+ };
739
+ }
740
+ // Also handle WebGL2 context
741
+ if (window.WebGL2RenderingContext) {
742
+ const getParameter2 = WebGL2RenderingContext.prototype.getParameter;
743
+ WebGL2RenderingContext.prototype.getParameter = function(parameter) {
744
+ if (webglParams.hasOwnProperty(parameter)) {
745
+ return webglParams[parameter];
746
+ }
747
+ return getParameter2.call(this, parameter);
748
+ };
567
749
  }
568
750
  }, 'WebGL spoofing');
569
751
 
752
+ // Permissions API spoofing
753
+ //
754
+ safeExecute(() => {
755
+ if (navigator.permissions?.query) {
756
+ const originalQuery = navigator.permissions.query;
757
+ navigator.permissions.query = function(descriptor) {
758
+ // More realistic permission states based on permission type
759
+ const permissionName = descriptor.name || descriptor;
760
+ let state = 'prompt'; // Default state
761
+
762
+ // Common permissions that are usually granted
763
+ if (['notifications', 'persistent-storage'].includes(permissionName)) {
764
+ state = Math.random() > 0.3 ? 'granted' : 'prompt';
765
+ }
766
+ // Privacy-sensitive permissions that are usually denied/prompt
767
+ else if (['camera', 'microphone', 'geolocation'].includes(permissionName)) {
768
+ state = Math.random() > 0.8 ? 'granted' : 'prompt';
769
+ }
770
+ // Other permissions random
771
+ else {
772
+ state = Math.random() > 0.5 ? 'granted' : 'prompt';
773
+ }
774
+
775
+ return Promise.resolve({
776
+ state: state,
777
+ onchange: null
778
+ });
779
+ };
780
+ }
781
+ // Block permission prompts from actually appearing
782
+ if (window.Notification && Notification.requestPermission) {
783
+ Notification.requestPermission = () => Promise.resolve('default');
784
+ }
785
+ }, 'permissions API spoofing');
786
+
787
+ // Media Device Spoofing
788
+ //
789
+ safeExecute(() => {
790
+ if (navigator.mediaDevices?.enumerateDevices) {
791
+ navigator.mediaDevices.enumerateDevices = function() {
792
+ return Promise.resolve([
793
+ { deviceId: 'default', kind: 'audioinput', label: 'Default - Microphone (Realtek Audio)', groupId: 'group1' },
794
+ { deviceId: 'default', kind: 'audiooutput', label: 'Default - Speakers (Realtek Audio)', groupId: 'group1' },
795
+ { deviceId: 'default', kind: 'videoinput', label: 'HD WebCam (USB Camera)', groupId: 'group2' }
796
+ ]);
797
+ };
798
+ }
799
+ }, 'media device spoofing');
800
+
801
+ // Fetch Request Headers Normalization
802
+ //
803
+ safeExecute(() => {
804
+ const originalFetch = window.fetch;
805
+ window.fetch = function(url, options = {}) {
806
+ const headers = { ...(options.headers || {}) };
807
+
808
+ // Add common browser headers if missing
809
+ if (!headers['Accept']) {
810
+ headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
811
+ }
812
+ if (!headers['Accept-Language']) {
813
+ headers['Accept-Language'] = 'en-US,en;q=0.5';
814
+ }
815
+ if (!headers['Accept-Encoding']) {
816
+ headers['Accept-Encoding'] = 'gzip, deflate, br';
817
+ }
818
+
819
+ return originalFetch.call(this, url, { ...options, headers });
820
+ };
821
+ }, 'fetch headers normalization');
822
+
823
+ // Image Loading Pattern Obfuscation
824
+ //
825
+ safeExecute(() => {
826
+ const originalImageSrc = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, 'src');
827
+ if (originalImageSrc) {
828
+ Object.defineProperty(HTMLImageElement.prototype, 'src', {
829
+ set: function(value) {
830
+ // Add random delay to image loading (0-50ms)
831
+ setTimeout(() => {
832
+ originalImageSrc.set.call(this, value);
833
+ }, Math.random() * 50);
834
+ },
835
+ get: originalImageSrc.get,
836
+ configurable: true
837
+ });
838
+ }
839
+ }, 'image loading obfuscation');
840
+
841
+ // CSS Media Query Spoofing
842
+ //
843
+ safeExecute(() => {
844
+ const originalMatchMedia = window.matchMedia;
845
+ window.matchMedia = function(query) {
846
+ const result = originalMatchMedia.call(this, query);
847
+ // Add slight randomization to avoid fingerprinting for device queries
848
+ if (query.includes('device-width') || query.includes('device-height') ||
849
+ query.includes('aspect-ratio') || query.includes('color-gamut')) {
850
+ Object.defineProperty(result, 'matches', {
851
+ get: () => Math.random() > 0.1 ? originalMatchMedia.call(window, query).matches : !originalMatchMedia.call(window, query).matches,
852
+ configurable: true
853
+ });
854
+ }
855
+ return result;
856
+ };
857
+ }, 'CSS media query spoofing');
858
+
859
+ // Enhanced WebRTC Spoofing
860
+ //
861
+ safeExecute(() => {
862
+ if (window.RTCPeerConnection) {
863
+ const OriginalRTC = window.RTCPeerConnection;
864
+ window.RTCPeerConnection = function(...args) {
865
+ const pc = new OriginalRTC(...args);
866
+ const originalCreateOffer = pc.createOffer;
867
+ pc.createOffer = function() {
868
+ return Promise.reject(new Error('WebRTC disabled'));
869
+ };
870
+ return pc;
871
+ };
872
+ Object.setPrototypeOf(window.RTCPeerConnection, OriginalRTC);
873
+ }
874
+ }, 'WebRTC spoofing');
875
+
876
+ // Font fingerprinting protection
877
+ //
878
+ safeExecute(() => {
879
+ // Standardize available fonts to common system fonts
880
+ const standardFonts = [
881
+ 'Arial', 'Helvetica', 'Times New Roman', 'Times', 'Courier New', 'Courier',
882
+ 'Verdana', 'Georgia', 'Palatino', 'Garamond', 'Bookman', 'Comic Sans MS',
883
+ 'Trebuchet MS', 'Arial Black', 'Impact', 'Tahoma', 'Lucida Console'
884
+ ];
885
+
886
+ // Intercept font availability detection
887
+ if (document.fonts && document.fonts.check) {
888
+ const originalCheck = document.fonts.check;
889
+ document.fonts.check = function(fontSpec) {
890
+ // Always return true for standard fonts, false for others
891
+ const fontFamily = fontSpec.match(/['"]([^'"]+)['"]/)?.[1] || fontSpec.split(' ').pop();
892
+ return standardFonts.some(font => fontFamily.includes(font));
893
+ };
894
+ }
895
+
896
+ // Prevent font loading detection
897
+ if (document.fonts && document.fonts.load) {
898
+ document.fonts.load = function() {
899
+ return Promise.resolve([]);
900
+ };
901
+ }
902
+
903
+ // Canvas-based font fingerprinting protection
904
+ //
905
+ const originalFillText = CanvasRenderingContext2D.prototype.fillText;
906
+ const originalStrokeText = CanvasRenderingContext2D.prototype.strokeText;
907
+ const originalMeasureText = CanvasRenderingContext2D.prototype.measureText;
908
+
909
+ CanvasRenderingContext2D.prototype.fillText = function(text, x, y, maxWidth) {
910
+ // Normalize font to standard before drawing
911
+ const currentFont = this.font;
912
+ if (currentFont && !standardFonts.some(font => currentFont.includes(font))) {
913
+ this.font = currentFont.replace(/['"]?[^'"]*['"]?/, '"Arial"');
914
+ }
915
+ return originalFillText.call(this, text, x, y, maxWidth);
916
+ };
917
+
918
+ CanvasRenderingContext2D.prototype.strokeText = function(text, x, y, maxWidth) {
919
+ const currentFont = this.font;
920
+ if (currentFont && !standardFonts.some(font => currentFont.includes(font))) {
921
+ this.font = currentFont.replace(/['"]?[^'"]*['"]?/, '"Arial"');
922
+ }
923
+ return originalStrokeText.call(this, text, x, y, maxWidth);
924
+ };
925
+
926
+ CanvasRenderingContext2D.prototype.measureText = function(text) {
927
+ const result = originalMeasureText.call(this, text);
928
+ // Add slight noise to text measurements to prevent precise fingerprinting
929
+ result.width += (Math.random() - 0.5) * 0.1;
930
+ return result;
931
+ };
932
+
933
+ // Comprehensive canvas fingerprinting protection
934
+ //
935
+ const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
936
+ CanvasRenderingContext2D.prototype.getImageData = function(sx, sy, sw, sh) {
937
+ const imageData = originalGetImageData.call(this, sx, sy, sw, sh);
938
+ // Add subtle noise to pixel data
939
+ for (let i = 0; i < imageData.data.length; i += 4) {
940
+ if (Math.random() < 0.1) { // 10% chance to modify each pixel
941
+ imageData.data[i] = Math.max(0, Math.min(255, imageData.data[i] + Math.floor(Math.random() * 3) - 1));
942
+ imageData.data[i + 1] = Math.max(0, Math.min(255, imageData.data[i + 1] + Math.floor(Math.random() * 3) - 1));
943
+ imageData.data[i + 2] = Math.max(0, Math.min(255, imageData.data[i + 2] + Math.floor(Math.random() * 3) - 1));
944
+ }
945
+ }
946
+ return imageData;
947
+ };
948
+
949
+ // WebGL canvas context fingerprinting
950
+ const originalGetContext = HTMLCanvasElement.prototype.getContext;
951
+ HTMLCanvasElement.prototype.getContext = function(contextType, contextAttributes) {
952
+ const context = originalGetContext.call(this, contextType, contextAttributes);
953
+
954
+ if (contextType === 'webgl' || contextType === 'webgl2' || contextType === 'experimental-webgl') {
955
+ // Override WebGL-specific fingerprinting methods
956
+ const originalGetShaderPrecisionFormat = context.getShaderPrecisionFormat;
957
+ context.getShaderPrecisionFormat = function(shaderType, precisionType) {
958
+ return {
959
+ rangeMin: 127,
960
+ rangeMax: 127,
961
+ precision: 23
962
+ };
963
+ };
964
+
965
+ const originalGetExtension = context.getExtension;
966
+ context.getExtension = function(name) {
967
+ // Block access to fingerprinting-sensitive extensions
968
+ if (name === 'WEBGL_debug_renderer_info') {
969
+ return null;
970
+ }
971
+ return originalGetExtension.call(this, name);
972
+ };
973
+ }
974
+
975
+ return context;
976
+ };
977
+
978
+ // Override font detection methods
979
+ //
980
+ const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth');
981
+ const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight');
982
+
983
+ if (originalOffsetWidth && originalOffsetHeight) {
984
+ Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
985
+ get: function() {
986
+ if (this.style && this.style.fontFamily) {
987
+ return Math.floor(originalOffsetWidth.get.call(this) + (Math.random() - 0.5) * 2);
988
+ }
989
+ return originalOffsetWidth.get.call(this);
990
+ },
991
+ configurable: true
992
+ });
993
+ }
994
+ }, 'font fingerprinting protection');
995
+
996
+ // Performance timing obfuscation
997
+ //
998
+ safeExecute(() => {
999
+ const originalNow = performance.now;
1000
+ performance.now = function() {
1001
+ return originalNow.call(this) + (Math.random() - 0.5) * 2; // +/- 1ms variation
1002
+ };
1003
+ }, 'performance timing obfuscation');
1004
+
570
1005
  // Canvas fingerprinting protection
1006
+ //
571
1007
  safeExecute(() => {
572
1008
  const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
573
1009
  HTMLCanvasElement.prototype.toDataURL = function(...args) {
@@ -584,6 +1020,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
584
1020
  }, 'canvas fingerprinting protection');
585
1021
 
586
1022
  // Battery API spoofing
1023
+ //
587
1024
  safeExecute(() => {
588
1025
  if (navigator.getBattery) {
589
1026
  navigator.getBattery = function() {
@@ -597,9 +1034,8 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
597
1034
  }
598
1035
  }, 'battery API spoofing');
599
1036
 
600
- // Suppress common console errors
601
-
602
1037
  // Enhanced Mouse/Pointer Spoofing
1038
+ //
603
1039
  safeExecute(() => {
604
1040
  // Spoof pointer capabilities
605
1041
  if (navigator.maxTouchPoints !== undefined) {
@@ -623,6 +1059,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
623
1059
  };
624
1060
 
625
1061
  // Spoof PointerEvent if available
1062
+ //
626
1063
  if (window.PointerEvent) {
627
1064
  const OriginalPointerEvent = window.PointerEvent;
628
1065
  window.PointerEvent = function(type, eventInitDict = {}) {
@@ -652,6 +1089,7 @@ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl)
652
1089
  }
653
1090
 
654
1091
  // Spoof mouse wheel behavior
1092
+ //
655
1093
  const originalWheelEvent = window.WheelEvent;
656
1094
  if (originalWheelEvent) {
657
1095
  window.WheelEvent = function(type, eventInitDict = {}) {
@@ -811,6 +1249,17 @@ async function applyFingerprintProtection(page, siteConfig, forceDebug, currentU
811
1249
  // Memory spoofing
812
1250
  safeDefinePropertyLocal(navigator, 'deviceMemory', { get: () => spoof.deviceMemory });
813
1251
  safeDefinePropertyLocal(navigator, 'hardwareConcurrency', { get: () => spoof.hardwareConcurrency });
1252
+
1253
+ // Connection type spoofing
1254
+ safeDefinePropertyLocal(navigator, 'connection', {
1255
+ get: () => ({
1256
+ effectiveType: ['slow-2g', '2g', '3g', '4g'][Math.floor(Math.random() * 4)],
1257
+ type: Math.random() > 0.5 ? 'cellular' : 'wifi',
1258
+ saveData: Math.random() > 0.8,
1259
+ downlink: 1.5 + Math.random() * 8,
1260
+ rtt: 50 + Math.random() * 200
1261
+ })
1262
+ });
814
1263
 
815
1264
  // Screen properties spoofing
816
1265
  ['width', 'height', 'availWidth', 'availHeight', 'colorDepth', 'pixelDepth'].forEach(prop => {
package/nwss.js CHANGED
@@ -1,4 +1,4 @@
1
- // === Network scanner script (nwss.js) v2.0.13 ===
1
+ // === Network scanner script (nwss.js) v2.0.15 ===
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
@@ -130,7 +130,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
130
130
  const { monitorBrowserHealth, isBrowserHealthy, isQuicklyResponsive, performGroupWindowCleanup, performRealtimeWindowCleanup, trackPageForRealtime, updatePageUsage, cleanupPageBeforeReload } = require('./lib/browserhealth');
131
131
 
132
132
  // --- Script Configuration & Constants ---
133
- const VERSION = '2.0.13'; // Script version
133
+ const VERSION = '2.0.15'; // Script version
134
134
 
135
135
  // get startTime
136
136
  const startTime = Date.now();
@@ -1335,6 +1335,7 @@ function setupFrameHandling(page, forceDebug) {
1335
1335
  '--memory-pressure-off',
1336
1336
  '--max_old_space_size=2048',
1337
1337
  '--no-first-run',
1338
+ '--disable-prompt-on-repost', // Fixes form popup on page reload
1338
1339
  '--disable-default-apps',
1339
1340
  '--disable-component-extensions-with-background-pages',
1340
1341
  '--disable-background-networking',
@@ -1994,6 +1995,34 @@ function setupFrameHandling(page, forceDebug) {
1994
1995
  // --- Apply all fingerprint spoofing (user agent, Brave, fingerprint protection) ---
1995
1996
  try {
1996
1997
  await applyAllFingerprintSpoofing(page, siteConfig, forceDebug, currentUrl);
1998
+
1999
+ // Client Hints protection for Chrome user agents
2000
+ if (siteConfig.userAgent && siteConfig.userAgent.toLowerCase().includes('chrome')) {
2001
+ let platform = 'Windows';
2002
+ let platformVersion = '15.0.0';
2003
+ let arch = 'x86';
2004
+
2005
+ if (siteConfig.userAgent.toLowerCase() === 'chrome_mac') {
2006
+ platform = 'macOS';
2007
+ platformVersion = '13.5.0';
2008
+ arch = 'arm';
2009
+ } else if (siteConfig.userAgent.toLowerCase() === 'chrome_linux') {
2010
+ platform = 'Linux';
2011
+ platformVersion = '6.5.0';
2012
+ arch = 'x86';
2013
+ }
2014
+
2015
+ await page.setExtraHTTPHeaders({
2016
+ 'Sec-CH-UA': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
2017
+ 'Sec-CH-UA-Platform': `"${platform}"`,
2018
+ 'Sec-CH-UA-Platform-Version': `"${platformVersion}"`,
2019
+ 'Sec-CH-UA-Mobile': '?0',
2020
+ 'Sec-CH-UA-Arch': `"${arch}"`,
2021
+ 'Sec-CH-UA-Bitness': '"64"',
2022
+ 'Sec-CH-UA-Full-Version': '"140.0.7339.208"',
2023
+ 'Sec-CH-UA-Full-Version-List': '"Chromium";v="140.0.7339.208", "Not=A?Brand";v="24.0.0.0", "Google Chrome";v="140.0.7339.208"'
2024
+ });
2025
+ }
1997
2026
  } catch (fingerprintErr) {
1998
2027
  if (fingerprintErr.message.includes('Session closed') ||
1999
2028
  fingerprintErr.message.includes('Protocol error') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanboynz/network-scanner",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
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": {