@fanboynz/network-scanner 1.0.46 → 1.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.
@@ -1,33 +1,80 @@
1
- # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
- # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
-
4
- name: Node.js Package
1
+ name: Publish to NPM
5
2
 
6
3
  on:
7
- release:
8
- types: [created]
4
+ push:
5
+ branches: [ main, master ] # adjust to your default branch name
9
6
 
10
7
  jobs:
11
- build:
8
+ check-version:
12
9
  runs-on: ubuntu-latest
10
+ outputs:
11
+ version-changed: ${{ steps.check.outputs.changed }}
12
+ version: ${{ steps.check.outputs.version }}
13
13
  steps:
14
14
  - uses: actions/checkout@v4
15
- - uses: actions/setup-node@v4
16
15
  with:
17
- node-version: 20
18
- - run: npm ci
19
- - run: npm test
16
+ fetch-depth: 0 # fetch full history to compare versions
17
+
18
+ - name: Check if version changed
19
+ id: check
20
+ run: |
21
+ # Get current version from package.json
22
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
23
+ echo "Current version: $CURRENT_VERSION"
24
+
25
+ # Get previous version from the last commit
26
+ git checkout HEAD~1 -- package.json 2>/dev/null || echo "No previous package.json found"
27
+ PREVIOUS_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "0.0.0")
28
+ echo "Previous version: $PREVIOUS_VERSION"
29
+
30
+ # Restore current package.json
31
+ git checkout HEAD -- package.json
32
+
33
+ # Check if version changed
34
+ if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
35
+ echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION"
36
+ echo "changed=true" >> $GITHUB_OUTPUT
37
+ echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
38
+ else
39
+ echo "Version unchanged"
40
+ echo "changed=false" >> $GITHUB_OUTPUT
41
+ echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
42
+ fi
20
43
 
21
- publish-npm:
22
- needs: build
44
+ publish:
45
+ needs: check-version
46
+ if: needs.check-version.outputs.version-changed == 'true'
23
47
  runs-on: ubuntu-latest
24
48
  steps:
25
49
  - uses: actions/checkout@v4
26
- - uses: actions/setup-node@v4
50
+
51
+ - name: Setup Node.js
52
+ uses: actions/setup-node@v4
27
53
  with:
28
- node-version: 20
29
- registry-url: https://registry.npmjs.org/
30
- - run: npm ci
31
- - run: npm publish
54
+ node-version: '18' # matches your package.json requirement
55
+ registry-url: 'https://registry.npmjs.org'
56
+
57
+ - name: Install dependencies
58
+ run: npm ci
59
+
60
+ - name: Run linting
61
+ run: npm run lint
62
+
63
+ - name: Verify npm authentication
64
+ run: npm whoami
65
+ env:
66
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
67
+
68
+ - name: Publish to NPM
69
+ run: npm publish
70
+ env:
71
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
72
+
73
+ - name: Create Git Tag
74
+ run: |
75
+ git config --local user.email "action@github.com"
76
+ git config --local user.name "GitHub Action"
77
+ git tag v${{ needs.check-version.outputs.version }}
78
+ git push origin v${{ needs.check-version.outputs.version }}
32
79
  env:
33
- NODE_AUTH_TOKEN: ${{secrets.npm_token}}
80
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,6 @@
1
+ import globals from "globals";
2
+ import { defineConfig } from "eslint/config";
3
+
4
+ export default defineConfig([
5
+ { files: ["**/*.{js,mjs,cjs}"], languageOptions: { globals: globals.browser } },
6
+ ]);
package/lib/cdp.js ADDED
@@ -0,0 +1,302 @@
1
+ // === Chrome DevTools Protocol (CDP) Module ===
2
+ // Handles CDP session management and network request logging for enhanced browser monitoring
3
+ //
4
+ // INTEGRATION GUIDE FOR OTHER APPLICATIONS:
5
+ // This module provides a clean interface for Chrome DevTools Protocol integration with Puppeteer.
6
+ // It can be easily integrated into any Node.js application that uses Puppeteer for browser automation.
7
+ //
8
+ // BASIC USAGE:
9
+ // const { createCDPSession } = require('./lib/cdp');
10
+ // const cdpManager = await createCDPSession(page, url, options);
11
+ // // ... do your work ...
12
+ // await cdpManager.cleanup(); // Always cleanup when done
13
+ //
14
+ // DEPENDENCIES:
15
+ // - Puppeteer (any recent version)
16
+ // - ./colorize module (for logging) - can be replaced with console.log if needed
17
+ //
18
+ // PERFORMANCE CONSIDERATIONS:
19
+ // - CDP adds ~10-20% overhead to page processing
20
+ // - Use selectively on complex sites that need deep network visibility
21
+ // - Avoid on high-volume batch processing unless debugging
22
+ //
23
+ // COMPATIBILITY:
24
+ // - Works with Chrome/Chromium browsers
25
+ // - Compatible with headless and headful modes
26
+ // - Tested with Puppeteer 13+ but should work with older versions
27
+
28
+ const { formatLogMessage } = require('./colorize');
29
+
30
+ /**
31
+ * Creates and manages a CDP session for network monitoring
32
+ *
33
+ * INTEGRATION EXAMPLE:
34
+ * const cdpManager = await createCDPSession(page, 'https://example.com', {
35
+ * enableCDP: true, // Global CDP flag
36
+ * siteSpecificCDP: true, // Site-specific CDP flag
37
+ * forceDebug: false // Enable debug logging
38
+ * });
39
+ *
40
+ * // Your page automation code here...
41
+ * await page.goto('https://example.com');
42
+ *
43
+ * // Always cleanup when done
44
+ * await cdpManager.cleanup();
45
+ *
46
+ * WHAT IT MONITORS:
47
+ * - All network requests (GET, POST, etc.)
48
+ * - Request initiators (script, parser, user, etc.)
49
+ * - Request/response timing
50
+ * - Failed requests and errors
51
+ *
52
+ * ERROR HANDLING:
53
+ * - Gracefully handles CDP connection failures
54
+ * - Distinguishes between critical and non-critical errors
55
+ * - Returns null session object if CDP setup fails
56
+ * - Never throws on cleanup operations
57
+ *
58
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
59
+ * @param {string} currentUrl - The URL being processed (used for logging context)
60
+ * @param {object} options - Configuration options
61
+ * @param {boolean} options.enableCDP - Global CDP flag (from --cdp command line)
62
+ * @param {boolean} options.siteSpecificCDP - Site-specific CDP flag (from config)
63
+ * @param {boolean} options.forceDebug - Debug logging flag
64
+ * @returns {Promise<object>} CDP session object with cleanup method
65
+ */
66
+ async function createCDPSession(page, currentUrl, options = {}) {
67
+ const { enableCDP, siteSpecificCDP, forceDebug } = options;
68
+
69
+ // Determine if CDP logging is needed for this page
70
+ // You can customize this logic for your application's needs
71
+ const cdpLoggingNeeded = enableCDP || siteSpecificCDP === true;
72
+
73
+ if (!cdpLoggingNeeded) {
74
+ // Return a null session with no-op cleanup for consistent API
75
+ return { session: null, cleanup: async () => {} };
76
+ }
77
+
78
+ // Log which CDP mode is being used
79
+ if (forceDebug) {
80
+ if (enableCDP) {
81
+ console.log(formatLogMessage('debug', `CDP logging globally enabled by --cdp, applying to page: ${currentUrl}`));
82
+ } else if (siteSpecificCDP === true) {
83
+ console.log(formatLogMessage('debug', `CDP logging enabled for page ${currentUrl} via site-specific 'cdp: true' config.`));
84
+ }
85
+ }
86
+
87
+ let cdpSession = null;
88
+
89
+ try {
90
+ // Create CDP session - this connects to Chrome's internal debugging interface
91
+ cdpSession = await page.target().createCDPSession();
92
+
93
+ // Enable network domain - required for network event monitoring
94
+ await cdpSession.send('Network.enable');
95
+
96
+ // Set up network request monitoring
97
+ // This captures ALL network requests at the browser engine level
98
+ cdpSession.on('Network.requestWillBeSent', (params) => {
99
+ const { url: requestUrl, method } = params.request;
100
+ const initiator = params.initiator ? params.initiator.type : 'unknown';
101
+
102
+ // Extract hostname for logging context (handles URL parsing errors gracefully)
103
+ let hostnameForLog = 'unknown-host';
104
+ try {
105
+ hostnameForLog = new URL(currentUrl).hostname;
106
+ } catch (_) {
107
+ // Ignore URL parsing errors for logging context
108
+ }
109
+
110
+ // Log the request with context - customize this for your needs
111
+ // Format: [cdp][hostname] METHOD url (initiator: type)
112
+ console.log(formatLogMessage('debug', `[cdp][${hostnameForLog}] ${method} ${requestUrl} (initiator: ${initiator})`));
113
+ });
114
+
115
+ if (forceDebug) {
116
+ console.log(formatLogMessage('debug', `CDP session created successfully for ${currentUrl}`));
117
+ }
118
+
119
+ return {
120
+ session: cdpSession,
121
+ cleanup: async () => {
122
+ // Safe cleanup that never throws errors
123
+ if (cdpSession) {
124
+ try {
125
+ await cdpSession.detach();
126
+ if (forceDebug) {
127
+ console.log(formatLogMessage('debug', `CDP session detached for ${currentUrl}`));
128
+ }
129
+ } catch (cdpCleanupErr) {
130
+ // Log cleanup errors but don't throw - cleanup should never fail the calling code
131
+ if (forceDebug) {
132
+ console.log(formatLogMessage('debug', `Failed to detach CDP session for ${currentUrl}: ${cdpCleanupErr.message}`));
133
+ }
134
+ }
135
+ }
136
+ }
137
+ };
138
+
139
+ } catch (cdpErr) {
140
+ cdpSession = null; // Reset on failure
141
+
142
+ // Categorize CDP errors for proper handling
143
+ if (cdpErr.message.includes('Network.enable timed out') ||
144
+ cdpErr.message.includes('Protocol error')) {
145
+ // CRITICAL ERROR: Browser is broken and needs restart
146
+ // Re-throw these errors so calling code can handle browser restart
147
+ throw new Error(`Browser protocol broken: ${cdpErr.message}`);
148
+ }
149
+
150
+ // NON-CRITICAL ERROR: CDP failed but browser is still usable
151
+ // Log warning but return working session object
152
+ console.warn(formatLogMessage('warn', `[cdp] Failed to attach CDP session for ${currentUrl}: ${cdpErr.message}`));
153
+
154
+ // Return null session with no-op cleanup for consistent API
155
+ return {
156
+ session: null,
157
+ cleanup: async () => {}
158
+ };
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Validates CDP availability and configuration
164
+ *
165
+ * USAGE IN YOUR APPLICATION:
166
+ * const validation = validateCDPConfig(siteConfig, globalCDPFlag);
167
+ * if (!validation.isValid) {
168
+ * console.warn('CDP configuration issues detected');
169
+ * }
170
+ * validation.recommendations.forEach(rec => console.log('Recommendation:', rec));
171
+ *
172
+ * @param {object} siteConfig - Site configuration object
173
+ * @param {boolean} globalCDP - Global CDP flag
174
+ * @returns {object} Validation result with recommendations
175
+ */
176
+ function validateCDPConfig(siteConfig, globalCDP) {
177
+ const warnings = [];
178
+ const recommendations = [];
179
+
180
+ // Check for conflicting configurations
181
+ if (globalCDP && siteConfig.cdp === false) {
182
+ warnings.push('Site-specific CDP disabled but global CDP is enabled - global setting will override');
183
+ }
184
+
185
+ // Performance recommendations
186
+ if (globalCDP || siteConfig.cdp === true) {
187
+ recommendations.push('CDP logging enabled - this may impact performance for high-traffic sites');
188
+
189
+ if (siteConfig.timeout && siteConfig.timeout < 30000) {
190
+ recommendations.push('Consider increasing timeout when using CDP logging to avoid protocol timeouts');
191
+ }
192
+ }
193
+
194
+ return {
195
+ isValid: true,
196
+ warnings,
197
+ recommendations
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Enhanced CDP session with additional network monitoring features
203
+ *
204
+ * ADVANCED FEATURES:
205
+ * - JavaScript exception monitoring
206
+ * - Security state change detection
207
+ * - Failed network request tracking
208
+ * - Enhanced error reporting
209
+ *
210
+ * USE CASES:
211
+ * - Security analysis requiring comprehensive monitoring
212
+ * - Debugging complex single-page applications
213
+ * - Performance analysis of web applications
214
+ * - Research requiring detailed browser insights
215
+ *
216
+ * PERFORMANCE IMPACT:
217
+ * - Adds additional CDP domain subscriptions
218
+ * - Higher memory usage due to more event listeners
219
+ * - Recommended only for detailed analysis scenarios
220
+ *
221
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
222
+ * @param {string} currentUrl - The URL being processed
223
+ * @param {object} options - Configuration options (same as createCDPSession)
224
+ * @returns {Promise<object>} Enhanced CDP session object with isEnhanced flag
225
+ */
226
+ async function createEnhancedCDPSession(page, currentUrl, options = {}) {
227
+ const basicSession = await createCDPSession(page, currentUrl, options);
228
+
229
+ if (!basicSession.session) {
230
+ return basicSession;
231
+ }
232
+
233
+ const { session } = basicSession;
234
+ const { forceDebug } = options;
235
+
236
+ try {
237
+ // Enable additional CDP domains for enhanced monitoring
238
+ await session.send('Runtime.enable'); // For JavaScript exceptions
239
+ await session.send('Security.enable'); // For security state changes
240
+
241
+ // Monitor JavaScript exceptions - useful for debugging problematic sites
242
+ session.on('Runtime.exceptionThrown', (params) => {
243
+ if (forceDebug) {
244
+ console.log(formatLogMessage('debug', `[cdp][exception] ${params.exceptionDetails.text}`));
245
+ }
246
+ });
247
+
248
+ // Monitor security state changes - detect mixed content, certificate issues, etc.
249
+ session.on('Security.securityStateChanged', (params) => {
250
+ if (forceDebug && params.securityState !== 'secure') {
251
+ console.log(formatLogMessage('debug', `[cdp][security] Security state: ${params.securityState}`));
252
+ }
253
+ });
254
+
255
+ // Monitor failed network requests - useful for understanding site issues
256
+ session.on('Network.loadingFailed', (params) => {
257
+ if (forceDebug) {
258
+ console.log(formatLogMessage('debug', `[cdp][failed] ${params.errorText}: ${params.requestId}`));
259
+ }
260
+ });
261
+
262
+ return {
263
+ session,
264
+ cleanup: basicSession.cleanup,
265
+ isEnhanced: true // Flag to indicate enhanced features are active
266
+ };
267
+
268
+ } catch (enhancedErr) {
269
+ if (forceDebug) {
270
+ console.log(formatLogMessage('debug', `Enhanced CDP features failed, falling back to basic session: ${enhancedErr.message}`));
271
+ }
272
+
273
+ // Graceful degradation: return basic session if enhanced features fail
274
+ // This ensures your application continues working even if advanced features break
275
+ return basicSession;
276
+ }
277
+ }
278
+
279
+ // EXPORT INTERFACE FOR OTHER APPLICATIONS:
280
+ // This module provides a clean, reusable interface for CDP integration.
281
+ // Simply require this module and use the exported functions.
282
+ //
283
+ // CUSTOMIZATION TIPS:
284
+ // 1. Replace './colorize' import with your own logging system
285
+ // 2. Modify the request logging format in the Network.requestWillBeSent handler
286
+ // 3. Add additional CDP domain subscriptions in createEnhancedCDPSession
287
+ // 4. Customize error categorization in the catch blocks
288
+ //
289
+ // TROUBLESHOOTING:
290
+ // - If you get "Protocol error" frequently, the browser may be overloaded
291
+ // - Timeout errors usually indicate the browser needs to be restarted
292
+ // - "Target closed" means the page was closed while CDP was active
293
+ //
294
+ // BROWSER COMPATIBILITY:
295
+ // - Chrome/Chromium 60+ (older versions may have limited CDP support)
296
+ // - Works in both headless and headed modes
297
+ // - Some features may not work in --no-sandbox mode
298
+ module.exports = {
299
+ createCDPSession,
300
+ validateCDPConfig,
301
+ createEnhancedCDPSession
302
+ };
package/nwss.js CHANGED
@@ -1,4 +1,4 @@
1
- // === Network scanner script (nwss.js) v1.0.46 ===
1
+ // === Network scanner script (nwss.js) v1.0.48 ===
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
@@ -25,6 +25,8 @@ const { handleBrowserExit, cleanupChromeTempFiles } = require('./lib/browserexit
25
25
  const { createNetToolsHandler, createEnhancedDryRunCallback, validateWhoisAvailability, validateDigAvailability } = require('./lib/nettools');
26
26
  // File compare
27
27
  const { loadComparisonRules, filterUniqueRules } = require('./lib/compare');
28
+ // CDP functionality
29
+ const { createCDPSession } = require('./lib/cdp');
28
30
  // Colorize various text when used
29
31
  const { colorize, colors, messageColors, tags, formatLogMessage } = require('./lib/colorize');
30
32
  // Enhanced mouse interaction and page simulation
@@ -37,7 +39,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
37
39
  const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
38
40
 
39
41
  // --- Script Configuration & Constants ---
40
- const VERSION = '1.0.46'; // Script version
42
+ const VERSION = '1.0.48'; // Script version
41
43
 
42
44
  // get startTime
43
45
  const startTime = Date.now();
@@ -1149,6 +1151,7 @@ function setupFrameHandling(page, forceDebug) {
1149
1151
 
1150
1152
  let page = null;
1151
1153
  let cdpSession = null;
1154
+ let cdpSessionManager = null;
1152
1155
  // Use Map to track domains and their resource types for --adblock-rules or --dry-run
1153
1156
  const matchedDomains = (adblockRulesMode || siteConfig.adblock_rules || dryRunMode) ? new Map() : new Set();
1154
1157
 
@@ -1274,36 +1277,19 @@ function setupFrameHandling(page, forceDebug) {
1274
1277
  // --- END: CSS Element Blocking Setup ---
1275
1278
 
1276
1279
  // --- Per-Page CDP Setup ---
1277
- const cdpLoggingNeededForPage = enableCDP || siteConfig.cdp === true;
1278
- if (cdpLoggingNeededForPage) {
1279
- if (forceDebug) {
1280
- if (enableCDP) {
1281
- console.log(formatLogMessage('debug', `CDP logging globally enabled by --cdp, applying to page: ${currentUrl}`));
1282
- } else if (siteConfig.cdp === true) {
1283
- console.log(formatLogMessage('debug', `CDP logging enabled for page ${currentUrl} via site-specific 'cdp: true' config.`));
1284
- }
1285
- }
1286
- try {
1287
- cdpSession = await page.target().createCDPSession();
1288
- await cdpSession.send('Network.enable');
1289
- cdpSession.on('Network.requestWillBeSent', (params) => {
1290
- const { url: requestUrl, method } = params.request;
1291
- const initiator = params.initiator ? params.initiator.type : 'unknown';
1292
- let hostnameForLog = 'unknown-host';
1293
- try {
1294
- hostnameForLog = new URL(currentUrl).hostname;
1295
- } catch (_) { /* ignore if currentUrl is invalid for URL parsing */ }
1296
- console.log(formatLogMessage('debug', `[cdp][${hostnameForLog}] ${method} ${requestUrl} (initiator: ${initiator})`));
1297
- });
1298
- } catch (cdpErr) {
1299
- cdpSession = null; // Reset on failure
1300
- if (cdpErr.message.includes('Network.enable timed out') ||
1301
- cdpErr.message.includes('Protocol error')) {
1302
- // This indicates browser is completely broken
1303
- throw new Error(`Browser protocol broken: ${cdpErr.message}`);
1304
- }
1305
- console.warn(formatLogMessage('warn', `[cdp] Failed to attach CDP session for ${currentUrl}: ${cdpErr.message}`));
1280
+
1281
+ try {
1282
+ cdpSessionManager = await createCDPSession(page, currentUrl, {
1283
+ enableCDP,
1284
+ siteSpecificCDP: siteConfig.cdp,
1285
+ forceDebug
1286
+ });
1287
+ } catch (cdpErr) {
1288
+ if (cdpErr.message.includes('Browser protocol broken')) {
1289
+ throw cdpErr; // Re-throw critical browser errors
1306
1290
  }
1291
+ // Non-critical CDP errors are already handled in the module
1292
+ cdpSessionManager = { session: null, cleanup: async () => {} };
1307
1293
  }
1308
1294
  // --- End of Per-Page CDP Setup ---
1309
1295
 
@@ -2267,19 +2253,8 @@ function setupFrameHandling(page, forceDebug) {
2267
2253
  } finally {
2268
2254
  // Guaranteed resource cleanup - this runs regardless of success or failure
2269
2255
 
2270
- if (cdpSession) {
2271
- try {
2272
- await cdpSession.detach();
2273
- if (forceDebug) console.log(formatLogMessage('debug', `CDP session detached for ${currentUrl}`));
2274
- } catch (cdpCleanupErr) {
2275
- if (forceDebug) console.log(formatLogMessage('debug', `Failed to detach CDP session for ${currentUrl}: ${cdpCleanupErr.message}`));
2276
- }
2277
- }
2278
- // Add small delay to allow cleanup to complete
2279
- try {
2280
- await new Promise(resolve => setTimeout(resolve, 100));
2281
- } catch (delayErr) {
2282
- // Ignore timeout errors
2256
+ if (cdpSessionManager) {
2257
+ await cdpSessionManager.cleanup();
2283
2258
  }
2284
2259
 
2285
2260
  if (page && !page.isClosed()) {
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@fanboynz/network-scanner",
3
- "version": "1.0.46",
3
+ "version": "1.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": {
7
7
  "start": "node nwss.js",
8
8
  "scan": "node nwss.js",
9
9
  "help": "node nwss.js --help",
10
- "version": "node nwss.js --version"
10
+ "version": "node nwss.js --version",
11
+ "lint": "eslint *.js lib/*.js"
11
12
  },
12
13
  "dependencies": {
13
14
  "p-limit": "^4.0.0",
@@ -41,5 +42,9 @@
41
42
  "bugs": {
42
43
  "url": "https://github.com/ryanbr/network-scanner/issues"
43
44
  },
44
- "homepage": "https://github.com/ryanbr/network-scanner"
45
+ "homepage": "https://github.com/ryanbr/network-scanner",
46
+ "devDependencies": {
47
+ "eslint": "^9.32.0",
48
+ "globals": "^16.3.0"
49
+ }
45
50
  }