@fanboynz/network-scanner 2.0.56 → 2.0.58
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/.github/workflows/npm-publish.yml +4 -5
- package/CLAUDE.md +65 -0
- package/lib/adblock.js +4 -3
- package/lib/browserexit.js +61 -96
- package/lib/browserhealth.js +223 -183
- package/lib/compare.js +0 -4
- package/lib/compress.js +6 -15
- package/lib/dry-run.js +1 -1
- package/lib/fingerprint.js +39 -37
- package/lib/flowproxy.js +8 -8
- package/lib/grep.js +1 -1
- package/lib/ignore_similar.js +78 -209
- package/lib/interaction.js +23 -45
- package/lib/openvpn_vpn.js +16 -21
- package/lib/output.js +12 -6
- package/lib/post-processing.js +282 -356
- package/lib/smart-cache.js +347 -267
- package/lib/validate_rules.js +12 -27
- package/nwss.js +15 -3
- package/package.json +3 -2
- package/.clauderc +0 -30
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
name: Publish to NPM
|
|
2
2
|
on:
|
|
3
|
-
|
|
4
|
-
branches: [ main, master ]
|
|
3
|
+
workflow_dispatch:
|
|
5
4
|
|
|
6
5
|
jobs:
|
|
7
6
|
publish:
|
|
8
7
|
runs-on: ubuntu-latest
|
|
9
8
|
permissions:
|
|
10
|
-
contents: write
|
|
9
|
+
contents: write
|
|
11
10
|
|
|
12
11
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
12
|
+
- uses: actions/checkout@v5
|
|
14
13
|
with:
|
|
15
14
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
16
15
|
fetch-depth: 0
|
|
17
16
|
|
|
18
17
|
- name: Setup Node.js
|
|
19
|
-
uses: actions/setup-node@
|
|
18
|
+
uses: actions/setup-node@v5
|
|
20
19
|
with:
|
|
21
20
|
node-version: '20'
|
|
22
21
|
registry-url: 'https://registry.npmjs.org'
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Network Scanner (NWSS)
|
|
2
|
+
|
|
3
|
+
Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, VPN/proxy routing, and multiple output formats.
|
|
4
|
+
|
|
5
|
+
## Project Structure
|
|
6
|
+
|
|
7
|
+
- `nwss.js` — Main entry point (~4,600 lines). CLI args, URL processing, orchestration.
|
|
8
|
+
- `config.json` — Default scan configuration (sites, filters, options).
|
|
9
|
+
- `lib/` — 28 focused, single-purpose modules:
|
|
10
|
+
- `fingerprint.js` — Bot detection evasion (device/GPU/timezone spoofing)
|
|
11
|
+
- `cloudflare.js` — Cloudflare challenge detection and solving
|
|
12
|
+
- `browserhealth.js` — Memory management and browser lifecycle
|
|
13
|
+
- `interaction.js` — Human-like mouse/scroll/typing simulation
|
|
14
|
+
- `smart-cache.js` — Multi-layer caching with persistence
|
|
15
|
+
- `nettools.js` — WHOIS/dig integration
|
|
16
|
+
- `output.js` — Multi-format rule output (adblock, dnsmasq, unbound, pihole, etc.)
|
|
17
|
+
- `proxy.js` — SOCKS5/HTTP proxy support
|
|
18
|
+
- `wireguard_vpn.js` / `openvpn_vpn.js` — VPN routing
|
|
19
|
+
- `adblock.js` — Adblock filter parsing and validation
|
|
20
|
+
- `validate_rules.js` — Domain and rule format validation
|
|
21
|
+
- `colorize.js` — Console output formatting and colors
|
|
22
|
+
- `domain-cache.js` — Domain detection cache for performance
|
|
23
|
+
- `post-processing.js` — Result cleanup and deduplication
|
|
24
|
+
- `redirect.js`, `referrer.js`, `cdp.js`, `curl.js`, `grep.js`, `compare.js`, `compress.js`, `dry-run.js`, `browserexit.js`, `clear_sitedata.js`, `flowproxy.js`, `ignore_similar.js`, `searchstring.js`
|
|
25
|
+
- `.github/workflows/npm-publish.yml` — Automated npm publishing
|
|
26
|
+
- `nwss.1` — Man page
|
|
27
|
+
|
|
28
|
+
## Tech Stack
|
|
29
|
+
|
|
30
|
+
- **Node.js** >=20.0.0
|
|
31
|
+
- **puppeteer** >=20.0.0 — Headless browser automation
|
|
32
|
+
- **psl** — Public Suffix List for domain parsing
|
|
33
|
+
- **lru-cache** — LRU cache implementation
|
|
34
|
+
- **p-limit** — Concurrency limiting (dynamically imported)
|
|
35
|
+
- **eslint** — Linting (`npm run lint`)
|
|
36
|
+
|
|
37
|
+
## Conventions
|
|
38
|
+
|
|
39
|
+
- Store modular functionality in `./lib/` with focused, single-purpose modules
|
|
40
|
+
- Use `messageColors` and `formatLogMessage` from `./lib/colorize` for consistent console output
|
|
41
|
+
- Implement timeout protection for all Puppeteer operations using `Promise.race` patterns
|
|
42
|
+
- Handle browser lifecycle with comprehensive cleanup in try-finally blocks
|
|
43
|
+
- Validate all external tool availability before use (grep, curl, whois, dig)
|
|
44
|
+
- Use `forceDebug` flag for detailed logging, `silentMode` for minimal output
|
|
45
|
+
- Use `Object.freeze` for constant configuration objects (TIMEOUTS, CACHE_LIMITS, CONCURRENCY_LIMITS)
|
|
46
|
+
- Use `fastTimeout(ms)` helper instead of `node:timers/promises` for Puppeteer 22.x compatibility
|
|
47
|
+
|
|
48
|
+
## Running
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
node nwss.js # Run with default config.json
|
|
52
|
+
node nwss.js config-custom.json # Run with custom config
|
|
53
|
+
node nwss.js --validate-config # Validate configuration
|
|
54
|
+
node nwss.js --dry-run # Preview without network calls
|
|
55
|
+
node nwss.js --headful # Launch with browser GUI
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Files to Ignore
|
|
59
|
+
|
|
60
|
+
- `node_modules/**`
|
|
61
|
+
- `logs/**`
|
|
62
|
+
- `sources/**`
|
|
63
|
+
- `.cache/**`
|
|
64
|
+
- `*.log`
|
|
65
|
+
- `*.gz`
|
package/lib/adblock.js
CHANGED
|
@@ -51,11 +51,12 @@ function parseAdblockRules(filePath, options = {}) {
|
|
|
51
51
|
caseSensitive = false
|
|
52
52
|
} = options;
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
let fileContent;
|
|
55
|
+
try {
|
|
56
|
+
fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
57
|
+
} catch (err) {
|
|
55
58
|
throw new Error(`Adblock rules file not found: ${filePath}`);
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
59
60
|
const lines = fileContent.split('\n');
|
|
60
61
|
|
|
61
62
|
const rules = {
|
package/lib/browserexit.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
8
9
|
const { execSync } = require('child_process');
|
|
9
10
|
|
|
10
11
|
// Constants for temp file cleanup
|
|
@@ -15,20 +16,55 @@ const CHROME_TEMP_PATHS = [
|
|
|
15
16
|
];
|
|
16
17
|
|
|
17
18
|
const CHROME_TEMP_PATTERNS = [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/^\.?com\.google\.Chrome\./,
|
|
20
|
+
/^\.?org\.chromium\.Chromium\./,
|
|
21
|
+
/^puppeteer-/
|
|
21
22
|
];
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Count and remove matching Chrome/Puppeteer temp entries from a directory using fs
|
|
26
|
+
* @param {string} basePath - Directory to scan
|
|
27
|
+
* @param {boolean} forceDebug - Whether to output debug logs
|
|
28
|
+
* @returns {number} Number of items cleaned
|
|
29
|
+
*/
|
|
30
|
+
function cleanTempDir(basePath, forceDebug) {
|
|
31
|
+
let entries;
|
|
32
|
+
try {
|
|
33
|
+
entries = fs.readdirSync(basePath);
|
|
34
|
+
} catch {
|
|
35
|
+
if (forceDebug) console.log(`[debug] [temp-cleanup] Cannot read ${basePath}`);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let cleaned = 0;
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
let matched = false;
|
|
42
|
+
for (const re of CHROME_TEMP_PATTERNS) {
|
|
43
|
+
if (re.test(entry)) { matched = true; break; }
|
|
44
|
+
}
|
|
45
|
+
if (!matched) continue;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
fs.rmSync(path.join(basePath, entry), { recursive: true, force: true });
|
|
49
|
+
cleaned++;
|
|
50
|
+
if (forceDebug) console.log(`[debug] [temp-cleanup] Removed ${basePath}/${entry}`);
|
|
51
|
+
} catch (rmErr) {
|
|
52
|
+
if (forceDebug) console.log(`[debug] [temp-cleanup] Failed to remove ${basePath}/${entry}: ${rmErr.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return cleaned;
|
|
57
|
+
}
|
|
58
|
+
|
|
23
59
|
/**
|
|
24
60
|
* Clean Chrome temporary files and directories
|
|
25
61
|
* @param {Object} options - Cleanup options
|
|
26
62
|
* @param {boolean} options.includeSnapTemp - Whether to clean snap temp directories
|
|
27
63
|
* @param {boolean} options.forceDebug - Whether to output debug logs
|
|
28
64
|
* @param {boolean} options.comprehensive - Whether to perform comprehensive cleanup of all temp locations
|
|
29
|
-
* @returns {
|
|
65
|
+
* @returns {Object} Cleanup results
|
|
30
66
|
*/
|
|
31
|
-
|
|
67
|
+
function cleanupChromeTempFiles(options = {}) {
|
|
32
68
|
const {
|
|
33
69
|
includeSnapTemp = false,
|
|
34
70
|
forceDebug = false,
|
|
@@ -36,57 +72,20 @@ async function cleanupChromeTempFiles(options = {}) {
|
|
|
36
72
|
} = options;
|
|
37
73
|
|
|
38
74
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
'rm -rf /tmp/com.google.Chrome.* 2>/dev/null || true',
|
|
43
|
-
'rm -rf /tmp/.com.google.Chrome.* 2>/dev/null || true',
|
|
44
|
-
'rm -rf /tmp/.org.chromium.Chromium.* 2>/dev/null || true',
|
|
45
|
-
'rm -rf /tmp/puppeteer-* 2>/dev/null || true',
|
|
46
|
-
'rm -rf /dev/shm/.com.google.Chrome.* 2>/dev/null || true',
|
|
47
|
-
'rm -rf /dev/shm/.org.chromium.Chromium.* 2>/dev/null || true'
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
// Add snap-specific cleanup if requested
|
|
51
|
-
if (includeSnapTemp || comprehensive) {
|
|
52
|
-
cleanupCommands.push('rm -rf /dev/shm/com.google.Chrome.* 2>/dev/null || true');
|
|
53
|
-
cleanupCommands.push(
|
|
54
|
-
'rm -rf /tmp/snap-private-tmp/snap.chromium/tmp/.org.chromium.Chromium.* 2>/dev/null || true',
|
|
55
|
-
'rm -rf /tmp/snap-private-tmp/snap.chromium/tmp/puppeteer-* 2>/dev/null || true'
|
|
56
|
-
);
|
|
57
|
-
}
|
|
75
|
+
const paths = comprehensive || includeSnapTemp
|
|
76
|
+
? CHROME_TEMP_PATHS
|
|
77
|
+
: CHROME_TEMP_PATHS.slice(0, 2); // /tmp and /dev/shm only
|
|
58
78
|
|
|
59
79
|
let totalCleaned = 0;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// Extract glob pattern and count matches before deletion
|
|
64
|
-
const globPattern = command.match(/rm -rf ([^ ]+)/)?.[1];
|
|
65
|
-
if (!globPattern) continue;
|
|
66
|
-
const fileCount = parseInt(execSync(`ls -1d ${globPattern} 2>/dev/null | wc -l || echo 0`, { stdio: 'pipe' }).toString().trim()) || 0;
|
|
67
|
-
|
|
68
|
-
if (fileCount > 0) {
|
|
69
|
-
execSync(command, { stdio: 'ignore' });
|
|
70
|
-
totalCleaned += fileCount;
|
|
71
|
-
|
|
72
|
-
if (forceDebug) {
|
|
73
|
-
console.log(`[debug] [temp-cleanup] Cleaned ${fileCount} items from ${globPattern}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
} catch (cmdErr) {
|
|
77
|
-
// Ignore individual command errors but log in debug mode
|
|
78
|
-
if (forceDebug) {
|
|
79
|
-
console.log(`[debug] [temp-cleanup] Cleanup command failed: ${command} (${cmdErr.message})`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
80
|
+
for (const basePath of paths) {
|
|
81
|
+
totalCleaned += cleanTempDir(basePath, forceDebug);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
if (forceDebug) {
|
|
85
|
-
console.log(`[debug] [temp-cleanup]
|
|
85
|
+
console.log(`[debug] [temp-cleanup] Cleanup completed (${totalCleaned} items)`);
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
return { success: true, itemsCleaned: totalCleaned };
|
|
89
|
-
|
|
90
89
|
} catch (cleanupErr) {
|
|
91
90
|
if (forceDebug) {
|
|
92
91
|
console.log(`[debug] [temp-cleanup] Chrome cleanup error: ${cleanupErr.message}`);
|
|
@@ -96,72 +95,38 @@ async function cleanupChromeTempFiles(options = {}) {
|
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
/**
|
|
99
|
-
* Comprehensive temp file cleanup that
|
|
98
|
+
* Comprehensive temp file cleanup that checks all known Chrome temp locations
|
|
100
99
|
* @param {Object} options - Cleanup options
|
|
101
100
|
* @param {boolean} options.forceDebug - Whether to output debug logs
|
|
102
101
|
* @param {boolean} options.verbose - Whether to show verbose output
|
|
103
|
-
* @returns {
|
|
102
|
+
* @returns {Object} Cleanup results
|
|
104
103
|
*/
|
|
105
|
-
|
|
104
|
+
function comprehensiveChromeTempCleanup(options = {}) {
|
|
106
105
|
const { forceDebug = false, verbose = false } = options;
|
|
107
|
-
|
|
106
|
+
|
|
108
107
|
try {
|
|
109
|
-
let totalCleaned = 0;
|
|
110
|
-
|
|
111
108
|
if (verbose && !forceDebug) {
|
|
112
109
|
console.log(`[temp-cleanup] Scanning Chrome/Puppeteer temporary files...`);
|
|
113
110
|
}
|
|
114
|
-
|
|
111
|
+
|
|
112
|
+
let totalCleaned = 0;
|
|
115
113
|
for (const basePath of CHROME_TEMP_PATHS) {
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
const pathExists = fs.existsSync(basePath);
|
|
119
|
-
|
|
120
|
-
if (!pathExists) {
|
|
121
|
-
if (forceDebug) {
|
|
122
|
-
console.log(`[debug] [temp-cleanup] Skipping non-existent path: ${basePath}`);
|
|
123
|
-
}
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
for (const pattern of CHROME_TEMP_PATTERNS) {
|
|
128
|
-
const fullPattern = `${basePath}/${pattern}`;
|
|
129
|
-
|
|
130
|
-
// Count items before deletion
|
|
131
|
-
const countCommand = `ls -1d ${fullPattern} 2>/dev/null | wc -l || echo 0`;
|
|
132
|
-
const itemCount = parseInt(execSync(countCommand, { stdio: 'pipe' }).toString().trim()) || 0;
|
|
133
|
-
|
|
134
|
-
if (itemCount > 0) {
|
|
135
|
-
const deleteCommand = `rm -rf ${fullPattern} 2>/dev/null || true`;
|
|
136
|
-
execSync(deleteCommand, { stdio: 'ignore' });
|
|
137
|
-
totalCleaned += itemCount;
|
|
138
|
-
|
|
139
|
-
if (forceDebug) {
|
|
140
|
-
console.log(`[debug] [temp-cleanup] Removed ${itemCount} items matching ${fullPattern}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
} catch (pathErr) {
|
|
145
|
-
if (forceDebug) {
|
|
146
|
-
console.log(`[debug] [temp-cleanup] Error checking path ${basePath}: ${pathErr.message}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
114
|
+
totalCleaned += cleanTempDir(basePath, forceDebug);
|
|
149
115
|
}
|
|
150
|
-
|
|
116
|
+
|
|
151
117
|
if (verbose && totalCleaned > 0) {
|
|
152
|
-
console.log(`[temp-cleanup]
|
|
118
|
+
console.log(`[temp-cleanup] Removed ${totalCleaned} temporary file(s)/folder(s)`);
|
|
153
119
|
} else if (verbose && totalCleaned === 0) {
|
|
154
|
-
console.log(`[temp-cleanup]
|
|
120
|
+
console.log(`[temp-cleanup] Clean - no remaining temporary files`);
|
|
155
121
|
} else if (forceDebug) {
|
|
156
122
|
console.log(`[debug] [temp-cleanup] Comprehensive cleanup completed (${totalCleaned} items)`);
|
|
157
123
|
}
|
|
158
|
-
|
|
124
|
+
|
|
159
125
|
return { success: true, itemsCleaned: totalCleaned };
|
|
160
|
-
|
|
161
126
|
} catch (err) {
|
|
162
127
|
const errorMsg = `Comprehensive temp file cleanup failed: ${err.message}`;
|
|
163
128
|
if (verbose) {
|
|
164
|
-
console.warn(`[temp-cleanup]
|
|
129
|
+
console.warn(`[temp-cleanup] ${errorMsg}`);
|
|
165
130
|
} else if (forceDebug) {
|
|
166
131
|
console.log(`[debug] [temp-cleanup] ${errorMsg}`);
|
|
167
132
|
}
|
|
@@ -317,7 +282,7 @@ async function forceBrowserKill(browser, forceDebug = false) {
|
|
|
317
282
|
}
|
|
318
283
|
|
|
319
284
|
// Wait for graceful termination
|
|
320
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
285
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
321
286
|
|
|
322
287
|
// Force kill any remaining processes with SIGKILL
|
|
323
288
|
for (const pid of pidsToKill) {
|