@fanboynz/network-scanner 2.0.19 → 2.0.21
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/README.md +3 -2
- package/lib/output.js +12 -22
- package/nwss.1 +69 -12
- package/nwss.js +95 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,8 +35,8 @@ A Puppeteer-based tool for scanning websites to find third-party (or optionally
|
|
|
35
35
|
|
|
36
36
|
| Argument | Description |
|
|
37
37
|
|:---------------------------|:------------|
|
|
38
|
-
| `--localhost`
|
|
39
|
-
| `--localhost
|
|
38
|
+
| `--localhost[=IP]` | Output as `IP domain.com` (default: 127.0.0.1) |
|
|
39
|
+
| | Examples: `--localhost`, `--localhost=0.0.0.0`, `--localhost=192.168.1.1` |
|
|
40
40
|
| `--plain` | Output just domains (no adblock formatting) |
|
|
41
41
|
| `--dnsmasq` | Output as `local=/domain.com/` (dnsmasq format) |
|
|
42
42
|
| `--dnsmasq-old` | Output as `server=/domain.com/` (dnsmasq old format) |
|
|
@@ -253,6 +253,7 @@ When a page redirects to a new domain, first-party/third-party detection is base
|
|
|
253
253
|
| `source` | Boolean | `false` | Save page source HTML after load |
|
|
254
254
|
| `screenshot` | Boolean | `false` | Capture screenshot on load failure |
|
|
255
255
|
| `headful` | Boolean | `false` | Launch browser with GUI for this site |
|
|
256
|
+
| `localhost` | String | - | Force custom IP format for this site (e.g., "127.0.0.1", "0.0.0.0", "192.168.1.1") |
|
|
256
257
|
| `adblock_rules` | Boolean | `false` | Generate adblock filter rules with resource types for this site |
|
|
257
258
|
| `interact_duration` | Milliseconds | `2000` | Duration of interaction simulation |
|
|
258
259
|
| `interact_scrolling` | Boolean | `true` | Enable scrolling simulation |
|
package/lib/output.js
CHANGED
|
@@ -93,8 +93,7 @@ function extractDomainFromRule(rule) {
|
|
|
93
93
|
* Formats a domain according to the specified output mode
|
|
94
94
|
* @param {string} domain - The domain to format
|
|
95
95
|
* @param {object} options - Formatting options
|
|
96
|
-
* @param {
|
|
97
|
-
* @param {boolean} options.localhostAlt - Use 0.0.0.0 format
|
|
96
|
+
* @param {string|null} options.localhostIP - Use custom IP format (e.g., '127.0.0.1', '0.0.0.0')
|
|
98
97
|
* @param {boolean} options.plain - Use plain domain format (no adblock syntax)
|
|
99
98
|
* @param {boolean} options.adblockRules - Generate adblock filter rules with resource types
|
|
100
99
|
* @param {boolean} options.dnsmasq - Use dnsmasq local format
|
|
@@ -106,7 +105,7 @@ function extractDomainFromRule(rule) {
|
|
|
106
105
|
* @returns {string} The formatted domain
|
|
107
106
|
*/
|
|
108
107
|
function formatDomain(domain, options = {}) {
|
|
109
|
-
const {
|
|
108
|
+
const { localhostIP = null, plain = false, adblockRules = false, dnsmasq = false, dnsmasqOld = false, unbound = false, privoxy = false, pihole = false, resourceType = null } = options;
|
|
110
109
|
|
|
111
110
|
|
|
112
111
|
// Validate domain length and format
|
|
@@ -132,10 +131,8 @@ function formatDomain(domain, options = {}) {
|
|
|
132
131
|
return `server=/${domain}/`;
|
|
133
132
|
} else if (unbound) {
|
|
134
133
|
return `local-zone: "${domain}." always_null`;
|
|
135
|
-
} else if (
|
|
136
|
-
return
|
|
137
|
-
} else if (localhostAlt) {
|
|
138
|
-
return `0.0.0.0 ${domain}`;
|
|
134
|
+
} else if (localhostIP) {
|
|
135
|
+
return `${localhostIP} ${domain}`;
|
|
139
136
|
} else if (adblockRules && resourceType) {
|
|
140
137
|
// Generate adblock filter rules with resource type modifiers
|
|
141
138
|
return `||${domain}^${resourceType}`;
|
|
@@ -178,8 +175,7 @@ function mapResourceTypeToAdblockModifier(resourceType) {
|
|
|
178
175
|
*/
|
|
179
176
|
function formatRules(matchedDomains, siteConfig = {}, globalOptions = {}) {
|
|
180
177
|
const {
|
|
181
|
-
|
|
182
|
-
localhostModeAlt = false,
|
|
178
|
+
localhostIP = null,
|
|
183
179
|
plainOutput = false,
|
|
184
180
|
adblockRulesMode = false,
|
|
185
181
|
dnsmasqMode = false,
|
|
@@ -190,8 +186,7 @@ function formatRules(matchedDomains, siteConfig = {}, globalOptions = {}) {
|
|
|
190
186
|
} = globalOptions;
|
|
191
187
|
|
|
192
188
|
// Site-level overrides
|
|
193
|
-
const
|
|
194
|
-
const siteLocalhostAlt = siteConfig.localhost_0_0_0_0 === true;
|
|
189
|
+
const siteLocalhostIP = siteConfig.localhost || null;
|
|
195
190
|
const sitePlainSetting = siteConfig.plain === true;
|
|
196
191
|
const siteAdblockRules = siteConfig.adblock_rules === true;
|
|
197
192
|
const siteDnsmasq = siteConfig.dnsmasq === true;
|
|
@@ -208,16 +203,14 @@ function formatRules(matchedDomains, siteConfig = {}, globalOptions = {}) {
|
|
|
208
203
|
privoxyMode || sitePrivoxy,
|
|
209
204
|
piholeMode || sitePihole,
|
|
210
205
|
adblockRulesMode || siteAdblockRules,
|
|
211
|
-
|
|
212
|
-
localhostModeAlt || siteLocalhostAlt,
|
|
206
|
+
(localhostIP || siteLocalhostIP) ? true : false,
|
|
213
207
|
plainOutput || sitePlainSetting
|
|
214
208
|
].filter(Boolean).length;
|
|
215
209
|
|
|
216
210
|
if (activeFormats > 1) {
|
|
217
211
|
// Multiple formats specified - fall back to standard adblock format
|
|
218
212
|
const formatOptions = {
|
|
219
|
-
|
|
220
|
-
localhostAlt: false,
|
|
213
|
+
localhostIP: null,
|
|
221
214
|
plain: false,
|
|
222
215
|
adblockRules: false,
|
|
223
216
|
dnsmasq: false,
|
|
@@ -240,8 +233,7 @@ function formatRules(matchedDomains, siteConfig = {}, globalOptions = {}) {
|
|
|
240
233
|
|
|
241
234
|
// Determine final formatting options
|
|
242
235
|
const formatOptions = {
|
|
243
|
-
|
|
244
|
-
localhostAlt: localhostModeAlt || siteLocalhostAlt,
|
|
236
|
+
localhostIP: siteLocalhostIP || localhostIP,
|
|
245
237
|
plain: plainOutput || sitePlainSetting,
|
|
246
238
|
adblockRules: adblockRulesMode || siteAdblockRules,
|
|
247
239
|
dnsmasq: dnsmasqMode || siteDnsmasq,
|
|
@@ -640,7 +632,7 @@ function handleOutput(results, config = {}) {
|
|
|
640
632
|
* @returns {string} Human-readable format description
|
|
641
633
|
*/
|
|
642
634
|
function getFormatDescription(options = {}) {
|
|
643
|
-
const {
|
|
635
|
+
const { localhostIP = null, plain = false, adblockRules = false, dnsmasq = false, dnsmasqOld = false, unbound = false, privoxy = false, pihole = false } = options;
|
|
644
636
|
|
|
645
637
|
// Plain always takes precedence
|
|
646
638
|
if (plain) {
|
|
@@ -659,10 +651,8 @@ function getFormatDescription(options = {}) {
|
|
|
659
651
|
return 'Unbound format (local-zone: "domain.com." always_null)';
|
|
660
652
|
} else if (adblockRules) {
|
|
661
653
|
return 'Adblock filter rules with resource type modifiers (||domain.com^$script)';
|
|
662
|
-
} else if (
|
|
663
|
-
return
|
|
664
|
-
} else if (localhostAlt) {
|
|
665
|
-
return 'Localhost format (0.0.0.0 domain.com)';
|
|
654
|
+
} else if (localhostIP) {
|
|
655
|
+
return `Localhost format (${localhostIP} domain.com)`;
|
|
666
656
|
} else {
|
|
667
657
|
return 'Adblock format (||domain.com^)';
|
|
668
658
|
}
|
package/nwss.1
CHANGED
|
@@ -33,12 +33,15 @@ Enable colored console output for status messages.
|
|
|
33
33
|
|
|
34
34
|
.SS Output Format Options
|
|
35
35
|
.TP
|
|
36
|
-
.
|
|
37
|
-
Output rules as \
|
|
36
|
+
.BR \--localhost [ =\fIIP\fR ]
|
|
37
|
+
Output rules as \fBIP domain.com\fR format for hosts file. If no IP is specified, defaults to \fB127.0.0.1\fR.
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
39
|
+
Examples:
|
|
40
|
+
.RS
|
|
41
|
+
\fB\--localhost\fR (uses 127.0.0.1)
|
|
42
|
+
\fB\--localhost=0.0.0.0\fR
|
|
43
|
+
\fB\--localhost=192.168.1.1\fR
|
|
44
|
+
.RE
|
|
42
45
|
|
|
43
46
|
.TP
|
|
44
47
|
.B \--plain
|
|
@@ -300,7 +303,7 @@ Number of times to reload the page (default: 1).
|
|
|
300
303
|
|
|
301
304
|
.TP
|
|
302
305
|
.B forcereload
|
|
303
|
-
Boolean. Force an
|
|
306
|
+
Boolean or Array. Force cache-clearing reload for all URLs or specific domains. Can be \fBtrue\fR/\fBfalse\fR or array of domain names like \fB["domain1.com", "domain2.com"]\fR. When set to \fBtrue\fR, applies to all URLs in the site configuration. When set to an array, applies only to URLs whose domains match the specified domains. Supports exact hostname matching and subdomain matching (e.g., "example.com" matches both "example.com" and "subdomain.example.com"). Domain matching is case-insensitive and automatically handles protocols, ports, and paths.
|
|
304
307
|
|
|
305
308
|
.TP
|
|
306
309
|
.B timeout
|
|
@@ -578,11 +581,9 @@ Number. Output full subdomains instead of root domains (1/0).
|
|
|
578
581
|
|
|
579
582
|
.TP
|
|
580
583
|
.B localhost
|
|
581
|
-
|
|
584
|
+
String. Force custom IP format for this site. Examples: \fB"127.0.0.1"\fR, \fB"0.0.0.0"\fR, \fB"192.168.1.1"\fR, \fB"10.0.0.1"\fR.
|
|
582
585
|
|
|
583
|
-
.
|
|
584
|
-
.B localhost_0_0_0_0
|
|
585
|
-
Boolean. Force localhost output format (0.0.0.0) for this site.
|
|
586
|
+
When set, overrides global \fB\--localhost\fR flag for this specific site.
|
|
586
587
|
|
|
587
588
|
.TP
|
|
588
589
|
.B dnsmasq
|
|
@@ -783,6 +784,37 @@ With default settings (\fBignore_similar_threshold: 80\fR):
|
|
|
783
784
|
}
|
|
784
785
|
.EE
|
|
785
786
|
|
|
787
|
+
.SS Force reload examples:
|
|
788
|
+
.EX
|
|
789
|
+
# Force reload for all URLs in a site configuration
|
|
790
|
+
{
|
|
791
|
+
"url": ["https://site1.com", "https://site2.com"],
|
|
792
|
+
"filterRegex": "ads|tracking",
|
|
793
|
+
"forcereload": true
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
# Force reload only for specific domains
|
|
797
|
+
{
|
|
798
|
+
"url": [
|
|
799
|
+
"https://example.com/page1",
|
|
800
|
+
"https://test.org/page2",
|
|
801
|
+
"https://demo.net/page3"
|
|
802
|
+
],
|
|
803
|
+
"filterRegex": "\\\\.(space|website)\\\\b",
|
|
804
|
+
"forcereload": ["example.com", "demo.net"],
|
|
805
|
+
"comments": [
|
|
806
|
+
"Only example.com and demo.net URLs get force reload",
|
|
807
|
+
"test.org URLs use standard reload"
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
# Mixed configuration with domain-specific force reload
|
|
812
|
+
{
|
|
813
|
+
"url": "https://cdn.example.com/content/page.html",
|
|
814
|
+
"forcereload": ["example.com"]
|
|
815
|
+
}
|
|
816
|
+
.EE
|
|
817
|
+
|
|
786
818
|
.SS Configuration with documentation comments:
|
|
787
819
|
.EX
|
|
788
820
|
{
|
|
@@ -970,9 +1002,11 @@ Format: \fB(^|\\.)domain\\.com$\fR
|
|
|
970
1002
|
For Pi-hole regex filters. Blocks domain and subdomains at DNS level.
|
|
971
1003
|
|
|
972
1004
|
.SS Hosts File Formats
|
|
973
|
-
|
|
1005
|
+
Flag: \fB\--localhost[=IP]\fR
|
|
974
1006
|
.br
|
|
975
|
-
|
|
1007
|
+
Format: \fBIP domain.com\fR (default IP: 127.0.0.1)
|
|
1008
|
+
.br
|
|
1009
|
+
Examples: \fB\--localhost\fR, \fB\--localhost=0.0.0.0\fR, \fB\--localhost=10.0.0.1\fR
|
|
976
1010
|
.br
|
|
977
1011
|
For system hosts files.
|
|
978
1012
|
|
|
@@ -988,6 +1022,19 @@ Format: \fBdomain.com\fR
|
|
|
988
1022
|
.br
|
|
989
1023
|
Simple domain list without formatting.
|
|
990
1024
|
|
|
1025
|
+
.SS Custom IP Examples
|
|
1026
|
+
.EX
|
|
1027
|
+
# Standard localhost blocking
|
|
1028
|
+
node nwss.js -o hosts.txt --localhost
|
|
1029
|
+
|
|
1030
|
+
# Block to null route
|
|
1031
|
+
node nwss.js -o hosts.txt --localhost=0.0.0.0
|
|
1032
|
+
|
|
1033
|
+
# Route to local server
|
|
1034
|
+
node nwss.js -o hosts.txt --localhost=192.168.1.100
|
|
1035
|
+
node nwss.js -o hosts.txt --localhost=10.0.0.1
|
|
1036
|
+
.EE
|
|
1037
|
+
|
|
991
1038
|
.SH FILES
|
|
992
1039
|
|
|
993
1040
|
.TP
|
|
@@ -1090,6 +1137,16 @@ Report bugs to the project repository or maintainer.
|
|
|
1090
1137
|
.BR unbound (8),
|
|
1091
1138
|
.BR privoxy (8)
|
|
1092
1139
|
|
|
1140
|
+
.SH EXAMPLES OF CONFIG WITH CUSTOM LOCALHOST IP
|
|
1141
|
+
.EX
|
|
1142
|
+
{
|
|
1143
|
+
"url": "https://example.com",
|
|
1144
|
+
"filterRegex": "ads|tracking",
|
|
1145
|
+
"localhost": "10.0.0.1"
|
|
1146
|
+
}
|
|
1147
|
+
.EE
|
|
1148
|
+
This configuration will output rules in the format \fB10.0.0.1 domain.com\fR for this specific site, overriding any global \fB\--localhost\fR flag.
|
|
1149
|
+
|
|
1093
1150
|
.SH AUTHORS
|
|
1094
1151
|
Written for malware research and network security analysis.
|
|
1095
1152
|
|
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v2.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v2.0.21 ===
|
|
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.21'; // Script version
|
|
134
134
|
|
|
135
135
|
// get startTime
|
|
136
136
|
const startTime = Date.now();
|
|
@@ -173,8 +173,12 @@ const silentMode = args.includes('--silent');
|
|
|
173
173
|
const showTitles = args.includes('--titles');
|
|
174
174
|
const dumpUrls = args.includes('--dumpurls');
|
|
175
175
|
const subDomainsMode = args.includes('--sub-domains');
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
// Parse --localhost with optional IP address
|
|
177
|
+
let localhostIP = null;
|
|
178
|
+
const localhostIndex = args.findIndex(arg => arg.startsWith('--localhost'));
|
|
179
|
+
if (localhostIndex !== -1) {
|
|
180
|
+
localhostIP = args[localhostIndex].includes('=') ? args[localhostIndex].split('=')[1] : '127.0.0.1';
|
|
181
|
+
}
|
|
178
182
|
const disableInteract = args.includes('--no-interact');
|
|
179
183
|
const plainOutput = args.includes('--plain');
|
|
180
184
|
const enableCDP = args.includes('--cdp');
|
|
@@ -230,7 +234,7 @@ if (adblockRulesMode) {
|
|
|
230
234
|
if (!outputFile) {
|
|
231
235
|
if (forceDebug) console.log(formatLogMessage('debug', `--adblock-rules ignored: requires --output (-o) to specify an output file`));
|
|
232
236
|
adblockRulesMode = false;
|
|
233
|
-
} else if (
|
|
237
|
+
} else if (localhostIP || plainOutput || dnsmasqMode || dnsmasqOldMode || unboundMode || privoxyMode || piholeMode) {
|
|
234
238
|
if (forceDebug) console.log(formatLogMessage('debug', `--adblock-rules ignored: incompatible with localhost/plain output modes`));
|
|
235
239
|
adblockRulesMode = false;
|
|
236
240
|
}
|
|
@@ -238,7 +242,7 @@ if (adblockRulesMode) {
|
|
|
238
242
|
|
|
239
243
|
// Validate --dnsmasq usage
|
|
240
244
|
if (dnsmasqMode) {
|
|
241
|
-
if (
|
|
245
|
+
if (localhostIP || plainOutput || adblockRulesMode || dnsmasqOldMode || unboundMode || privoxyMode || piholeMode) {
|
|
242
246
|
if (forceDebug) console.log(formatLogMessage('debug', `--dnsmasq-old ignored: incompatible with localhost/plain/adblock-rules/dnsmasq output modes`));
|
|
243
247
|
dnsmasqMode = false;
|
|
244
248
|
}
|
|
@@ -246,7 +250,7 @@ if (dnsmasqMode) {
|
|
|
246
250
|
|
|
247
251
|
// Validate --dnsmasq-old usage
|
|
248
252
|
if (dnsmasqOldMode) {
|
|
249
|
-
if (
|
|
253
|
+
if (localhostIP || plainOutput || adblockRulesMode || dnsmasqMode || unboundMode || privoxyMode || piholeMode) {
|
|
250
254
|
if (forceDebug) console.log(formatLogMessage('debug', `--dnsmasq-old ignored: incompatible with localhost/plain/adblock-rules/dnsmasq output modes`));
|
|
251
255
|
dnsmasqOldMode = false;
|
|
252
256
|
}
|
|
@@ -254,7 +258,7 @@ if (dnsmasqOldMode) {
|
|
|
254
258
|
|
|
255
259
|
// Validate --unbound usage
|
|
256
260
|
if (unboundMode) {
|
|
257
|
-
if (
|
|
261
|
+
if (localhostIP || plainOutput || adblockRulesMode || dnsmasqMode || dnsmasqOldMode || privoxyMode || piholeMode) {
|
|
258
262
|
if (forceDebug) console.log(formatLogMessage('debug', `--unbound ignored: incompatible with localhost/plain/adblock-rules/dnsmasq output modes`));
|
|
259
263
|
unboundMode = false;
|
|
260
264
|
}
|
|
@@ -262,7 +266,7 @@ if (unboundMode) {
|
|
|
262
266
|
|
|
263
267
|
// Validate --privoxy usage
|
|
264
268
|
if (privoxyMode) {
|
|
265
|
-
if (
|
|
269
|
+
if (localhostIP || plainOutput || adblockRulesMode || dnsmasqMode || dnsmasqOldMode || unboundMode || piholeMode) {
|
|
266
270
|
if (forceDebug) console.log(formatLogMessage('debug', `--privoxy ignored: incompatible with localhost/plain/adblock-rules/dnsmasq/unbound output modes`));
|
|
267
271
|
privoxyMode = false;
|
|
268
272
|
}
|
|
@@ -270,7 +274,7 @@ if (privoxyMode) {
|
|
|
270
274
|
|
|
271
275
|
// Validate --pihole usage
|
|
272
276
|
if (piholeMode) {
|
|
273
|
-
if (
|
|
277
|
+
if (localhostIP || plainOutput || adblockRulesMode || dnsmasqMode || dnsmasqOldMode || unboundMode || privoxyMode) {
|
|
274
278
|
if (forceDebug) console.log(formatLogMessage('debug', `--pihole ignored: incompatible with localhost/plain/adblock-rules/dnsmasq/unbound/privoxy output modes`));
|
|
275
279
|
piholeMode = false;
|
|
276
280
|
}
|
|
@@ -430,8 +434,8 @@ Options:
|
|
|
430
434
|
--append Append new rules to output file instead of overwriting (requires -o)
|
|
431
435
|
|
|
432
436
|
Output Format Options:
|
|
433
|
-
--localhost
|
|
434
|
-
|
|
437
|
+
--localhost[=IP] Output as IP domain.com (default: 127.0.0.1)
|
|
438
|
+
Examples: --localhost, --localhost=0.0.0.0, --localhost=192.168.1.1
|
|
435
439
|
--plain Output just domains (no adblock formatting)
|
|
436
440
|
--dnsmasq Output as local=/domain.com/ (dnsmasq format)
|
|
437
441
|
--dnsmasq-old Output as server=/domain.com/ (dnsmasq old format)
|
|
@@ -512,7 +516,7 @@ Redirect Handling Options:
|
|
|
512
516
|
interact_intensity: "low"|"medium"|"high" Interaction simulation intensity (default: medium)
|
|
513
517
|
delay: <milliseconds> Delay after load (default: 4000)
|
|
514
518
|
reload: <number> Reload page n times after load (default: 1)
|
|
515
|
-
forcereload: true/false
|
|
519
|
+
forcereload: true/false or ["domain1.com", "domain2.com"] Force cache-clearing reload for all URLs or specific domains
|
|
516
520
|
clear_sitedata: true/false Clear all cookies, cache, storage before each load (default: false)
|
|
517
521
|
subDomains: 1/0 Output full subdomains (default: 0)
|
|
518
522
|
localhost: true/false Force localhost output (127.0.0.1)
|
|
@@ -1478,8 +1482,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1478
1482
|
const allowFirstParty = siteConfig.firstParty === true || siteConfig.firstParty === 1;
|
|
1479
1483
|
const allowThirdParty = siteConfig.thirdParty === undefined || siteConfig.thirdParty === true || siteConfig.thirdParty === 1;
|
|
1480
1484
|
const perSiteSubDomains = siteConfig.subDomains === 1 ? true : subDomainsMode;
|
|
1481
|
-
const
|
|
1482
|
-
const siteLocalhostAlt = siteConfig.localhost_0_0_0_0 === true;
|
|
1485
|
+
const siteLocalhostIP = siteConfig.localhost || null;
|
|
1483
1486
|
const cloudflarePhishBypass = siteConfig.cloudflare_phish === true;
|
|
1484
1487
|
const cloudflareBypass = siteConfig.cloudflare_bypass === true;
|
|
1485
1488
|
// Add redirect and same-page loop protection
|
|
@@ -3199,7 +3202,80 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3199
3202
|
updatePageUsage(page, true);
|
|
3200
3203
|
|
|
3201
3204
|
const totalReloads = (siteConfig.reload || 1) - 1; // Subtract 1 because initial load counts as first
|
|
3202
|
-
|
|
3205
|
+
|
|
3206
|
+
// Enhanced forcereload logic: support boolean or domain array
|
|
3207
|
+
let useForceReload = false;
|
|
3208
|
+
if (siteConfig.forcereload === true) {
|
|
3209
|
+
// Original behavior: force reload for all URLs
|
|
3210
|
+
useForceReload = true;
|
|
3211
|
+
} else if (Array.isArray(siteConfig.forcereload)) {
|
|
3212
|
+
// Input validation: filter out invalid entries
|
|
3213
|
+
const validDomains = siteConfig.forcereload.filter(domain => {
|
|
3214
|
+
if (typeof domain !== 'string') {
|
|
3215
|
+
if (forceDebug) {
|
|
3216
|
+
console.log(formatLogMessage('debug', `Invalid forcereload entry (not string): ${typeof domain} - ${JSON.stringify(domain)}`));
|
|
3217
|
+
}
|
|
3218
|
+
return false;
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
if (domain.trim() === '') {
|
|
3222
|
+
if (forceDebug) {
|
|
3223
|
+
console.log(formatLogMessage('debug', `Invalid forcereload entry (empty string)`));
|
|
3224
|
+
}
|
|
3225
|
+
return false;
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
return true;
|
|
3229
|
+
});
|
|
3230
|
+
|
|
3231
|
+
if (validDomains.length === 0) {
|
|
3232
|
+
if (forceDebug) {
|
|
3233
|
+
console.log(formatLogMessage('debug', `No valid domains in forcereload array for ${currentUrl}`));
|
|
3234
|
+
}
|
|
3235
|
+
useForceReload = false;
|
|
3236
|
+
} else {
|
|
3237
|
+
// New behavior: force reload only for matching domains
|
|
3238
|
+
const currentDomain = safeGetDomain(currentUrl, true); // Get full hostname
|
|
3239
|
+
const currentRootDomain = safeGetDomain(currentUrl, false); // Get root domain
|
|
3240
|
+
|
|
3241
|
+
useForceReload = validDomains.some(domain => {
|
|
3242
|
+
// Enhanced domain cleaning: handle protocols, ports, paths, and normalize case
|
|
3243
|
+
let cleanDomain = domain.trim();
|
|
3244
|
+
cleanDomain = cleanDomain.replace(/^https?:\/\//, ''); // Remove protocol
|
|
3245
|
+
cleanDomain = cleanDomain.replace(/:\d+$/, ''); // Remove port (e.g., :8080)
|
|
3246
|
+
cleanDomain = cleanDomain.replace(/\/.*$/, ''); // Remove path
|
|
3247
|
+
cleanDomain = cleanDomain.toLowerCase(); // Normalize case
|
|
3248
|
+
|
|
3249
|
+
// Additional validation: basic domain format check
|
|
3250
|
+
if (!/^[a-z0-9.-]+$/.test(cleanDomain)) {
|
|
3251
|
+
if (forceDebug) {
|
|
3252
|
+
console.log(formatLogMessage('debug', `Skipping invalid domain format in forcereload: ${domain} -> ${cleanDomain}`));
|
|
3253
|
+
}
|
|
3254
|
+
return false;
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
// Check if current URL matches this domain
|
|
3258
|
+
// Support both exact hostname match and subdomain match
|
|
3259
|
+
if (currentDomain.toLowerCase() === cleanDomain || currentRootDomain.toLowerCase() === cleanDomain) {
|
|
3260
|
+
return true;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
// Check if current hostname ends with the domain (subdomain match)
|
|
3264
|
+
if (currentDomain.toLowerCase().endsWith('.' + cleanDomain)) {
|
|
3265
|
+
return true;
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
return false;
|
|
3269
|
+
});
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
if (forceDebug && useForceReload) {
|
|
3273
|
+
console.log(formatLogMessage('debug', `Force reload enabled for ${currentUrl} - matches domain in forcereload list`));
|
|
3274
|
+
} else if (forceDebug && validDomains.length > 0) {
|
|
3275
|
+
console.log(formatLogMessage('debug', `Force reload not applied for ${currentUrl} - no domain match in [${validDomains.join(', ')}]`));
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
// If forcereload is not specified, false, or any other value, useForceReload remains false
|
|
3203
3279
|
|
|
3204
3280
|
if (useForceReload && forceDebug) {
|
|
3205
3281
|
console.log(formatLogMessage('debug', `Using force reload mechanism for all ${totalReloads + 1} reload(s) on ${currentUrl}`));
|
|
@@ -3392,8 +3468,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3392
3468
|
} else {
|
|
3393
3469
|
// Format rules using the output module
|
|
3394
3470
|
const globalOptions = {
|
|
3395
|
-
|
|
3396
|
-
localhostModeAlt,
|
|
3471
|
+
localhostIP,
|
|
3397
3472
|
plainOutput,
|
|
3398
3473
|
adblockRulesMode,
|
|
3399
3474
|
dnsmasqMode,
|
|
@@ -3434,8 +3509,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3434
3509
|
// For other errors, preserve any matches we found before the error
|
|
3435
3510
|
if (matchedDomains && (matchedDomains.size > 0 || (matchedDomains instanceof Map && matchedDomains.size > 0))) {
|
|
3436
3511
|
const globalOptions = {
|
|
3437
|
-
|
|
3438
|
-
localhostModeAlt,
|
|
3512
|
+
localhostIP,
|
|
3439
3513
|
plainOutput,
|
|
3440
3514
|
adblockRulesMode,
|
|
3441
3515
|
dnsmasqMode,
|
|
@@ -3883,8 +3957,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3883
3957
|
const detectedDomainsCount = getDetectedDomainsCount();
|
|
3884
3958
|
if (forceDebug) {
|
|
3885
3959
|
const globalOptions = {
|
|
3886
|
-
|
|
3887
|
-
localhostModeAlt,
|
|
3960
|
+
localhostIP,
|
|
3888
3961
|
plainOutput,
|
|
3889
3962
|
adblockRules: adblockRulesMode,
|
|
3890
3963
|
dnsmasq: dnsmasqMode,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.21",
|
|
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": {
|