@fanboynz/network-scanner 2.0.47 → 2.0.48
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/adblock.js +20 -40
- package/lib/grep.js +5 -76
- package/package.json +1 -1
package/lib/adblock.js
CHANGED
|
@@ -382,6 +382,7 @@ function createMatcher(rules, options = {}) {
|
|
|
382
382
|
const urlCache = new URLCache(1000);
|
|
383
383
|
let cacheHits = 0;
|
|
384
384
|
let cacheMisses = 0;
|
|
385
|
+
const hasPartyRules = rules.thirdPartyRules.length > 0 || rules.firstPartyRules.length > 0;
|
|
385
386
|
|
|
386
387
|
return {
|
|
387
388
|
rules,
|
|
@@ -416,22 +417,21 @@ function createMatcher(rules, options = {}) {
|
|
|
416
417
|
cacheMisses++;
|
|
417
418
|
}
|
|
418
419
|
|
|
419
|
-
//
|
|
420
|
-
const hasPartyRules = rules.thirdPartyRules.length > 0 || rules.firstPartyRules.length > 0;
|
|
421
|
-
const isThirdParty = (sourceUrl && hasPartyRules)
|
|
422
|
-
? isThirdPartyRequest(url, sourceUrl)
|
|
423
|
-
: false;
|
|
424
|
-
|
|
425
|
-
// OPTIMIZATION #2: Calculate hostname parts once and reuse (avoid duplicate split operations)
|
|
420
|
+
// Calculate hostname parts once and reuse
|
|
426
421
|
const hostnameParts = lowerHostname.split('.');
|
|
422
|
+
|
|
423
|
+
// Precompute parent domains once, reused for whitelist and block checks
|
|
424
|
+
const parentDomains = [];
|
|
425
|
+
const partsLen = hostnameParts.length;
|
|
426
|
+
for (let i = 1; i < partsLen; i++) {
|
|
427
|
+
parentDomains.push(hostnameParts.slice(i).join('.'));
|
|
428
|
+
}
|
|
427
429
|
|
|
428
|
-
//
|
|
430
|
+
// Extract and cache source page domain for $domain and third-party checks
|
|
429
431
|
let sourceDomain = null;
|
|
430
|
-
let cachedSourceData = null;
|
|
431
432
|
|
|
432
433
|
if (sourceUrl) {
|
|
433
|
-
|
|
434
|
-
cachedSourceData = urlCache.get(sourceUrl);
|
|
434
|
+
const cachedSourceData = urlCache.get(sourceUrl);
|
|
435
435
|
|
|
436
436
|
if (cachedSourceData) {
|
|
437
437
|
sourceDomain = cachedSourceData.lowerHostname;
|
|
@@ -454,6 +454,11 @@ function createMatcher(rules, options = {}) {
|
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
// Calculate third-party status using already-parsed hostnames
|
|
458
|
+
const isThirdParty = (sourceDomain && hasPartyRules)
|
|
459
|
+
? getBaseDomain(lowerHostname) !== getBaseDomain(sourceDomain)
|
|
460
|
+
: false;
|
|
461
|
+
|
|
457
462
|
// === WHITELIST CHECK (exception rules take precedence) ===
|
|
458
463
|
|
|
459
464
|
// Fast path: Check exact domain in Map (O(1))
|
|
@@ -468,10 +473,8 @@ function createMatcher(rules, options = {}) {
|
|
|
468
473
|
}
|
|
469
474
|
|
|
470
475
|
// Check parent domains for subdomain matches (e.g., sub.example.com -> example.com)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const parentDomain = hostnameParts.slice(i).join('.');
|
|
474
|
-
rule = rules.whitelistMap.get(parentDomain); // V8: Single Map lookup
|
|
476
|
+
for (let i = 0; i < parentDomains.length; i++) {
|
|
477
|
+
rule = rules.whitelistMap.get(parentDomains[i]);
|
|
475
478
|
if (rule) {
|
|
476
479
|
if (enableLogging) {
|
|
477
480
|
console.log(`[Adblock] Whitelisted: ${url} (${rule.raw})`);
|
|
@@ -508,9 +511,8 @@ function createMatcher(rules, options = {}) {
|
|
|
508
511
|
}
|
|
509
512
|
|
|
510
513
|
// Check parent domains for subdomain matches (e.g., ads.example.com -> example.com)
|
|
511
|
-
for (let i =
|
|
512
|
-
|
|
513
|
-
rule = rules.domainMap.get(parentDomain); // V8: Single Map lookup
|
|
514
|
+
for (let i = 0; i < parentDomains.length; i++) {
|
|
515
|
+
rule = rules.domainMap.get(parentDomains[i]);
|
|
514
516
|
if (rule) {
|
|
515
517
|
if (enableLogging) {
|
|
516
518
|
console.log(`[Adblock] Blocked domain: ${url} (${rule.raw})`);
|
|
@@ -796,27 +798,6 @@ function matchesRule(rule, url, hostname, isThirdParty, resourceType, sourceDoma
|
|
|
796
798
|
}
|
|
797
799
|
}
|
|
798
800
|
|
|
799
|
-
/**
|
|
800
|
-
* Determine if request is third-party
|
|
801
|
-
* @param {string} requestUrl - URL being requested
|
|
802
|
-
* @param {string} sourceUrl - URL of the page making the request
|
|
803
|
-
* @returns {boolean} True if third-party request
|
|
804
|
-
*/
|
|
805
|
-
function isThirdPartyRequest(requestUrl, sourceUrl) {
|
|
806
|
-
try {
|
|
807
|
-
const requestHostname = new URL(requestUrl).hostname;
|
|
808
|
-
const sourceHostname = new URL(sourceUrl).hostname;
|
|
809
|
-
|
|
810
|
-
// Extract base domain (handle subdomains)
|
|
811
|
-
const requestDomain = getBaseDomain(requestHostname);
|
|
812
|
-
const sourceDomain = getBaseDomain(sourceHostname);
|
|
813
|
-
|
|
814
|
-
return requestDomain !== sourceDomain;
|
|
815
|
-
} catch (err) {
|
|
816
|
-
return false;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
801
|
/**
|
|
821
802
|
* Extract base domain from hostname
|
|
822
803
|
* @param {string} hostname - Full hostname
|
|
@@ -833,6 +814,5 @@ function getBaseDomain(hostname) {
|
|
|
833
814
|
|
|
834
815
|
module.exports = {
|
|
835
816
|
parseAdblockRules,
|
|
836
|
-
isThirdPartyRequest,
|
|
837
817
|
getBaseDomain
|
|
838
818
|
};
|
package/lib/grep.js
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const { spawnSync } = require('child_process');
|
|
6
|
-
const crypto = require('crypto');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const os = require('os');
|
|
9
6
|
const { colorize, colors, messageColors, tags, formatLogMessage } = require('./colorize');
|
|
10
7
|
|
|
11
8
|
// === Constants ===
|
|
@@ -21,53 +18,9 @@ const GREP_DEFAULTS = {
|
|
|
21
18
|
GREP_SUCCESS_STATUS: 0,
|
|
22
19
|
GREP_NOT_FOUND_STATUS: 1,
|
|
23
20
|
CURL_SUCCESS_STATUS: 0,
|
|
24
|
-
VERSION_LINE_INDEX: 0
|
|
25
|
-
RANDOM_STRING_LENGTH: 9,
|
|
26
|
-
TEMP_DIR_PREFIX: 'grep_search_'
|
|
21
|
+
VERSION_LINE_INDEX: 0
|
|
27
22
|
};
|
|
28
23
|
|
|
29
|
-
/**
|
|
30
|
-
* Creates a temporary directory and file with content for grep processing
|
|
31
|
-
* Uses mkdtempSync to avoid race conditions from filename collisions
|
|
32
|
-
* @param {string} content - The content to write to temp file
|
|
33
|
-
* @param {string} prefix - Prefix for temp filename
|
|
34
|
-
* @returns {object} Object containing tempDir and tempFile paths
|
|
35
|
-
*/
|
|
36
|
-
function createTempFile(content, prefix = 'scanner_grep') {
|
|
37
|
-
const tempDir = os.tmpdir();
|
|
38
|
-
|
|
39
|
-
// Create a unique temporary directory to avoid race conditions
|
|
40
|
-
const uniqueTempDir = fs.mkdtempSync(path.join(tempDir, GREP_DEFAULTS.TEMP_DIR_PREFIX));
|
|
41
|
-
|
|
42
|
-
// Use cryptographically secure random ID for additional uniqueness
|
|
43
|
-
const uniqueId = crypto.randomBytes(8).toString('hex');
|
|
44
|
-
const tempFile = path.join(uniqueTempDir, `${prefix}_${uniqueId}.tmp`);
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
// Write atomically with error handling
|
|
48
|
-
fs.writeFileSync(tempFile, content, {
|
|
49
|
-
encoding: 'utf8',
|
|
50
|
-
mode: 0o600 // Restrict permissions for security
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
return { tempDir: uniqueTempDir, tempFile };
|
|
54
|
-
} catch (error) {
|
|
55
|
-
// Clean up temp directory on write failure
|
|
56
|
-
try {
|
|
57
|
-
if (fs.existsSync(tempFile)) {
|
|
58
|
-
fs.unlinkSync(tempFile);
|
|
59
|
-
}
|
|
60
|
-
if (fs.existsSync(uniqueTempDir)) {
|
|
61
|
-
fs.rmdirSync(uniqueTempDir);
|
|
62
|
-
}
|
|
63
|
-
} catch (cleanupErr) {
|
|
64
|
-
// Ignore cleanup errors, report original error
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
throw new Error(`Failed to create temp file: ${error.message}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
24
|
/**
|
|
72
25
|
* Searches content using grep with the provided patterns
|
|
73
26
|
* @param {string} content - The content to search
|
|
@@ -86,15 +39,8 @@ async function grepContent(content, searchPatterns, options = {}) {
|
|
|
86
39
|
if (!content || searchPatterns.length === 0) {
|
|
87
40
|
return { found: false, matchedPattern: null, allMatches: [] };
|
|
88
41
|
}
|
|
89
|
-
|
|
90
|
-
let tempFile = null;
|
|
91
|
-
let tempDir = null;
|
|
92
|
-
|
|
42
|
+
|
|
93
43
|
try {
|
|
94
|
-
// Create temporary directory and file with content
|
|
95
|
-
const tempResult = createTempFile(content, 'grep_search');
|
|
96
|
-
tempDir = tempResult.tempDir;
|
|
97
|
-
tempFile = tempResult.tempFile;
|
|
98
44
|
|
|
99
45
|
const allMatches = [];
|
|
100
46
|
let firstMatch = null;
|
|
@@ -111,12 +57,12 @@ async function grepContent(content, searchPatterns, options = {}) {
|
|
|
111
57
|
if (wholeWord) grepArgs.push('-w');
|
|
112
58
|
if (!regex) grepArgs.push('-F'); // Fixed strings (literal)
|
|
113
59
|
|
|
114
|
-
|
|
115
|
-
grepArgs.push(pattern, tempFile);
|
|
60
|
+
grepArgs.push(pattern);
|
|
116
61
|
|
|
117
62
|
try {
|
|
118
63
|
const result = spawnSync('grep', grepArgs, {
|
|
119
64
|
encoding: 'utf8',
|
|
65
|
+
input: content,
|
|
120
66
|
timeout: GREP_DEFAULTS.GREP_TIMEOUT,
|
|
121
67
|
maxBuffer: GREP_DEFAULTS.MAX_BUFFER_SIZE
|
|
122
68
|
});
|
|
@@ -147,22 +93,6 @@ async function grepContent(content, searchPatterns, options = {}) {
|
|
|
147
93
|
|
|
148
94
|
} catch (error) {
|
|
149
95
|
throw new Error(`Grep search failed: ${error.message}`);
|
|
150
|
-
} finally {
|
|
151
|
-
// Clean up temporary file and directory
|
|
152
|
-
if (tempFile) {
|
|
153
|
-
try {
|
|
154
|
-
fs.unlinkSync(tempFile);
|
|
155
|
-
} catch (cleanupErr) {
|
|
156
|
-
console.warn(formatLogMessage('warn', `[grep] Failed to cleanup temp file ${tempFile}: ${cleanupErr.message}`));
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (tempDir) {
|
|
160
|
-
try {
|
|
161
|
-
fs.rmdirSync(tempDir);
|
|
162
|
-
} catch (cleanupErr) {
|
|
163
|
-
console.warn(formatLogMessage('warn', `[grep] Failed to cleanup temp directory ${tempDir}: ${cleanupErr.message}`));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
96
|
}
|
|
167
97
|
}
|
|
168
98
|
|
|
@@ -418,6 +348,5 @@ module.exports = {
|
|
|
418
348
|
grepContent,
|
|
419
349
|
downloadAndGrep,
|
|
420
350
|
createGrepHandler,
|
|
421
|
-
validateGrepAvailability
|
|
422
|
-
createTempFile
|
|
351
|
+
validateGrepAvailability
|
|
423
352
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.48",
|
|
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": {
|