@serve.zone/dcrouter 18.0.2 → 18.1.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.
Files changed (103) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +1529 -1382
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +7 -2
  5. package/dist_ts/classes.dcrouter.js +61 -9
  6. package/dist_ts/db/documents/classes.authentication-event.doc.d.ts +25 -0
  7. package/dist_ts/db/documents/classes.authentication-event.doc.js +273 -0
  8. package/dist_ts/db/documents/classes.email-traffic-bucket.doc.d.ts +25 -0
  9. package/dist_ts/db/documents/classes.email-traffic-bucket.doc.js +200 -0
  10. package/dist_ts/db/documents/classes.smtp-account.doc.d.ts +31 -0
  11. package/dist_ts/db/documents/classes.smtp-account.doc.js +176 -0
  12. package/dist_ts/db/documents/index.d.ts +3 -0
  13. package/dist_ts/db/documents/index.js +4 -1
  14. package/dist_ts/email/classes.accepted-email-spool.d.ts +1 -0
  15. package/dist_ts/email/classes.accepted-email-spool.js +9 -1
  16. package/dist_ts/email/classes.email-settings.manager.d.ts +7 -0
  17. package/dist_ts/email/classes.email-settings.manager.js +30 -1
  18. package/dist_ts/email/classes.smtp-account.manager.d.ts +110 -0
  19. package/dist_ts/email/classes.smtp-account.manager.js +507 -0
  20. package/dist_ts/email/classes.workapp-mail-manager.d.ts +23 -4
  21. package/dist_ts/email/classes.workapp-mail-manager.js +39 -46
  22. package/dist_ts/email/index.d.ts +2 -0
  23. package/dist_ts/email/index.js +3 -1
  24. package/dist_ts/email/smtp-scram.d.ts +13 -0
  25. package/dist_ts/email/smtp-scram.js +19 -0
  26. package/dist_ts/monitoring/classes.metricsmanager.d.ts +19 -0
  27. package/dist_ts/monitoring/classes.metricsmanager.js +240 -44
  28. package/dist_ts/opsserver/classes.opsserver.d.ts +1 -0
  29. package/dist_ts/opsserver/classes.opsserver.js +3 -1
  30. package/dist_ts/opsserver/handlers/admin.handler.d.ts +1 -0
  31. package/dist_ts/opsserver/handlers/admin.handler.js +61 -14
  32. package/dist_ts/opsserver/handlers/email-settings.handler.js +14 -2
  33. package/dist_ts/opsserver/handlers/index.d.ts +1 -0
  34. package/dist_ts/opsserver/handlers/index.js +2 -1
  35. package/dist_ts/opsserver/handlers/security.handler.js +21 -3
  36. package/dist_ts/opsserver/handlers/smtp-account.handler.d.ts +20 -0
  37. package/dist_ts/opsserver/handlers/smtp-account.handler.js +155 -0
  38. package/dist_ts/opsserver/handlers/stats.handler.js +27 -10
  39. package/dist_ts/security/classes.authentication-event-manager.d.ts +35 -0
  40. package/dist_ts/security/classes.authentication-event-manager.js +185 -0
  41. package/dist_ts/security/index.d.ts +1 -0
  42. package/dist_ts/security/index.js +2 -1
  43. package/dist_ts_interfaces/data/email-settings.d.ts +10 -0
  44. package/dist_ts_interfaces/data/index.d.ts +1 -0
  45. package/dist_ts_interfaces/data/index.js +2 -1
  46. package/dist_ts_interfaces/data/route-management.d.ts +1 -1
  47. package/dist_ts_interfaces/data/route-management.js +3 -1
  48. package/dist_ts_interfaces/data/smtp-account.d.ts +50 -0
  49. package/dist_ts_interfaces/data/smtp-account.js +9 -0
  50. package/dist_ts_interfaces/data/stats.d.ts +16 -0
  51. package/dist_ts_interfaces/requests/index.d.ts +1 -0
  52. package/dist_ts_interfaces/requests/index.js +2 -1
  53. package/dist_ts_interfaces/requests/smtp-accounts.d.ts +125 -0
  54. package/dist_ts_interfaces/requests/smtp-accounts.js +2 -0
  55. package/dist_ts_migrations/index.js +186 -13
  56. package/dist_ts_web/00_commitinfo_data.js +1 -1
  57. package/dist_ts_web/appstate/smtp-accounts.d.ts +38 -0
  58. package/dist_ts_web/appstate/smtp-accounts.js +94 -0
  59. package/dist_ts_web/appstate.d.ts +1 -0
  60. package/dist_ts_web/appstate.js +2 -1
  61. package/dist_ts_web/elements/email/index.d.ts +1 -0
  62. package/dist_ts_web/elements/email/index.js +2 -1
  63. package/dist_ts_web/elements/email/ops-view-smtp-accounts.d.ts +25 -0
  64. package/dist_ts_web/elements/email/ops-view-smtp-accounts.js +598 -0
  65. package/dist_ts_web/elements/ops-dashboard.js +3 -1
  66. package/dist_ts_web/elements/overview/ops-view-overview.js +3 -2
  67. package/dist_ts_web/elements/security/ops-view-security-authentication.js +20 -13
  68. package/dist_ts_web/elements/security/ops-view-security-overview.js +8 -11
  69. package/dist_ts_web/router.js +2 -2
  70. package/package.json +2 -2
  71. package/readme.md +20 -0
  72. package/ts/00_commitinfo_data.ts +1 -1
  73. package/ts/classes.dcrouter.ts +66 -8
  74. package/ts/db/documents/classes.authentication-event.doc.ts +248 -0
  75. package/ts/db/documents/classes.email-traffic-bucket.doc.ts +161 -0
  76. package/ts/db/documents/classes.smtp-account.doc.ts +103 -0
  77. package/ts/db/documents/index.ts +3 -0
  78. package/ts/email/classes.accepted-email-spool.ts +8 -0
  79. package/ts/email/classes.email-settings.manager.ts +34 -0
  80. package/ts/email/classes.smtp-account.manager.ts +601 -0
  81. package/ts/email/classes.workapp-mail-manager.ts +53 -55
  82. package/ts/email/index.ts +2 -0
  83. package/ts/email/smtp-scram.ts +24 -0
  84. package/ts/monitoring/classes.metricsmanager.ts +287 -50
  85. package/ts/opsserver/classes.opsserver.ts +2 -0
  86. package/ts/opsserver/handlers/admin.handler.ts +74 -15
  87. package/ts/opsserver/handlers/email-settings.handler.ts +13 -1
  88. package/ts/opsserver/handlers/index.ts +1 -0
  89. package/ts/opsserver/handlers/security.handler.ts +23 -2
  90. package/ts/opsserver/handlers/smtp-account.handler.ts +199 -0
  91. package/ts/opsserver/handlers/stats.handler.ts +29 -9
  92. package/ts/security/classes.authentication-event-manager.ts +221 -0
  93. package/ts/security/index.ts +1 -0
  94. package/ts_web/00_commitinfo_data.ts +1 -1
  95. package/ts_web/appstate/smtp-accounts.ts +143 -0
  96. package/ts_web/appstate.ts +1 -0
  97. package/ts_web/elements/email/index.ts +1 -0
  98. package/ts_web/elements/email/ops-view-smtp-accounts.ts +586 -0
  99. package/ts_web/elements/ops-dashboard.ts +2 -0
  100. package/ts_web/elements/overview/ops-view-overview.ts +2 -1
  101. package/ts_web/elements/security/ops-view-security-authentication.ts +20 -13
  102. package/ts_web/elements/security/ops-view-security-overview.ts +7 -12
  103. package/ts_web/router.ts +1 -1
@@ -0,0 +1,103 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { DcRouterDb } from '../classes.dcrouter-db.js';
3
+ import type { ISmtpScramVerifier } from '@push.rocks/smartmta';
4
+ import type {
5
+ ISmtpAccountInfo,
6
+ ISmtpAccountMailPolicy,
7
+ ISmtpAccountRecipientScope,
8
+ ISmtpAccountSenderScope,
9
+ } from '../../../ts_interfaces/data/smtp-account.js';
10
+
11
+ const getDb = () => DcRouterDb.getInstance().getDb();
12
+
13
+ /**
14
+ * Operator-managed authenticated SMTP submission account.
15
+ *
16
+ * At rest the credential is exclusively a hashed SCRAM-SHA-256 verifier —
17
+ * the plaintext password is machine-generated, shown once at create/rotate
18
+ * time, and never persisted. `toApiObject()` never exposes the verifier.
19
+ */
20
+ @plugins.smartdata.Collection(() => getDb())
21
+ export class SmtpAccountDoc extends plugins.smartdata.SmartDataDbDoc<SmtpAccountDoc, SmtpAccountDoc> {
22
+ @plugins.smartdata.unI()
23
+ @plugins.smartdata.svDb()
24
+ public id!: string;
25
+
26
+ @plugins.smartdata.index({ unique: true })
27
+ @plugins.smartdata.svDb()
28
+ public username!: string;
29
+
30
+ @plugins.smartdata.svDb()
31
+ public description: string = '';
32
+
33
+ @plugins.smartdata.svDb()
34
+ public enabled: boolean = true;
35
+
36
+ /** Hashed credential only — never a plaintext password. */
37
+ @plugins.smartdata.svDb()
38
+ public credentialVerifier!: ISmtpScramVerifier;
39
+
40
+ @plugins.smartdata.svDb()
41
+ public senderScope!: ISmtpAccountSenderScope;
42
+
43
+ @plugins.smartdata.svDb()
44
+ public recipientScope!: ISmtpAccountRecipientScope;
45
+
46
+ @plugins.smartdata.svDb()
47
+ public mailPolicy!: ISmtpAccountMailPolicy;
48
+
49
+ @plugins.smartdata.svDb()
50
+ public createdAt!: number;
51
+
52
+ @plugins.smartdata.svDb()
53
+ public updatedAt!: number;
54
+
55
+ @plugins.smartdata.svDb()
56
+ public createdBy!: string;
57
+
58
+ @plugins.smartdata.svDb()
59
+ public lastRotatedAt?: number;
60
+
61
+ constructor() {
62
+ super();
63
+ }
64
+
65
+ /** Wire representation — never carries the verifier or any secret. */
66
+ public toApiObject(): ISmtpAccountInfo {
67
+ return {
68
+ id: this.id,
69
+ username: this.username,
70
+ description: this.description || '',
71
+ enabled: this.enabled,
72
+ senderScope: {
73
+ addresses: [...(this.senderScope?.addresses || [])],
74
+ domains: [...(this.senderScope?.domains || [])],
75
+ },
76
+ recipientScope: {
77
+ mode: this.recipientScope?.mode || 'any',
78
+ addresses: [...(this.recipientScope?.addresses || [])],
79
+ domains: [...(this.recipientScope?.domains || [])],
80
+ },
81
+ mailPolicy: {
82
+ dkimSign: Boolean(this.mailPolicy?.dkimSign),
83
+ ...(this.mailPolicy?.queue ? { queue: this.mailPolicy.queue } : {}),
84
+ },
85
+ createdAt: this.createdAt,
86
+ updatedAt: this.updatedAt,
87
+ createdBy: this.createdBy,
88
+ ...(this.lastRotatedAt ? { lastRotatedAt: this.lastRotatedAt } : {}),
89
+ };
90
+ }
91
+
92
+ public static async findById(id: string): Promise<SmtpAccountDoc | null> {
93
+ return await SmtpAccountDoc.getInstance({ id });
94
+ }
95
+
96
+ public static async findByUsername(username: string): Promise<SmtpAccountDoc | null> {
97
+ return await SmtpAccountDoc.getInstance({ username });
98
+ }
99
+
100
+ public static async findAll(): Promise<SmtpAccountDoc[]> {
101
+ return await SmtpAccountDoc.getInstances({});
102
+ }
103
+ }
@@ -4,6 +4,8 @@ export * from './classes.cached.ip.reputation.js';
4
4
  export * from './classes.ip-intelligence.doc.js';
5
5
  export * from './classes.security-block-rule.doc.js';
6
6
  export * from './classes.security-policy-audit.doc.js';
7
+ export * from './classes.authentication-event.doc.js';
8
+ export * from './classes.email-traffic-bucket.doc.js';
7
9
 
8
10
  // Config document classes
9
11
  export * from './classes.route.doc.js';
@@ -42,6 +44,7 @@ export * from './classes.acme-config.doc.js';
42
44
  // Email domain management
43
45
  export * from './classes.email-domain.doc.js';
44
46
  export * from './classes.email-server-settings.doc.js';
47
+ export * from './classes.smtp-account.doc.js';
45
48
 
46
49
  // Web Push provider documents
47
50
  export * from './classes.webpush-binding.doc.js';
@@ -256,6 +256,7 @@ export class AcceptedEmailSpool {
256
256
  await this.notifyEmailQueuePersisted(cachedEmail, 'email-accepted-without-queue');
257
257
  }
258
258
 
259
+ this.trackAcceptedInboundEmail(cachedEmail);
259
260
  return {
260
261
  accepted: true,
261
262
  smtpCode: 250,
@@ -319,6 +320,7 @@ export class AcceptedEmailSpool {
319
320
  await this.notifyEmailQueuePersisted(cachedEmail, 'raw-email-accepted-without-queue');
320
321
  }
321
322
 
323
+ this.trackAcceptedInboundEmail(cachedEmail);
322
324
  return {
323
325
  accepted: true,
324
326
  spoolItemId: cachedEmail.id,
@@ -480,6 +482,12 @@ export class AcceptedEmailSpool {
480
482
  logger.log('warn', `Durable envelope ${cachedEmail.id}: ${failed.length}/${dispatchResult.results.length} non-store recipients failed dispatch: ${failed.map((result) => `${result.recipient}=${result.message || result.status}`).join('; ')}`);
481
483
  }
482
484
  }
485
+ this.trackAcceptedInboundEmail(cachedEmail);
486
+ }
487
+
488
+ private trackAcceptedInboundEmail(cachedEmailArg: CachedEmail): void {
489
+ if (cachedEmailArg.direction !== 'inbound') return;
490
+ this.dcRouterRef.metricsManager?.trackEmailReceived(cachedEmailArg.from);
483
491
  }
484
492
 
485
493
  /**
@@ -1,6 +1,8 @@
1
1
  import type { IUnifiedEmailServerOptions } from '@push.rocks/smartmta';
2
2
  import { EmailServerSettingsDoc } from '../db/index.js';
3
3
  import { logger } from '../logger.js';
4
+ import { isSmtpAccountRouteName } from './classes.smtp-account.manager.js';
5
+ import { isWorkAppManagedMailRouteName } from './classes.workapp-mail-manager.js';
4
6
  import type { IDcRouterOptions } from '../classes.dcrouter.js';
5
7
  import type {
6
8
  IEmailPortConfig,
@@ -216,6 +218,10 @@ export class EmailSettingsManager {
216
218
  }
217
219
  }
218
220
 
221
+ if (hasOwn(updates, 'removeRouteNames') && updates.removeRouteNames?.length) {
222
+ nextConfig.routes = this.removeRoutesByName(nextConfig.routes || [], updates.removeRouteNames);
223
+ }
224
+
219
225
  if (nextEnabled) {
220
226
  if (!nextConfig.hostname?.trim()) {
221
227
  throw new Error('Email hostname is required when email is enabled');
@@ -228,6 +234,34 @@ export class EmailSettingsManager {
228
234
  return nextConfig;
229
235
  }
230
236
 
237
+ /**
238
+ * Remove persisted legacy routes by exact name — the internal-relay
239
+ * retirement lever, not a general route editor. Refuses generated managed
240
+ * route names (those are composed at runtime, never persisted here) and
241
+ * fails loudly on unknown names instead of silently no-oping.
242
+ */
243
+ private removeRoutesByName(
244
+ routes: NonNullable<IUnifiedEmailServerOptions['routes']>,
245
+ routeNames: string[],
246
+ ): NonNullable<IUnifiedEmailServerOptions['routes']> {
247
+ let remaining = routes;
248
+ for (const routeName of routeNames) {
249
+ const name = (routeName || '').trim();
250
+ if (!name) {
251
+ throw new Error('Route removal requires a non-empty route name');
252
+ }
253
+ if (isWorkAppManagedMailRouteName(name) || isSmtpAccountRouteName(name)) {
254
+ throw new Error(`Route '${name}' is a generated managed route and cannot be removed from persisted settings`);
255
+ }
256
+ const next = remaining.filter((route) => route.name !== name);
257
+ if (next.length === remaining.length) {
258
+ throw new Error(`Email route not found in persisted settings: ${name}`);
259
+ }
260
+ remaining = next;
261
+ }
262
+ return remaining;
263
+ }
264
+
231
265
  private patchEmailPortConfig(
232
266
  existingPortConfig: IEmailPortConfig | undefined,
233
267
  updates: TEmailServerSettingsUpdate,