@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.
- package/lib/fingerprint.js +464 -15
- package/nwss.js +31 -2
- package/package.json +1 -1
package/lib/fingerprint.js
CHANGED
|
@@ -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/
|
|
20
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
21
|
-
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
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:
|
|
25
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:
|
|
26
|
-
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:
|
|
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.
|
|
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
|
-
{
|
|
453
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
|
564
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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": {
|