@fanboynz/network-scanner 3.0.2 → 3.1.0
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/CHANGELOG.md +34 -0
- package/lib/adblock-rust.js +17 -4
- package/lib/adblock.js +92 -15
- package/lib/browserhealth.js +57 -28
- package/lib/cdp.js +68 -34
- package/lib/clear_sitedata.js +68 -20
- package/lib/compress.js +26 -58
- package/lib/curl.js +44 -22
- package/lib/domain-cache.js +8 -57
- package/lib/dry-run.js +9 -4
- package/lib/fingerprint.js +735 -114
- package/lib/interaction.js +262 -26
- package/lib/nettools.js +47 -76
- package/lib/openvpn_vpn.js +116 -35
- package/lib/searchstring.js +15 -237
- package/lib/validate_rules.js +285 -3
- package/lib/wireguard_vpn.js +64 -12
- package/nwss.js +529 -217
- package/package.json +1 -1
- package/regex-tool/index.html +321 -628
- package/scripts/test-stealth.js +39 -13
package/scripts/test-stealth.js
CHANGED
|
@@ -70,7 +70,7 @@ const TARGETS = [
|
|
|
70
70
|
extract: async (page) => {
|
|
71
71
|
return await page.evaluate(() => {
|
|
72
72
|
const cells = Array.from(document.querySelectorAll('td'));
|
|
73
|
-
const out = { passed: 0, failed: 0, warn: 0, total: 0, failures: [] };
|
|
73
|
+
const out = { passed: 0, failed: 0, warn: 0, total: 0, failures: [], warnings: [] };
|
|
74
74
|
for (const c of cells) {
|
|
75
75
|
const cls = c.className || '';
|
|
76
76
|
if (cls.includes('passed')) { out.passed++; out.total++; }
|
|
@@ -81,7 +81,14 @@ const TARGETS = [
|
|
|
81
81
|
const label = row?.querySelector('td')?.textContent?.trim() || '?';
|
|
82
82
|
out.failures.push(label);
|
|
83
83
|
}
|
|
84
|
-
else if (cls.includes('warn')) {
|
|
84
|
+
else if (cls.includes('warn')) {
|
|
85
|
+
out.warn++; out.total++;
|
|
86
|
+
// Capture warn-row labels too so a soft regression (cell moving
|
|
87
|
+
// passed -> warn) is debuggable without --headful.
|
|
88
|
+
const row = c.closest('tr');
|
|
89
|
+
const label = row?.querySelector('td')?.textContent?.trim() || '?';
|
|
90
|
+
out.warnings.push(label);
|
|
91
|
+
}
|
|
85
92
|
}
|
|
86
93
|
return out;
|
|
87
94
|
});
|
|
@@ -97,15 +104,29 @@ const TARGETS = [
|
|
|
97
104
|
await new Promise(r => setTimeout(r, 8000)); // give async tests time
|
|
98
105
|
return await page.evaluate(() => {
|
|
99
106
|
const text = document.body.innerText || '';
|
|
100
|
-
// CreepJS
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
// CreepJS's actual stealth-relevant outputs are in a "Headless"
|
|
108
|
+
// section as percentages (e.g. "67% headless", "40% stealth",
|
|
109
|
+
// "44% like headless"), not the "Trust Score" label the old
|
|
110
|
+
// regex expected. Engine identification comes from "chromium:
|
|
111
|
+
// true/false" in the same block. Lower headless % and higher
|
|
112
|
+
// stealth % are better for evasion.
|
|
113
|
+
const headlessMatch = text.match(/(\d+(?:\.\d+)?)\s*%\s+headless\b/i);
|
|
114
|
+
const likeHeadlessMatch = text.match(/(\d+(?:\.\d+)?)\s*%\s+like\s+headless/i);
|
|
115
|
+
const stealthMatch = text.match(/(\d+(?:\.\d+)?)\s*%\s+stealth\b/i);
|
|
116
|
+
const chromiumMatch = text.match(/chromium\s*:\s*(true|false)/i);
|
|
117
|
+
// FP ID is CreepJS's stable fingerprint hash — same value across
|
|
118
|
+
// reloads if the fingerprint is unchanged; lets you A/B before
|
|
119
|
+
// and after a spoof change.
|
|
120
|
+
const fpIdMatch = text.match(/FP\s*ID\s*:?\s*([0-9a-f]{16,})/i);
|
|
104
121
|
return {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
headlessPct: headlessMatch ? parseFloat(headlessMatch[1]) : null,
|
|
123
|
+
likeHeadlessPct: likeHeadlessMatch ? parseFloat(likeHeadlessMatch[1]) : null,
|
|
124
|
+
stealthPct: stealthMatch ? parseFloat(stealthMatch[1]) : null,
|
|
125
|
+
isChromium: chromiumMatch ? chromiumMatch[1] === 'true' : null,
|
|
126
|
+
fpId: fpIdMatch ? fpIdMatch[1].slice(0, 16) : null,
|
|
127
|
+
// Larger excerpt (40 lines, up to 2KB) so a future UI rotation
|
|
128
|
+
// is debuggable from the output without --headful.
|
|
129
|
+
excerpt: text.split('\n').slice(0, 40).join('\n').slice(0, 2000)
|
|
109
130
|
};
|
|
110
131
|
});
|
|
111
132
|
}
|
|
@@ -165,10 +186,15 @@ function formatResult(target, result) {
|
|
|
165
186
|
if (result.failures.length) {
|
|
166
187
|
lines.push(` failure rows: ${result.failures.slice(0, 10).join(', ')}${result.failures.length > 10 ? ` ... +${result.failures.length - 10} more` : ''}`);
|
|
167
188
|
}
|
|
189
|
+
if (result.warnings && result.warnings.length) {
|
|
190
|
+
lines.push(` warn rows: ${result.warnings.slice(0, 10).join(', ')}${result.warnings.length > 10 ? ` ... +${result.warnings.length - 10} more` : ''}`);
|
|
191
|
+
}
|
|
168
192
|
} else if (target.name === 'creepjs') {
|
|
169
|
-
lines.push(`
|
|
170
|
-
lines.push(`
|
|
171
|
-
lines.push(`
|
|
193
|
+
lines.push(` FP ID: ${result.fpId ?? 'n/a'} (stable across reloads if fingerprint unchanged)`);
|
|
194
|
+
lines.push(` engine chromium: ${result.isChromium ?? 'n/a'}`);
|
|
195
|
+
lines.push(` headless score: ${result.headlessPct ?? 'n/a'}% (lower = better; 0% = real browser)`);
|
|
196
|
+
lines.push(` like-headless: ${result.likeHeadlessPct ?? 'n/a'}% (lower = better; soft headless signals)`);
|
|
197
|
+
lines.push(` stealth score: ${result.stealthPct ?? 'n/a'}% (lower = better; % likely to be using anti-detection tooling)`);
|
|
172
198
|
if (result.excerpt) lines.push(` excerpt:\n ${result.excerpt.split('\n').join('\n ')}`);
|
|
173
199
|
} else if (target.name === 'browserleaks') {
|
|
174
200
|
for (const [k, v] of Object.entries(result)) {
|