@serve.zone/dcrouter 13.23.0 → 13.25.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.
@@ -33,6 +33,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
33
33
  return useValue ? value : void 0;
34
34
  };
35
35
  import * as appstate from '../../appstate.js';
36
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
36
37
  import { viewHostCss } from '../shared/css.js';
37
38
  import { DeesElement, customElement, html, state, css, cssManager, } from '@design.estate/dees-element';
38
39
  import {} from '@design.estate/dees-catalog';
@@ -42,32 +43,36 @@ let OpsViewSecurityBlocked = (() => {
42
43
  let _classExtraInitializers = [];
43
44
  let _classThis;
44
45
  let _classSuper = DeesElement;
45
- let _statsState_decorators;
46
- let _statsState_initializers = [];
47
- let _statsState_extraInitializers = [];
46
+ let _securityPolicyState_decorators;
47
+ let _securityPolicyState_initializers = [];
48
+ let _securityPolicyState_extraInitializers = [];
48
49
  var OpsViewSecurityBlocked = class extends _classSuper {
49
50
  static { _classThis = this; }
50
51
  static {
51
52
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
52
- _statsState_decorators = [state()];
53
- __esDecorate(this, null, _statsState_decorators, { kind: "accessor", name: "statsState", static: false, private: false, access: { has: obj => "statsState" in obj, get: obj => obj.statsState, set: (obj, value) => { obj.statsState = value; } }, metadata: _metadata }, _statsState_initializers, _statsState_extraInitializers);
53
+ _securityPolicyState_decorators = [state()];
54
+ __esDecorate(this, null, _securityPolicyState_decorators, { kind: "accessor", name: "securityPolicyState", static: false, private: false, access: { has: obj => "securityPolicyState" in obj, get: obj => obj.securityPolicyState, set: (obj, value) => { obj.securityPolicyState = value; } }, metadata: _metadata }, _securityPolicyState_initializers, _securityPolicyState_extraInitializers);
54
55
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
55
56
  OpsViewSecurityBlocked = _classThis = _classDescriptor.value;
56
57
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
57
58
  }
58
- #statsState_accessor_storage = __runInitializers(this, _statsState_initializers, appstate.statsStatePart.getState());
59
- get statsState() { return this.#statsState_accessor_storage; }
60
- set statsState(value) { this.#statsState_accessor_storage = value; }
59
+ #securityPolicyState_accessor_storage = __runInitializers(this, _securityPolicyState_initializers, appstate.securityPolicyStatePart.getState());
60
+ get securityPolicyState() { return this.#securityPolicyState_accessor_storage; }
61
+ set securityPolicyState(value) { this.#securityPolicyState_accessor_storage = value; }
61
62
  constructor() {
62
63
  super();
63
- __runInitializers(this, _statsState_extraInitializers);
64
- const sub = appstate.statsStatePart
64
+ __runInitializers(this, _securityPolicyState_extraInitializers);
65
+ const sub = appstate.securityPolicyStatePart
65
66
  .select((s) => s)
66
67
  .subscribe((s) => {
67
- this.statsState = s;
68
+ this.securityPolicyState = s;
68
69
  });
69
70
  this.rxSubscriptions.push(sub);
70
71
  }
72
+ async connectedCallback() {
73
+ await super.connectedCallback();
74
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.fetchSecurityPolicyAction, null);
75
+ }
71
76
  static styles = [
72
77
  cssManager.defaultStyles,
73
78
  viewHostCss,
@@ -75,73 +80,423 @@ let OpsViewSecurityBlocked = (() => {
75
80
  dees-statsgrid {
76
81
  margin-bottom: 32px;
77
82
  }
83
+
84
+ .sectionStack {
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: 32px;
88
+ }
89
+
90
+ .statusBadge {
91
+ display: inline-flex;
92
+ align-items: center;
93
+ padding: 4px 8px;
94
+ border-radius: 4px;
95
+ font-size: 12px;
96
+ font-weight: 500;
97
+ }
98
+
99
+ .statusBadge.enabled {
100
+ background: ${cssManager.bdTheme('#e8f5e9', '#1a3a1a')};
101
+ color: ${cssManager.bdTheme('#388e3c', '#66bb6a')};
102
+ }
103
+
104
+ .statusBadge.disabled {
105
+ background: ${cssManager.bdTheme('#f5f5f5', '#2a2a2a')};
106
+ color: ${cssManager.bdTheme('#757575', '#999')};
107
+ }
108
+
109
+ .typeBadge {
110
+ display: inline-flex;
111
+ align-items: center;
112
+ padding: 4px 8px;
113
+ border-radius: 999px;
114
+ font-size: 12px;
115
+ font-weight: 500;
116
+ background: ${cssManager.bdTheme('#eef2ff', '#1e1b4b')};
117
+ color: ${cssManager.bdTheme('#4338ca', '#a5b4fc')};
118
+ }
119
+
120
+ .errorMessage {
121
+ padding: 12px 16px;
122
+ border-radius: 8px;
123
+ background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
124
+ color: ${cssManager.bdTheme('#b91c1c', '#fca5a5')};
125
+ }
78
126
  `,
79
127
  ];
80
128
  render() {
81
- const metrics = this.statsState.securityMetrics;
82
- if (!metrics) {
83
- return html `
84
- <div class="loadingMessage">
85
- <p>Loading security metrics...</p>
86
- </div>
87
- `;
88
- }
89
- const blockedIPs = metrics.blockedIPs || [];
129
+ const state = this.securityPolicyState;
130
+ const activeRules = state.rules.filter((rule) => rule.enabled);
131
+ const disabledRules = state.rules.length - activeRules.length;
132
+ const compiledPolicy = state.compiledPolicy || { blockedIps: [], blockedCidrs: [] };
90
133
  const tiles = [
91
134
  {
92
- id: 'totalBlocked',
93
- title: 'Blocked IPs',
94
- value: blockedIPs.length,
135
+ id: 'activeRules',
136
+ title: 'Active Rules',
137
+ value: activeRules.length,
138
+ type: 'number',
139
+ icon: 'lucide:shield-check',
140
+ color: activeRules.length > 0 ? '#ef4444' : '#22c55e',
141
+ description: `${disabledRules} disabled`,
142
+ },
143
+ {
144
+ id: 'compiledIps',
145
+ title: 'Compiled IPs',
146
+ value: compiledPolicy.blockedIps.length,
95
147
  type: 'number',
96
- icon: 'lucide:ShieldBan',
97
- color: blockedIPs.length > 0 ? '#ef4444' : '#22c55e',
98
- description: 'Currently blocked addresses',
148
+ icon: 'lucide:server-off',
149
+ color: '#ef4444',
150
+ description: 'Direct IP blocks enforced by SmartProxy',
151
+ },
152
+ {
153
+ id: 'compiledCidrs',
154
+ title: 'Compiled CIDRs',
155
+ value: compiledPolicy.blockedCidrs.length,
156
+ type: 'number',
157
+ icon: 'lucide:network',
158
+ color: '#f97316',
159
+ description: 'Network ranges pushed to enforcement layers',
160
+ },
161
+ {
162
+ id: 'intelligenceRecords',
163
+ title: 'IP Intelligence',
164
+ value: state.ipIntelligence.length,
165
+ type: 'number',
166
+ icon: 'lucide:radar',
167
+ color: '#6366f1',
168
+ description: 'Observed public IPs with enrichment',
99
169
  },
100
170
  ];
101
171
  return html `
102
- <dees-heading level="3">Blocked IPs</dees-heading>
172
+ <dees-heading level="3">Security Blocking</dees-heading>
173
+
174
+ ${state.error ? html `<div class="errorMessage">${state.error}</div>` : html ``}
103
175
 
104
176
  <dees-statsgrid
105
177
  .tiles=${tiles}
106
178
  .minTileWidth=${200}
107
179
  ></dees-statsgrid>
108
180
 
181
+ <div class="sectionStack">
182
+ ${this.renderRulesTable()}
183
+ ${this.renderCompiledPolicyTable()}
184
+ ${this.renderIpIntelligenceTable()}
185
+ ${this.renderAuditTable()}
186
+ </div>
187
+ `;
188
+ }
189
+ renderRulesTable() {
190
+ return html `
191
+ <dees-table
192
+ .heading1=${'Managed Block Rules'}
193
+ .heading2=${'Rules compiled into SmartProxy policy and remote ingress edge firewall snapshots'}
194
+ .data=${this.securityPolicyState.rules}
195
+ .rowKey=${'id'}
196
+ .displayFunction=${(rule) => ({
197
+ 'Type': html `<span class="typeBadge">${rule.type}</span>`,
198
+ 'Value': rule.value,
199
+ 'Match': rule.type === 'organization' ? (rule.matchMode || 'contains') : '-',
200
+ 'Reason': rule.reason || '-',
201
+ 'Status': html `<span class="statusBadge ${rule.enabled ? 'enabled' : 'disabled'}">${rule.enabled ? 'Enabled' : 'Disabled'}</span>`,
202
+ 'Created': this.formatDateTime(rule.createdAt),
203
+ 'Updated': this.formatDateTime(rule.updatedAt),
204
+ })}
205
+ .dataActions=${this.getRuleActions()}
206
+ searchable
207
+ .showColumnFilters=${true}
208
+ dataName="rule"
209
+ ></dees-table>
210
+ `;
211
+ }
212
+ renderCompiledPolicyTable() {
213
+ const policy = this.securityPolicyState.compiledPolicy || { blockedIps: [], blockedCidrs: [] };
214
+ const rows = [
215
+ ...policy.blockedIps.map((value) => ({ type: 'ip', value })),
216
+ ...policy.blockedCidrs.map((value) => ({ type: 'cidr', value })),
217
+ ];
218
+ return html `
219
+ <dees-table
220
+ .heading1=${'Compiled Enforcement Policy'}
221
+ .heading2=${'Concrete IPs and CIDRs currently sent to SmartProxy and remote ingress'}
222
+ .data=${rows}
223
+ .rowKey=${'value'}
224
+ .displayFunction=${(row) => ({
225
+ 'Enforcement Type': html `<span class="typeBadge">${row.type}</span>`,
226
+ 'Value': row.value,
227
+ })}
228
+ searchable
229
+ .showColumnFilters=${true}
230
+ dataName="compiled rule"
231
+ ></dees-table>
232
+ `;
233
+ }
234
+ renderIpIntelligenceTable() {
235
+ return html `
236
+ <dees-table
237
+ .heading1=${'Observed IP Intelligence'}
238
+ .heading2=${'Public IPs observed in network metrics and enriched for ASN / organization matching'}
239
+ .data=${this.securityPolicyState.ipIntelligence}
240
+ .rowKey=${'ipAddress'}
241
+ .displayFunction=${(record) => ({
242
+ 'IP Address': record.ipAddress,
243
+ 'ASN': record.asn ? `AS${record.asn}` : '-',
244
+ 'ASN Org': record.asnOrg || '-',
245
+ 'Registrant Org': record.registrantOrg || '-',
246
+ 'Country': record.countryCode || record.country || '-',
247
+ 'Network Range': record.networkRange || '-',
248
+ 'Abuse Contact': record.abuseContact || '-',
249
+ 'Seen': record.seenCount,
250
+ 'Last Seen': this.formatDateTime(record.lastSeenAt),
251
+ })}
252
+ .dataActions=${this.getIpIntelligenceActions()}
253
+ searchable
254
+ .showColumnFilters=${true}
255
+ dataName="ip intelligence record"
256
+ ></dees-table>
257
+ `;
258
+ }
259
+ renderAuditTable() {
260
+ return html `
109
261
  <dees-table
110
- .heading1=${'Blocked IP Addresses'}
111
- .heading2=${'IPs blocked due to suspicious activity'}
112
- .data=${blockedIPs.map((ip) => ({ ip }))}
113
- .displayFunction=${(item) => ({
114
- 'IP Address': item.ip,
115
- 'Reason': 'Suspicious activity',
262
+ .heading1=${'Policy Audit'}
263
+ .heading2=${'Recent security policy changes'}
264
+ .data=${this.securityPolicyState.auditEvents}
265
+ .rowKey=${'id'}
266
+ .displayFunction=${(event) => ({
267
+ 'Time': this.formatDateTime(event.createdAt),
268
+ 'Action': event.action,
269
+ 'Actor': event.actor,
270
+ 'Details': this.formatAuditDetails(event.details),
116
271
  })}
117
- .dataActions=${[
272
+ searchable
273
+ .showColumnFilters=${true}
274
+ dataName="audit event"
275
+ ></dees-table>
276
+ `;
277
+ }
278
+ getRuleActions() {
279
+ return [
280
+ {
281
+ name: 'Create Rule',
282
+ iconName: 'lucide:plus',
283
+ type: ['header'],
284
+ actionFunc: async () => this.showRuleDialog(),
285
+ },
286
+ {
287
+ name: 'Edit',
288
+ iconName: 'lucide:pencil',
289
+ type: ['inRow', 'contextmenu'],
290
+ actionFunc: async (actionData) => this.showRuleDialog(actionData.item),
291
+ },
292
+ {
293
+ name: 'Enable',
294
+ iconName: 'lucide:play',
295
+ type: ['contextmenu'],
296
+ actionRelevancyCheckFunc: (actionData) => !actionData.item.enabled,
297
+ actionFunc: async (actionData) => {
298
+ const rule = actionData.item;
299
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
300
+ id: rule.id,
301
+ enabled: true,
302
+ });
303
+ },
304
+ },
118
305
  {
119
- name: 'Unblock',
120
- iconName: 'lucide:shield-off',
306
+ name: 'Disable',
307
+ iconName: 'lucide:pause',
121
308
  type: ['contextmenu'],
122
- actionFunc: async (item) => {
123
- await this.unblockIP(item.ip);
309
+ actionRelevancyCheckFunc: (actionData) => actionData.item.enabled,
310
+ actionFunc: async (actionData) => {
311
+ const rule = actionData.item;
312
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
313
+ id: rule.id,
314
+ enabled: false,
315
+ });
124
316
  },
125
317
  },
126
318
  {
127
- name: 'Clear All',
319
+ name: 'Delete',
128
320
  iconName: 'lucide:trash-2',
129
- type: ['header'],
130
- actionFunc: async () => {
131
- await this.clearBlockedIPs();
321
+ type: ['contextmenu'],
322
+ actionFunc: async (actionData) => {
323
+ const rule = actionData.item;
324
+ if (!window.confirm(`Delete block rule ${rule.type}:${rule.value}?`))
325
+ return;
326
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.deleteSecurityBlockRuleAction, rule.id);
132
327
  },
133
328
  },
134
- ]}
135
- ></dees-table>
136
- `;
329
+ ];
330
+ }
331
+ getIpIntelligenceActions() {
332
+ return [
333
+ {
334
+ name: 'Refresh Intelligence',
335
+ iconName: 'lucide:refresh-cw',
336
+ type: ['inRow', 'contextmenu'],
337
+ actionFunc: async (actionData) => {
338
+ const record = actionData.item;
339
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.refreshIpIntelligenceAction, record.ipAddress);
340
+ },
341
+ },
342
+ {
343
+ name: 'Block IP',
344
+ iconName: 'lucide:shield-ban',
345
+ type: ['contextmenu'],
346
+ actionFunc: async (actionData) => {
347
+ const record = actionData.item;
348
+ await this.showRuleDialog(undefined, {
349
+ type: 'ip',
350
+ value: record.ipAddress,
351
+ reason: 'Blocked from IP intelligence table',
352
+ });
353
+ },
354
+ },
355
+ {
356
+ name: 'Block Network Range',
357
+ iconName: 'lucide:network',
358
+ type: ['contextmenu'],
359
+ actionRelevancyCheckFunc: (actionData) => Boolean(actionData.item.networkRange),
360
+ actionFunc: async (actionData) => {
361
+ const record = actionData.item;
362
+ await this.showRuleDialog(undefined, {
363
+ type: 'cidr',
364
+ value: record.networkRange || '',
365
+ reason: 'Blocked network range from IP intelligence table',
366
+ });
367
+ },
368
+ },
369
+ {
370
+ name: 'Block ASN',
371
+ iconName: 'lucide:radio-tower',
372
+ type: ['contextmenu'],
373
+ actionRelevancyCheckFunc: (actionData) => Boolean(actionData.item.asn),
374
+ actionFunc: async (actionData) => {
375
+ const record = actionData.item;
376
+ await this.showRuleDialog(undefined, {
377
+ type: 'asn',
378
+ value: String(record.asn),
379
+ reason: 'Blocked ASN from IP intelligence table',
380
+ });
381
+ },
382
+ },
383
+ {
384
+ name: 'Block Organization',
385
+ iconName: 'lucide:building-2',
386
+ type: ['contextmenu'],
387
+ actionRelevancyCheckFunc: (actionData) => Boolean(actionData.item.asnOrg || actionData.item.registrantOrg),
388
+ actionFunc: async (actionData) => {
389
+ const record = actionData.item;
390
+ await this.showRuleDialog(undefined, {
391
+ type: 'organization',
392
+ value: record.asnOrg || record.registrantOrg || '',
393
+ reason: 'Blocked organization from IP intelligence table',
394
+ });
395
+ },
396
+ },
397
+ ];
398
+ }
399
+ async showRuleDialog(rule, defaults = {}) {
400
+ const { DeesModal } = await import('@design.estate/dees-catalog');
401
+ const typeOptions = [
402
+ { key: 'ip', option: 'IP address' },
403
+ { key: 'cidr', option: 'CIDR / network range' },
404
+ { key: 'asn', option: 'ASN' },
405
+ { key: 'organization', option: 'Organization' },
406
+ ];
407
+ const matchModeOptions = [
408
+ { key: 'contains', option: 'Organization contains value' },
409
+ { key: 'exact', option: 'Organization exactly matches value' },
410
+ ];
411
+ const selectedType = rule?.type || defaults.type || 'ip';
412
+ const selectedMatchMode = rule?.matchMode || defaults.matchMode || 'contains';
413
+ await DeesModal.createAndShow({
414
+ heading: rule ? `Edit Block Rule: ${rule.type}:${rule.value}` : 'Create Block Rule',
415
+ content: html `
416
+ <dees-form>
417
+ ${rule ? html `` : html `
418
+ <dees-input-dropdown
419
+ .key=${'type'}
420
+ .label=${'Rule Type'}
421
+ .options=${typeOptions}
422
+ .selectedOption=${typeOptions.find((option) => option.key === selectedType)}
423
+ ></dees-input-dropdown>
424
+ `}
425
+ <dees-input-text
426
+ .key=${'value'}
427
+ .label=${'Value'}
428
+ .value=${rule?.value || defaults.value || ''}
429
+ .required=${true}
430
+ ></dees-input-text>
431
+ <dees-input-dropdown
432
+ .key=${'matchMode'}
433
+ .label=${'Organization Match Mode'}
434
+ .description=${'Only used for organization rules'}
435
+ .options=${matchModeOptions}
436
+ .selectedOption=${matchModeOptions.find((option) => option.key === selectedMatchMode)}
437
+ ></dees-input-dropdown>
438
+ <dees-input-text
439
+ .key=${'reason'}
440
+ .label=${'Reason'}
441
+ .value=${rule?.reason || defaults.reason || ''}
442
+ ></dees-input-text>
443
+ <dees-input-checkbox
444
+ .key=${'enabled'}
445
+ .label=${'Enabled'}
446
+ .value=${rule ? rule.enabled : defaults.enabled !== false}
447
+ ></dees-input-checkbox>
448
+ </dees-form>
449
+ `,
450
+ menuOptions: [
451
+ { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg) => modalArg.destroy() },
452
+ {
453
+ name: rule ? 'Save' : 'Create',
454
+ iconName: rule ? 'lucide:check' : 'lucide:plus',
455
+ action: async (modalArg) => {
456
+ const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
457
+ if (!form)
458
+ return;
459
+ const data = await form.collectFormData();
460
+ const type = (rule?.type || this.getDropdownKey(data.type));
461
+ const value = String(data.value || '').trim();
462
+ if (!type || !value)
463
+ return;
464
+ const matchMode = type === 'organization'
465
+ ? this.getDropdownKey(data.matchMode)
466
+ : undefined;
467
+ const payload = {
468
+ value,
469
+ matchMode,
470
+ reason: String(data.reason || '').trim() || undefined,
471
+ enabled: data.enabled !== false,
472
+ };
473
+ if (rule) {
474
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
475
+ id: rule.id,
476
+ ...payload,
477
+ });
478
+ }
479
+ else {
480
+ await appstate.securityPolicyStatePart.dispatchAction(appstate.createSecurityBlockRuleAction, {
481
+ type,
482
+ ...payload,
483
+ });
484
+ }
485
+ await modalArg.destroy();
486
+ },
487
+ },
488
+ ],
489
+ });
490
+ }
491
+ getDropdownKey(value) {
492
+ return typeof value === 'string' ? value : value?.key || '';
137
493
  }
138
- async clearBlockedIPs() {
139
- // SmartProxy manages IP blocking not yet exposed via API
140
- alert('Clearing blocked IPs is not yet supported from the UI.');
494
+ formatDateTime(timestamp) {
495
+ return timestamp ? new Date(timestamp).toLocaleString() : '-';
141
496
  }
142
- async unblockIP(ip) {
143
- // SmartProxy manages IP blocking — not yet exposed via API
144
- alert(`Unblocking IP ${ip} is not yet supported from the UI.`);
497
+ formatAuditDetails(details) {
498
+ const text = JSON.stringify(details);
499
+ return text.length > 160 ? `${text.slice(0, 157)}...` : text;
145
500
  }
146
501
  static {
147
502
  __runInitializers(_classThis, _classExtraInitializers);
@@ -150,4 +505,4 @@ let OpsViewSecurityBlocked = (() => {
150
505
  return OpsViewSecurityBlocked = _classThis;
151
506
  })();
152
507
  export { OpsViewSecurityBlocked };
153
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BzLXZpZXctc2VjdXJpdHktYmxvY2tlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzX3dlYi9lbGVtZW50cy9zZWN1cml0eS9vcHMtdmlldy1zZWN1cml0eS1ibG9ja2VkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssUUFBUSxNQUFNLG1CQUFtQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUUvQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLGFBQWEsRUFDYixJQUFJLEVBQ0osS0FBSyxFQUNMLEdBQUcsRUFDSCxVQUFVLEdBRVgsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQW1CLE1BQU0sNkJBQTZCLENBQUM7SUFTakQsc0JBQXNCOzRCQURsQyxhQUFhLENBQUMsMkJBQTJCLENBQUM7Ozs7c0JBQ0MsV0FBVzs7OztzQ0FBbkIsU0FBUSxXQUFXOzs7O3NDQUNwRCxLQUFLLEVBQUU7WUFDUixtTEFBUyxVQUFVLDZCQUFWLFVBQVUsK0ZBQTZEO1lBRmxGLDZLQWdHQzs7OztRQTlGQyxpRkFBNEMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUcsRUFBQztRQUFoRixJQUFTLFVBQVUsZ0RBQTZEO1FBQWhGLElBQVMsVUFBVSxzREFBNkQ7UUFFaEY7WUFDRSxLQUFLLEVBQUUsQ0FBQzs7WUFDUixNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsY0FBYztpQkFDaEMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7aUJBQ2hCLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO2dCQUNmLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDO1lBQ3RCLENBQUMsQ0FBQyxDQUFDO1lBQ0wsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDaEM7UUFFTSxNQUFNLENBQUMsTUFBTSxHQUFHO1lBQ3JCLFVBQVUsQ0FBQyxhQUFhO1lBQ3hCLFdBQVc7WUFDWCxHQUFHLENBQUE7Ozs7S0FJRjtTQUNGLENBQUM7UUFFSyxNQUFNO1lBQ1gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUM7WUFFaEQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNiLE9BQU8sSUFBSSxDQUFBOzs7O09BSVYsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLFVBQVUsR0FBYSxPQUFPLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztZQUV0RCxNQUFNLEtBQUssR0FBaUI7Z0JBQzFCO29CQUNFLEVBQUUsRUFBRSxjQUFjO29CQUNsQixLQUFLLEVBQUUsYUFBYTtvQkFDcEIsS0FBSyxFQUFFLFVBQVUsQ0FBQyxNQUFNO29CQUN4QixJQUFJLEVBQUUsUUFBUTtvQkFDZCxJQUFJLEVBQUUsa0JBQWtCO29CQUN4QixLQUFLLEVBQUUsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUztvQkFDcEQsV0FBVyxFQUFFLDZCQUE2QjtpQkFDM0M7YUFDRixDQUFDO1lBRUYsT0FBTyxJQUFJLENBQUE7Ozs7aUJBSUUsS0FBSzt3QkFDRSxHQUFHOzs7O29CQUlQLHNCQUFzQjtvQkFDdEIsd0NBQXdDO2dCQUM1QyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQzsyQkFDckIsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzVCLFlBQVksRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDckIsUUFBUSxFQUFFLHFCQUFxQjthQUNoQyxDQUFDO3VCQUNhO2dCQUNiO29CQUNFLElBQUksRUFBRSxTQUFTO29CQUNmLFFBQVEsRUFBRSxtQkFBbUI7b0JBQzdCLElBQUksRUFBRSxDQUFDLGFBQXNCLENBQUM7b0JBQzlCLFVBQVUsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7d0JBQ3pCLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ2hDLENBQUM7aUJBQ0Y7Z0JBQ0Q7b0JBQ0UsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLFFBQVEsRUFBRSxnQkFBZ0I7b0JBQzFCLElBQUksRUFBRSxDQUFDLFFBQWlCLENBQUM7b0JBQ3pCLFVBQVUsRUFBRSxLQUFLLElBQUksRUFBRTt3QkFDckIsTUFBTSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7b0JBQy9CLENBQUM7aUJBQ0Y7YUFDRjs7S0FFSixDQUFDO1FBQ0osQ0FBQztRQUVPLEtBQUssQ0FBQyxlQUFlO1lBQzNCLDJEQUEyRDtZQUMzRCxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBRU8sS0FBSyxDQUFDLFNBQVMsQ0FBQyxFQUFVO1lBQ2hDLDJEQUEyRDtZQUMzRCxLQUFLLENBQUMsaUJBQWlCLEVBQUUsb0NBQW9DLENBQUMsQ0FBQztRQUNqRSxDQUFDOztZQS9GVSx1REFBc0I7Ozs7O1NBQXRCLHNCQUFzQiJ9
508
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BzLXZpZXctc2VjdXJpdHktYmxvY2tlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzX3dlYi9lbGVtZW50cy9zZWN1cml0eS9vcHMtdmlldy1zZWN1cml0eS1ibG9ja2VkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssUUFBUSxNQUFNLG1CQUFtQixDQUFDO0FBQzlDLE9BQU8sS0FBSyxVQUFVLE1BQU0sc0NBQXNDLENBQUM7QUFDbkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRS9DLE9BQU8sRUFDTCxXQUFXLEVBQ1gsYUFBYSxFQUNiLElBQUksRUFDSixLQUFLLEVBQ0wsR0FBRyxFQUNILFVBQVUsR0FFWCxNQUFNLDZCQUE2QixDQUFDO0FBQ3JDLE9BQU8sRUFBbUIsTUFBTSw2QkFBNkIsQ0FBQztJQVNqRCxzQkFBc0I7NEJBRGxDLGFBQWEsQ0FBQywyQkFBMkIsQ0FBQzs7OztzQkFDQyxXQUFXOzs7O3NDQUFuQixTQUFRLFdBQVc7Ozs7K0NBQ3BELEtBQUssRUFBRTtZQUNSLDhNQUFTLG1CQUFtQiw2QkFBbkIsbUJBQW1CLGlIQUErRTtZQUY3Ryw2S0EwY0M7Ozs7UUF4Y0MsbUdBQThELFFBQVEsQ0FBQyx1QkFBdUIsQ0FBQyxRQUFRLEVBQUcsRUFBQztRQUEzRyxJQUFTLG1CQUFtQix5REFBK0U7UUFBM0csSUFBUyxtQkFBbUIsK0RBQStFO1FBRTNHO1lBQ0UsS0FBSyxFQUFFLENBQUM7O1lBQ1IsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLHVCQUF1QjtpQkFDekMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7aUJBQ2hCLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO2dCQUNmLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxDQUFDLENBQUM7WUFDL0IsQ0FB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
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@serve.zone/dcrouter",
3
3
  "private": false,
4
- "version": "13.23.0",
4
+ "version": "13.25.0",
5
5
  "description": "A multifaceted routing service handling mail and SMS delivery functions.",
6
6
  "type": "module",
7
7
  "exports": {
@@ -51,7 +51,7 @@
51
51
  "@push.rocks/smartmetrics": "^3.0.3",
52
52
  "@push.rocks/smartmigration": "1.2.0",
53
53
  "@push.rocks/smartmta": "^5.3.3",
54
- "@push.rocks/smartnetwork": "^4.6.0",
54
+ "@push.rocks/smartnetwork": "^4.7.0",
55
55
  "@push.rocks/smartpath": "^6.0.0",
56
56
  "@push.rocks/smartpromise": "^4.2.3",
57
57
  "@push.rocks/smartproxy": "^27.9.0",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '13.23.0',
6
+ version: '13.25.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -25,6 +25,9 @@ export class IpIntelligenceDoc extends plugins.smartdata.SmartDataDbDoc<IpIntell
25
25
  @plugins.smartdata.svDb()
26
26
  public networkRange: string | null = null;
27
27
 
28
+ @plugins.smartdata.svDb()
29
+ public networkCidrs: string[] | null = null;
30
+
28
31
  @plugins.smartdata.svDb()
29
32
  public abuseContact: string | null = null;
30
33
 
@@ -178,6 +178,30 @@ export class SecurityHandler {
178
178
  ),
179
179
  );
180
180
 
181
+ router.addTypedHandler(
182
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetCompiledSecurityPolicy>(
183
+ 'getCompiledSecurityPolicy',
184
+ async () => {
185
+ const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
186
+ return {
187
+ policy: manager
188
+ ? await manager.compilePolicy()
189
+ : { blockedIps: [], blockedCidrs: [] },
190
+ };
191
+ },
192
+ ),
193
+ );
194
+
195
+ router.addTypedHandler(
196
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListSecurityPolicyAudit>(
197
+ 'listSecurityPolicyAudit',
198
+ async (dataArg) => {
199
+ const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
200
+ return { events: manager ? await manager.listAuditEvents(dataArg.limit || 100) : [] };
201
+ },
202
+ ),
203
+ );
204
+
181
205
  const adminRouter = this.opsServerRef.adminRouter;
182
206
 
183
207
  adminRouter.addTypedHandler(
@@ -226,6 +250,20 @@ export class SecurityHandler {
226
250
  },
227
251
  ),
228
252
  );
253
+
254
+ adminRouter.addTypedHandler(
255
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RefreshIpIntelligence>(
256
+ 'refreshIpIntelligence',
257
+ async (dataArg) => {
258
+ const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
259
+ if (!manager) return { success: false, message: 'Security policy manager not initialized' };
260
+ const record = await manager.refreshIpIntelligence(dataArg.ipAddress);
261
+ return record
262
+ ? { success: true, record }
263
+ : { success: false, message: 'IP address is invalid or not public' };
264
+ },
265
+ ),
266
+ );
229
267
  }
230
268
 
231
269
  private async collectSecurityMetrics(): Promise<{