securenow 8.14.0 → 8.14.1
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/cli/automation.js +1 -1
- package/cli/challenges.js +1 -1
- package/cli/fp.js +1 -1
- package/cli/monitor.js +1 -1
- package/cli/rateLimits.js +24 -8
- package/cli/security.js +10 -10
- package/cli/ui.js +1 -0
- package/firewall.js +1 -1
- package/package.json +1 -1
package/cli/automation.js
CHANGED
|
@@ -82,7 +82,7 @@ async function list(args, flags) {
|
|
|
82
82
|
|
|
83
83
|
console.log('');
|
|
84
84
|
const rows = rules.map((rule) => [
|
|
85
|
-
ui.c.dim(
|
|
85
|
+
ui.c.dim(rule.id || rule._id || ''),
|
|
86
86
|
rule.name || '-',
|
|
87
87
|
ui.statusBadge(rule.status || 'active'),
|
|
88
88
|
formatApplications(rule),
|
package/cli/challenges.js
CHANGED
|
@@ -64,7 +64,7 @@ async function list(args, flags) {
|
|
|
64
64
|
|
|
65
65
|
console.log('');
|
|
66
66
|
const rows = rules.map((r) => [
|
|
67
|
-
ui.c.dim(
|
|
67
|
+
ui.c.dim(r.id || r._id || ''),
|
|
68
68
|
r.status === 'active' ? ui.statusBadge('active') : ui.statusBadge(r.status || 'unknown'),
|
|
69
69
|
describeTarget(r),
|
|
70
70
|
`pow:${r.difficulty}`,
|
package/cli/fp.js
CHANGED
|
@@ -76,7 +76,7 @@ async function list(args, flags) {
|
|
|
76
76
|
const rows = exclusions.map(e => {
|
|
77
77
|
const scope = e.type === 'global' ? ui.c.cyan('All Rules') : `Rule: ${ui.truncate(e.ruleName || '?', 18)}`;
|
|
78
78
|
return [
|
|
79
|
-
ui.c.dim(
|
|
79
|
+
ui.c.dim(e.id || e._id || ''),
|
|
80
80
|
scope,
|
|
81
81
|
ui.truncate(conditionsSummary(e.conditions, e.matchMode), 40),
|
|
82
82
|
(e.matchMode || 'all').toUpperCase(),
|
package/cli/monitor.js
CHANGED
|
@@ -351,7 +351,7 @@ async function notificationsList(args, flags) {
|
|
|
351
351
|
|
|
352
352
|
console.log('');
|
|
353
353
|
const rows = notifications.map(n => [
|
|
354
|
-
ui.c.dim(
|
|
354
|
+
ui.c.dim(n.id || n._id || ''),
|
|
355
355
|
ui.statusBadge(n.read ? 'read' : 'unread'),
|
|
356
356
|
ui.truncate(n.title || n.message || n.type || '', 50),
|
|
357
357
|
n.ip || '—',
|
package/cli/rateLimits.js
CHANGED
|
@@ -47,6 +47,16 @@ function describeTarget(rule) {
|
|
|
47
47
|
return parts.join(' ') || 'all traffic';
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// The bucket each request counts against: "ip", "global", "header x-api-key", "cookie session".
|
|
51
|
+
function describeKey(rule) {
|
|
52
|
+
const keyBy = rule.keyBy || 'ip';
|
|
53
|
+
return rule.keyName && (keyBy === 'header' || keyBy === 'cookie') ? `${keyBy} ${rule.keyName}` : keyBy;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isExpired(rule) {
|
|
57
|
+
return Boolean(rule.expiresAt) && new Date(rule.expiresAt).getTime() <= Date.now();
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
function naturalText(args, flags) {
|
|
51
61
|
return String(flags.text || flags.prompt || flags.query || args.join(' ') || '').trim();
|
|
52
62
|
}
|
|
@@ -62,6 +72,11 @@ function draftFromFlags(flags) {
|
|
|
62
72
|
if (flags.mode || flags['path-mode']) draft.pathMatchMode = flags.mode || flags['path-mode'];
|
|
63
73
|
if (flags.method) draft.method = flags.method;
|
|
64
74
|
if (flags['key-by'] || flags.keyBy) draft.keyBy = flags['key-by'] || flags.keyBy;
|
|
75
|
+
else if (flags.header) draft.keyBy = 'header';
|
|
76
|
+
else if (flags.cookie) draft.keyBy = 'cookie';
|
|
77
|
+
if (flags['key-name'] || flags.keyName || flags.header || flags.cookie) {
|
|
78
|
+
draft.keyName = flags['key-name'] || flags.keyName || flags.header || flags.cookie;
|
|
79
|
+
}
|
|
65
80
|
if (flags.limit) draft.limit = Number(flags.limit);
|
|
66
81
|
if (flags.window || flags['window-seconds']) draft.windowSeconds = parseWindow(flags.window || flags['window-seconds']);
|
|
67
82
|
if (flags.duration) draft.duration = flags.duration;
|
|
@@ -76,7 +91,7 @@ function printParsedDraft(data) {
|
|
|
76
91
|
['Name', draft.name || '-'],
|
|
77
92
|
['Target', describeTarget(draft)],
|
|
78
93
|
['Limit', `${draft.limit || '-'} / ${draft.windowSeconds || '-'}s`],
|
|
79
|
-
['Key by', draft
|
|
94
|
+
['Key by', describeKey(draft)],
|
|
80
95
|
['App', draft.appKey || 'all'],
|
|
81
96
|
['Environment', draft.environment || 'all'],
|
|
82
97
|
['Duration', draft.duration || 'none'],
|
|
@@ -107,16 +122,17 @@ async function list(args, flags) {
|
|
|
107
122
|
|
|
108
123
|
console.log('');
|
|
109
124
|
const rows = rules.map((r) => [
|
|
110
|
-
ui.c.dim(
|
|
111
|
-
r.status === 'active' ?
|
|
125
|
+
ui.c.dim(r.id || r._id || ''),
|
|
126
|
+
ui.statusBadge(r.status === 'active' && isExpired(r) ? 'expired' : (r.status || 'unknown')),
|
|
112
127
|
describeTarget(r),
|
|
113
128
|
`${r.limit}/${r.windowSeconds}s`,
|
|
129
|
+
describeKey(r),
|
|
114
130
|
r.applicationKey || ui.c.dim('all apps'),
|
|
115
131
|
r.environment || ui.c.dim('all envs'),
|
|
116
132
|
r.expiresAt ? new Date(r.expiresAt).toLocaleString() : ui.c.dim('permanent'),
|
|
117
133
|
ui.timeAgo(r.createdAt),
|
|
118
134
|
]);
|
|
119
|
-
ui.table(['ID', 'Status', 'Target', 'Limit', 'App', 'Env', 'Expires', 'Created'], rows);
|
|
135
|
+
ui.table(['ID', 'Status', 'Target', 'Limit', 'Per', 'App', 'Env', 'Expires', 'Created'], rows);
|
|
120
136
|
console.log('');
|
|
121
137
|
} catch (err) {
|
|
122
138
|
s.fail('Failed to fetch rate limits');
|
|
@@ -167,7 +183,7 @@ async function fromText(args, flags) {
|
|
|
167
183
|
if (flags.json) { ui.json(data); return; }
|
|
168
184
|
const r = data.rateLimit;
|
|
169
185
|
console.log('');
|
|
170
|
-
console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s`);
|
|
186
|
+
console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
|
|
171
187
|
console.log(` ${ui.c.dim('ID:')} ${r.id || r._id}`);
|
|
172
188
|
console.log('');
|
|
173
189
|
} catch (err) {
|
|
@@ -197,7 +213,7 @@ async function show(args, flags) {
|
|
|
197
213
|
['Status', r.status || '-'],
|
|
198
214
|
['Target', describeTarget(r)],
|
|
199
215
|
['Limit', `${r.limit}/${r.windowSeconds}s`],
|
|
200
|
-
['Key by',
|
|
216
|
+
['Key by', describeKey(r)],
|
|
201
217
|
['App', r.applicationKey || 'all apps'],
|
|
202
218
|
['Environment', r.environment || 'all envs'],
|
|
203
219
|
['Reason', r.reason || '-'],
|
|
@@ -251,7 +267,7 @@ async function add(args, flags) {
|
|
|
251
267
|
if (flags.json) { ui.json(data); return; }
|
|
252
268
|
const r = data.rateLimit;
|
|
253
269
|
console.log('');
|
|
254
|
-
console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s`);
|
|
270
|
+
console.log(` ${ui.c.green('ACTIVE')} ${describeTarget(r)} at ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
|
|
255
271
|
console.log(` ${ui.c.dim('ID:')} ${r.id || r._id}`);
|
|
256
272
|
console.log('');
|
|
257
273
|
} catch (err) {
|
|
@@ -330,7 +346,7 @@ async function test(args, flags) {
|
|
|
330
346
|
if (data.limited) {
|
|
331
347
|
console.log(` ${ui.c.bold(ui.c.yellow('RATE LIMITED'))} - ${data.matches.length} matching rule${data.matches.length !== 1 ? 's' : ''}`);
|
|
332
348
|
for (const r of data.matches.slice(0, 5)) {
|
|
333
|
-
console.log(` ${ui.c.dim(r.id || r._id)} ${describeTarget(r)} ${r.limit}/${r.windowSeconds}s`);
|
|
349
|
+
console.log(` ${ui.c.dim(r.id || r._id)} ${describeTarget(r)} ${r.limit}/${r.windowSeconds}s per ${describeKey(r)}`);
|
|
334
350
|
}
|
|
335
351
|
} else {
|
|
336
352
|
console.log(` ${ui.c.bold(ui.c.green('NOT LIMITED'))} - no matching rate-limit rules`);
|
package/cli/security.js
CHANGED
|
@@ -190,7 +190,7 @@ async function alertRulesList(args, flags) {
|
|
|
190
190
|
|
|
191
191
|
console.log('');
|
|
192
192
|
const rows = rules.map((r) => [
|
|
193
|
-
ui.c.dim(
|
|
193
|
+
ui.c.dim(r.id || r._id || ''),
|
|
194
194
|
r.name || '—',
|
|
195
195
|
ruleStatusBadge(r),
|
|
196
196
|
r.mode === 'test' ? ui.c.yellow('test') : ui.c.dim('prod'),
|
|
@@ -836,7 +836,7 @@ async function alertRuleExclusions(args, flags) {
|
|
|
836
836
|
if (flags.json) { ui.json(data); return; }
|
|
837
837
|
console.log('');
|
|
838
838
|
const rows = exclusions.map((e) => [
|
|
839
|
-
ui.c.dim(
|
|
839
|
+
ui.c.dim(e.id || e._id || ''),
|
|
840
840
|
e.isActive === false ? ui.statusBadge('disabled') : ui.statusBadge('active'),
|
|
841
841
|
e.matchMode || 'all',
|
|
842
842
|
ui.truncate(e.reason || e.pathPattern || JSON.stringify(e.conditions || []), 72),
|
|
@@ -862,7 +862,7 @@ async function alertChannelsList(args, flags) {
|
|
|
862
862
|
|
|
863
863
|
console.log('');
|
|
864
864
|
const rows = channels.map(ch => [
|
|
865
|
-
ui.c.dim(
|
|
865
|
+
ui.c.dim(ch.id || ch._id || ''),
|
|
866
866
|
ch.name || '—',
|
|
867
867
|
ch.type || '—',
|
|
868
868
|
ui.statusBadge(ch.enabled !== false ? 'enabled' : 'disabled'),
|
|
@@ -891,7 +891,7 @@ async function alertHistoryList(args, flags) {
|
|
|
891
891
|
|
|
892
892
|
console.log('');
|
|
893
893
|
const rows = history.map(h => [
|
|
894
|
-
ui.c.dim(
|
|
894
|
+
ui.c.dim(h.id || h._id || ''),
|
|
895
895
|
h.ruleName || h.type || '—',
|
|
896
896
|
h.severity ? ui.statusBadge(h.severity) : '—',
|
|
897
897
|
ui.truncate(h.message || h.description || '', 40),
|
|
@@ -938,7 +938,7 @@ async function blocklistList(args, flags) {
|
|
|
938
938
|
|
|
939
939
|
console.log('');
|
|
940
940
|
const rows = items.map(b => [
|
|
941
|
-
ui.c.dim(
|
|
941
|
+
ui.c.dim(b.id || b._id || ''),
|
|
942
942
|
ui.c.red(describeBlockTarget(b)),
|
|
943
943
|
ui.truncate(b.reason || '', 40),
|
|
944
944
|
b.source || '—',
|
|
@@ -1011,7 +1011,7 @@ async function revokeList(args, flags) {
|
|
|
1011
1011
|
if (flags.json) { ui.json(entries); return; }
|
|
1012
1012
|
console.log('');
|
|
1013
1013
|
ui.table(['ID', 'Type', 'Value', 'Scope', 'Expires'], entries.map((r) => [
|
|
1014
|
-
ui.c.dim(
|
|
1014
|
+
ui.c.dim(r.id || r._id || ''),
|
|
1015
1015
|
r.type,
|
|
1016
1016
|
ui.truncate(r.value, 28),
|
|
1017
1017
|
r.applicationKey || ui.c.dim('all'),
|
|
@@ -1191,7 +1191,7 @@ async function allowlistList(args, flags) {
|
|
|
1191
1191
|
|
|
1192
1192
|
console.log('');
|
|
1193
1193
|
const rows = items.map(a => [
|
|
1194
|
-
ui.c.dim(
|
|
1194
|
+
ui.c.dim(a.id || a._id || ''),
|
|
1195
1195
|
ui.c.green(a.ip || '—'),
|
|
1196
1196
|
a.label || ui.c.dim('—'),
|
|
1197
1197
|
ui.truncate(a.reason || '', 40),
|
|
@@ -1307,7 +1307,7 @@ async function trustedList(args, flags) {
|
|
|
1307
1307
|
|
|
1308
1308
|
console.log('');
|
|
1309
1309
|
const rows = items.map(t => [
|
|
1310
|
-
ui.c.dim(
|
|
1310
|
+
ui.c.dim(t.id || t._id || ''),
|
|
1311
1311
|
ui.c.green(t.ip || t.cidr || '—'),
|
|
1312
1312
|
t.label || t.description || ui.c.dim('—'),
|
|
1313
1313
|
t.applicationKey || ui.c.dim('all apps'),
|
|
@@ -1494,7 +1494,7 @@ async function forensicsLibrary(args, flags) {
|
|
|
1494
1494
|
|
|
1495
1495
|
console.log('');
|
|
1496
1496
|
const rows = queries.map(q => [
|
|
1497
|
-
ui.c.dim(
|
|
1497
|
+
ui.c.dim(q.id || q._id || ''),
|
|
1498
1498
|
q.name || q.title || '—',
|
|
1499
1499
|
ui.truncate(q.description || q.query || '', 50),
|
|
1500
1500
|
ui.timeAgo(q.createdAt),
|
|
@@ -1756,7 +1756,7 @@ async function instancesList(args, flags) {
|
|
|
1756
1756
|
|
|
1757
1757
|
console.log('');
|
|
1758
1758
|
const rows = instances.map(inst => [
|
|
1759
|
-
ui.c.dim(
|
|
1759
|
+
ui.c.dim(inst.id || inst._id || ''),
|
|
1760
1760
|
inst.name || inst.host || '—',
|
|
1761
1761
|
inst.host || '—',
|
|
1762
1762
|
inst.port != null ? String(inst.port) : '—',
|
package/cli/ui.js
CHANGED
|
@@ -354,6 +354,7 @@ function statusBadge(status) {
|
|
|
354
354
|
trusted: c.green('■ trusted'),
|
|
355
355
|
enabled: c.green('● enabled'),
|
|
356
356
|
disabled: c.dim('○ disabled'),
|
|
357
|
+
expired: c.dim('○ expired'),
|
|
357
358
|
paused: c.yellow('◆ paused'),
|
|
358
359
|
critical: c.red('▲ critical'),
|
|
359
360
|
high: c.red('▲ high'),
|
package/firewall.js
CHANGED
|
@@ -1478,7 +1478,7 @@ function init(options) {
|
|
|
1478
1478
|
_rateLimitStore = require('./rate-limit-store').createRateLimitStore(storeSpec, {
|
|
1479
1479
|
log: (...args) => { if (_options.log) fwLog(...args); },
|
|
1480
1480
|
});
|
|
1481
|
-
if (_options.log && _rateLimitStore) fwLog('[securenow] Firewall: shared rate-limit counters
|
|
1481
|
+
if (_options.log && _rateLimitStore) fwLog('[securenow] Firewall: shared rate-limit counters: connecting to %s', _rateLimitStore.describe());
|
|
1482
1482
|
} catch (e) {
|
|
1483
1483
|
_rateLimitStore = null;
|
|
1484
1484
|
if (_options.log) fwWarn('[securenow] Firewall: rate-limit store disabled (%s); counting in-process', e.message);
|
package/package.json
CHANGED