securenow 5.18.0 → 6.0.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.
Files changed (85) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +40 -239
  3. package/cli.js +455 -415
  4. package/console-instrumentation.js +136 -147
  5. package/docs/ALL-FRAMEWORKS-QUICKSTART.md +455 -1339
  6. package/docs/ARCHITECTURE.md +3 -3
  7. package/docs/AUTO-BODY-CAPTURE.md +1 -1
  8. package/docs/AUTO-SETUP.md +4 -4
  9. package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
  10. package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
  11. package/docs/CHANGELOG-NEXTJS.md +1 -1
  12. package/docs/CUSTOMER-GUIDE.md +16 -16
  13. package/docs/EASIEST-SETUP.md +5 -5
  14. package/docs/ENVIRONMENT-VARIABLES.md +652 -880
  15. package/docs/EXPRESS-BODY-CAPTURE.md +12 -13
  16. package/docs/EXPRESS-SETUP-GUIDE.md +720 -719
  17. package/docs/INDEX.md +4 -22
  18. package/docs/LOGGING-GUIDE.md +708 -701
  19. package/docs/LOGGING-QUICKSTART.md +239 -234
  20. package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
  21. package/docs/NEXTJS-GUIDE.md +14 -14
  22. package/docs/NEXTJS-QUICKSTART.md +1 -1
  23. package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
  24. package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
  25. package/docs/REDACTION-EXAMPLES.md +1 -1
  26. package/docs/REQUEST-BODY-CAPTURE.md +10 -19
  27. package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
  28. package/examples/README.md +6 -6
  29. package/examples/instrumentation-with-auto-capture.ts +1 -1
  30. package/examples/nextjs-env-example.txt +2 -2
  31. package/examples/nextjs-instrumentation.js +1 -1
  32. package/examples/nextjs-instrumentation.ts +1 -1
  33. package/examples/nextjs-with-logging-example.md +6 -6
  34. package/examples/nextjs-with-options.ts +1 -1
  35. package/examples/test-nextjs-setup.js +1 -1
  36. package/nextjs-auto-capture.js +207 -199
  37. package/nextjs-middleware.js +181 -186
  38. package/nextjs-webpack-config.js +53 -88
  39. package/nextjs-wrapper.js +158 -158
  40. package/nextjs.d.ts +1 -1
  41. package/nextjs.js +135 -190
  42. package/package.json +45 -67
  43. package/postinstall.js +6 -6
  44. package/register.d.ts +1 -1
  45. package/register.js +4 -39
  46. package/tracing.d.ts +1 -2
  47. package/tracing.js +22 -287
  48. package/web-vite.mjs +156 -239
  49. package/CONSUMING-APPS-GUIDE.md +0 -455
  50. package/NPM_README.md +0 -1933
  51. package/SKILL-API.md +0 -600
  52. package/SKILL-CLI.md +0 -409
  53. package/cidr.js +0 -83
  54. package/cli/apps.js +0 -585
  55. package/cli/auth.js +0 -280
  56. package/cli/client.js +0 -115
  57. package/cli/config.js +0 -173
  58. package/cli/firewall.js +0 -100
  59. package/cli/fp.js +0 -638
  60. package/cli/init.js +0 -201
  61. package/cli/monitor.js +0 -440
  62. package/cli/run.js +0 -133
  63. package/cli/security.js +0 -1064
  64. package/cli/ui.js +0 -386
  65. package/docs/API-KEYS-GUIDE.md +0 -233
  66. package/docs/AUTO-SETUP-SUMMARY.md +0 -331
  67. package/docs/BODY-CAPTURE-FIX.md +0 -261
  68. package/docs/COMPLETION-REPORT.md +0 -408
  69. package/docs/FINAL-SOLUTION.md +0 -335
  70. package/docs/FIREWALL-GUIDE.md +0 -426
  71. package/docs/IMPLEMENTATION-SUMMARY.md +0 -410
  72. package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +0 -323
  73. package/docs/NEXTJS-SETUP-COMPLETE.md +0 -795
  74. package/docs/NUXT-GUIDE.md +0 -166
  75. package/docs/SOLUTION-SUMMARY.md +0 -312
  76. package/firewall-cloud.js +0 -212
  77. package/firewall-iptables.js +0 -139
  78. package/firewall-only.js +0 -38
  79. package/firewall-tcp.js +0 -74
  80. package/firewall.js +0 -720
  81. package/free-trial-banner.js +0 -174
  82. package/nuxt-server-plugin.mjs +0 -423
  83. package/nuxt.d.ts +0 -60
  84. package/nuxt.mjs +0 -75
  85. package/resolve-ip.js +0 -77
package/SKILL-CLI.md DELETED
@@ -1,409 +0,0 @@
1
- # SecureNow CLI — Agent Skill
2
-
3
- Use the `securenow` CLI to perform security DevOps from the terminal: manage apps, investigate threats, control the firewall, analyze traces, handle false positives, and run instrumented Node.js processes. Every command supports `--json` for machine-readable output.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- # Install globally (recommended for CLI usage)
9
- npm install -g securenow
10
-
11
- # Or install per-project and use via npx
12
- npm install securenow
13
- npx securenow <command>
14
- ```
15
-
16
- ### Authenticate
17
-
18
- ```bash
19
- securenow login # opens browser OAuth; stores JWT in ~/.securenow/credentials.json
20
- securenow login --token <JWT> # headless / CI login (get token from dashboard Settings)
21
- securenow login --local # save credentials to this project only (.securenow/)
22
- securenow whoami # verify session (shows auth source)
23
- ```
24
-
25
- **Per-project credentials:** Use `--local` to keep separate logins in different project directories on the same machine. Credentials resolve in order: `SECURENOW_TOKEN` env var → project `.securenow/credentials.json` → global `~/.securenow/credentials.json`.
26
-
27
- ### Integrate With Your App
28
-
29
- The CLI can also instrument any Node.js app at launch — no code changes:
30
-
31
- ```bash
32
- # Express, Fastify, NestJS, Koa, Hapi, raw Node.js
33
- securenow run src/index.js
34
-
35
- # Or via the Node preload flag
36
- node -r securenow/register src/index.js
37
- ```
38
-
39
- For Next.js, run the interactive scaffolding:
40
-
41
- ```bash
42
- securenow init --key snk_live_...
43
- ```
44
-
45
- This auto-detects your framework and creates the necessary `instrumentation.ts`, `next.config.js` changes, and writes your API key to `.env.local`.
46
-
47
- ### Install This Skill in Cursor
48
-
49
- Save this file as `.cursor/skills/securenow-cli/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about CLI commands, security investigations, or firewall management.
50
-
51
- ## Configuration
52
-
53
- Config lives in `~/.securenow/` (global) and optionally `.securenow/` (per-project):
54
-
55
- | File | Content |
56
- |------|---------|
57
- | `~/.securenow/config.json` | `apiUrl`, `appUrl`, `defaultApp`, `output` |
58
- | `~/.securenow/credentials.json` | `token`, `email`, `expiresAt` (global) |
59
- | `.securenow/credentials.json` | `token`, `email`, `expiresAt` (project-local, use `login --local`) |
60
-
61
- **Credential resolution order:** `SECURENOW_TOKEN` env var → `.securenow/credentials.json` (project) → `~/.securenow/credentials.json` (global).
62
-
63
- ```bash
64
- securenow config set apiUrl https://api.securenow.ai
65
- securenow config set defaultApp my-app-key
66
- securenow config get # show all
67
- securenow config get defaultApp # show one
68
- securenow config path # print file paths + active auth source
69
- ```
70
-
71
- Environment overrides: `SECURENOW_TOKEN` (JWT), `SECURENOW_API_URL`, `SECURENOW_APP_URL`, `SECURENOW_APP` (default app key).
72
-
73
- ## Global Flags
74
-
75
- | Flag | Short | Effect |
76
- |------|-------|--------|
77
- | `--json` | `-j` | JSON output (pipe-friendly) |
78
- | `--help` | | Show help for any command |
79
- | `--verbose` | `-v` | Verbose output |
80
- | `--force` | `-f` | Skip confirmations |
81
- | `--yes` | `-y` | Auto-confirm prompts |
82
-
83
- Debug mode: `SECURENOW_DEBUG=1 securenow <cmd>` prints stack traces on errors.
84
-
85
- ---
86
-
87
- ## Command Reference
88
-
89
- ### Run — Instrument Any Node.js App
90
-
91
- ```bash
92
- securenow run <script> # auto-detect CJS/ESM, inject OTel preload
93
- securenow run --watch src/index.js # pass Node flags through
94
- securenow run --inspect src/server.js --port 3000
95
- securenow src/index.js # shorthand — auto-detected as "run"
96
- ```
97
-
98
- Spawns `node --require securenow/register [--import otel/hook.mjs] <script>`. ESM detection uses nearest `package.json` `"type"` field or `.mjs`/`.cjs` extension.
99
-
100
- ### Authentication
101
-
102
- ```bash
103
- securenow login # browser-based OAuth (stores in global ~/.securenow/)
104
- securenow login --token <JWT> # headless / CI login
105
- securenow login --local # save credentials to project .securenow/ (per-project session)
106
- securenow logout # clear active credentials (local if present, else global)
107
- securenow logout --local # clear project-local credentials only
108
- securenow whoami # show email, user ID, API URL, auth source, expiry, default app
109
- ```
110
-
111
- ### Applications
112
-
113
- ```bash
114
- securenow apps # list all apps (default subcommand)
115
- securenow apps list # same as above
116
- securenow apps create <name> [--hosts h1,h2] [--instance <id>] # interactive instance picker
117
- securenow apps info <id> # show app details
118
- securenow apps delete <id> [--force] # delete an app
119
- securenow apps default <app-key> # set default app for all commands
120
- securenow apps discover [appId] [--domain example.com] # discover subdomains, add as apps
121
- securenow apps scan [--yes] # scan all app domains for new subdomains
122
- ```
123
-
124
- ### Init — Project Setup
125
-
126
- ```bash
127
- securenow init [--key <API_KEY>]
128
- ```
129
-
130
- Auto-detects framework (Next.js, Nuxt, Express, Fastify, Koa, Hapi, Node) from `package.json`. Then:
131
- - **Next.js**: creates `instrumentation.ts/js`, suggests `withSecureNow()` in `next.config`
132
- - **Nuxt**: tells you to add `securenow/nuxt` to modules
133
- - **Node/Express/etc.**: suggests adding `-r securenow/register` to start script
134
- - Writes `SECURENOW_API_KEY` to `.env.local` or `.env` if `--key` provided
135
-
136
- ### Dashboard & Status
137
-
138
- ```bash
139
- securenow status [--app <key>] # dashboard overview
140
- securenow analytics [--app <key>] # response analytics
141
- ```
142
-
143
- ---
144
-
145
- ### Traces
146
-
147
- ```bash
148
- securenow traces [--app <key>] [--limit N] [--start ISO] [--end ISO]
149
- securenow traces list --app my-app --limit 50
150
- securenow traces show <traceId> # full trace detail with spans
151
- securenow traces analyze <traceId> # AI-powered trace analysis
152
- ```
153
-
154
- ### Logs
155
-
156
- ```bash
157
- securenow logs [--app <key>] [--limit N] [--minutes M] [--level error|warn|info]
158
- securenow logs list --app my-app --minutes 30 --level error
159
- securenow logs trace <traceId> # logs correlated to a specific trace
160
- ```
161
-
162
- ### Notifications
163
-
164
- ```bash
165
- securenow notifications [--limit N] [--page P]
166
- securenow notifications list --limit 20
167
- securenow notifications read <id> # mark one as read
168
- securenow notifications read-all # mark all as read
169
- securenow notifications unread # unread count
170
- ```
171
-
172
- ### Alerts
173
-
174
- ```bash
175
- securenow alerts # list alert rules (default)
176
- securenow alerts rules # list alert rules (columns: Status, Applications, Schedule)
177
- securenow alerts rules show <id> # one rule; JSON: --json
178
- securenow alerts rules update <id> --applications-all # all current & future apps
179
- securenow alerts rules update <id> --apps key1,key2 # explicit app keys only
180
- securenow alerts channels # list alert channels (Slack, email, etc.)
181
- securenow alerts history [--limit N] # past triggered alerts
182
- ```
183
-
184
- ---
185
-
186
- ### IP Intelligence
187
-
188
- ```bash
189
- securenow ip <ip-address> # lookup (geo, ASN, threat score, reputation)
190
- securenow ip lookup <ip-address> # same as above
191
- securenow ip traces <ip-address> # traces originating from this IP
192
- ```
193
-
194
- ### Forensics — Natural Language Security Queries
195
-
196
- ```bash
197
- securenow forensics "show me all SQL injection attempts in the last 24h"
198
- securenow forensics query "top 10 IPs by blocked requests" --app my-app
199
- securenow forensics chat --app my-app # interactive forensics chat session
200
- securenow forensics library # view saved/template queries
201
- ```
202
-
203
- ### API Map
204
-
205
- ```bash
206
- securenow api-map # list discovered API endpoints
207
- securenow api-map list # same
208
- securenow api-map stats # endpoint statistics
209
- ```
210
-
211
- ---
212
-
213
- ### Firewall
214
-
215
- ```bash
216
- securenow firewall # show status (default)
217
- securenow firewall status # layers, sync time, blocked count, API key info
218
- securenow firewall test-ip <ip> # check if IP would be blocked
219
- ```
220
-
221
- ### Blocklist — Block Malicious IPs
222
-
223
- ```bash
224
- securenow blocklist # list blocked IPs
225
- securenow blocklist list
226
- securenow blocklist add <ip> [--reason "Brute force"]
227
- securenow blocklist remove <id>
228
- securenow blocklist stats # block counts, top reasons
229
- ```
230
-
231
- ### Allowlist — Restrict to Known IPs
232
-
233
- ```bash
234
- securenow allowlist # list allowed IPs
235
- securenow allowlist list
236
- securenow allowlist add <ip> [--label "Office"] [--reason "Corporate VPN"]
237
- securenow allowlist remove <id>
238
- securenow allowlist stats
239
- ```
240
-
241
- ### Trusted Proxies
242
-
243
- ```bash
244
- securenow trusted # list trusted IPs
245
- securenow trusted list
246
- securenow trusted add <ip> [--label "CloudFlare edge"]
247
- securenow trusted remove <id>
248
- ```
249
-
250
- ---
251
-
252
- ### False Positive Management
253
-
254
- The `fp` command manages exclusion rules that prevent known-safe traffic from triggering security alerts.
255
-
256
- ```bash
257
- securenow fp # list all exclusion rules
258
- securenow fp list
259
- securenow fp show <id> # rule details
260
- securenow fp delete <id> [--yes]
261
-
262
- # Create exclusion rules
263
- securenow fp create \
264
- --conditions '[{"field":"http.target","op":"starts_with","value":"/api/health"}]' \
265
- --match-mode all \
266
- --rule-scope any_rule \
267
- --reason "Health check endpoint"
268
-
269
- # Shorthand safe-value presets
270
- securenow fp create \
271
- --path /api/events \
272
- --method POST \
273
- --path-safe standard \
274
- --ua-safe standard \
275
- --headers-safe standard \
276
- --query-keys page,limit \
277
- --headers-keys host,content-type \
278
- --reason "Event webhook"
279
-
280
- # Edit an existing rule
281
- securenow fp edit <id> [--active true|false] [--conditions '[...]']
282
-
283
- # Test conditions against a request body
284
- securenow fp test-body '{"user":"admin"}' --conditions '[{"field":"body.user","op":"eq","value":"admin"}]'
285
- securenow fp test-body @request.json --conditions '[...]'
286
-
287
- # Dry-run conditions against the last 3 days of live traces
288
- securenow fp dry-run --conditions '[{"field":"http.target","op":"starts_with","value":"/api/webhook"}]'
289
-
290
- # AI-generate exclusion conditions from a description
291
- securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook" \
292
- --context '{"method":"POST","path":"/api/stripe/webhook"}'
293
-
294
- # Mark an IP as false positive on a specific notification
295
- securenow fp mark <notification-id> <ip> \
296
- [--conditions '[...]'] \
297
- [--reason "Known partner IP"] \
298
- [--rule-scope this_rule|specific_rules|all_existing|any_rule] \
299
- [--target-rules id1,id2]
300
- ```
301
-
302
- **Condition fields:** `http.target`, `http.method`, `http.url`, `http.user_agent`, `http.request.header.*`, `body.*`, `http.status_code`, `net.peer.ip`, and more.
303
-
304
- **Operators:** `eq`, `neq`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, `exists`, `not_exists`, `gt`, `lt`, `gte`, `lte`.
305
-
306
- **Match modes:** `all` (AND logic), `any` (OR logic).
307
-
308
- **Rule scopes:** `this_rule` (single alert rule), `specific_rules` (comma-separated IDs via `--target-rules`), `all_existing` (all current rules), `any_rule` (all current and future rules).
309
-
310
- **Safe-value presets:** `standard` or `strict`. These auto-generate conditions that whitelist common safe patterns for paths, query strings, user-agents, and headers.
311
-
312
- ---
313
-
314
- ### Instances
315
-
316
- ```bash
317
- securenow instances # list ClickHouse instances
318
- securenow instances list
319
- securenow instances test <id> # test connection
320
- ```
321
-
322
- ---
323
-
324
- ## Workflow Examples for Agentic AI
325
-
326
- ### Investigate a Security Alert
327
-
328
- ```bash
329
- securenow notifications list --limit 5 --json
330
- # IMPORTANT: parse the ipInvestigations array for each notification — see statuses below
331
- securenow ip <attacker-ip> --json
332
- securenow ip traces <attacker-ip> --json
333
- securenow traces show <trace-id> --json
334
- securenow traces analyze <trace-id> --json
335
- # Decision: block the IP
336
- securenow blocklist add <attacker-ip> --reason "Automated: SQL injection detected"
337
- ```
338
-
339
- #### Notification IP Investigation Statuses
340
-
341
- Each notification contains an `ipInvestigations` array. **Every IP has its own `status` field** that you MUST check before taking action or raising flags. Do not rely only on top-level notification fields — always cross-reference each IP's individual investigation status.
342
-
343
- | Status | Meaning | Action |
344
- |--------|---------|--------|
345
- | `open` | Still needs review — no determination yet | Investigate: run `securenow ip <ip>`, check traces, decide to block or dismiss |
346
- | `false_positive` | Trusted/dismissed by exclusion rule, verified bot, or trusted IP list | **Skip** — greyed out in UI, no action needed |
347
- | `blocked` | Already on the user's blocklist | **Skip** — already handled |
348
- | `clean` | Pipeline analyzed and cleared as benign | **Skip** — verified safe |
349
-
350
- **Critical workflow rule:** When investigating notifications, iterate `ipInvestigations[]` and **only flag or act on IPs with `status: "open"`**. IPs marked `false_positive`, `blocked`, or `clean` have already been triaged — do not re-flag them.
351
-
352
- ### Triage and Suppress a False Positive
353
-
354
- ```bash
355
- securenow notifications list --json
356
- # Identify a false positive notification
357
- securenow fp ai-fill --description "Stripe webhook calls to /api/stripe/webhook"
358
- # Review the suggested conditions, then create the rule
359
- securenow fp create --conditions '<ai-suggested-conditions>' --rule-scope any_rule --reason "Stripe webhook"
360
- # Or directly mark the notification's IP as FP
361
- securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known Stripe IP"
362
- ```
363
-
364
- ### Onboard a New Application
365
-
366
- ```bash
367
- securenow apps create my-new-app --hosts api.example.com,app.example.com
368
- securenow apps default my-new-app
369
- securenow init --key snk_live_abc123...
370
- securenow run src/index.js
371
- securenow status --json
372
- ```
373
-
374
- ### Security Posture Check
375
-
376
- ```bash
377
- securenow status --json
378
- securenow firewall status --json
379
- securenow blocklist stats --json
380
- securenow api-map stats --json
381
- securenow forensics "summarize all attacks in the last 7 days"
382
- ```
383
-
384
- ### Discover Attack Surface
385
-
386
- ```bash
387
- securenow apps discover --domain example.com
388
- securenow apps scan --yes
389
- securenow api-map list --json
390
- securenow api-map stats --json
391
- ```
392
-
393
- ---
394
-
395
- ## Output Parsing
396
-
397
- All commands support `--json` for structured output. When piping to other tools or parsing programmatically, always use `--json`. Table output is the default for human readability.
398
-
399
- ## Error Handling
400
-
401
- | Exit code / Error | Meaning | Recovery |
402
- |------------------|---------|----------|
403
- | `Session expired` | JWT expired | `securenow login` (or `login --local`) |
404
- | `Not logged in` | No token found | `securenow login` or set `SECURENOW_TOKEN` env var |
405
- | `Access denied (403)` | Insufficient plan or permissions | Upgrade plan or check user role |
406
- | `Cannot connect` | API unreachable | Check `SECURENOW_API_URL` or network |
407
- | `Unknown command` | Typo or unrecognized command | `securenow help` |
408
-
409
- Set `SECURENOW_DEBUG=1` for full stack traces on any error.
package/cidr.js DELETED
@@ -1,83 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Bitmask-based CIDR matching. No regex on user input — prevents ReDoS.
5
- * All operations use unsigned 32-bit integers for IPv4 addresses.
6
- */
7
-
8
- function ipToInt(ip) {
9
- const parts = ip.split('.');
10
- if (parts.length !== 4) return null;
11
- let result = 0;
12
- for (let i = 0; i < 4; i++) {
13
- const n = parseInt(parts[i], 10);
14
- if (isNaN(n) || n < 0 || n > 255) return null;
15
- result = (result << 8) + n;
16
- }
17
- return result >>> 0;
18
- }
19
-
20
- function parseCidr(cidr) {
21
- const slash = cidr.indexOf('/');
22
- if (slash === -1) return null;
23
- const ip = cidr.slice(0, slash);
24
- const bits = parseInt(cidr.slice(slash + 1), 10);
25
- if (isNaN(bits) || bits < 0 || bits > 32) return null;
26
- const network = ipToInt(ip);
27
- if (network === null) return null;
28
- const mask = bits === 0 ? 0 : (~((1 << (32 - bits)) - 1)) >>> 0;
29
- return { network: (network & mask) >>> 0, mask };
30
- }
31
-
32
- function matchesCidr(ipInt, cidrEntry) {
33
- return ((ipInt & cidrEntry.mask) >>> 0) === cidrEntry.network;
34
- }
35
-
36
- /**
37
- * Create a matcher from a list of IPs and CIDRs.
38
- * Returns { isBlocked(ip), stats() }.
39
- * Exact IPs use a Set for O(1) lookup; CIDRs use array scan (typically < 100 entries).
40
- */
41
- function createMatcher(ipList) {
42
- const exactSet = new Set();
43
- const cidrRanges = [];
44
-
45
- for (const entry of ipList) {
46
- const trimmed = (entry || '').trim();
47
- if (!trimmed) continue;
48
-
49
- if (trimmed.includes('/')) {
50
- const parsed = parseCidr(trimmed);
51
- if (parsed) cidrRanges.push(parsed);
52
- } else {
53
- const normalized = trimmed.replace(/^::ffff:/, '');
54
- exactSet.add(normalized);
55
- }
56
- }
57
-
58
- function isBlocked(ip) {
59
- if (!ip) return false;
60
- const normalized = ip.replace(/^::ffff:/, '');
61
-
62
- if (exactSet.has(normalized)) return true;
63
-
64
- if (cidrRanges.length > 0) {
65
- const ipInt = ipToInt(normalized);
66
- if (ipInt !== null) {
67
- for (const cidr of cidrRanges) {
68
- if (matchesCidr(ipInt, cidr)) return true;
69
- }
70
- }
71
- }
72
-
73
- return false;
74
- }
75
-
76
- function stats() {
77
- return { exact: exactSet.size, cidr: cidrRanges.length, total: exactSet.size + cidrRanges.length };
78
- }
79
-
80
- return { isBlocked, stats };
81
- }
82
-
83
- module.exports = { ipToInt, parseCidr, matchesCidr, createMatcher };