@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.
- package/deno.json +1 -1
- package/dist_serve/bundle.js +1529 -1382
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +7 -2
- package/dist_ts/classes.dcrouter.js +61 -9
- package/dist_ts/db/documents/classes.authentication-event.doc.d.ts +25 -0
- package/dist_ts/db/documents/classes.authentication-event.doc.js +273 -0
- package/dist_ts/db/documents/classes.email-traffic-bucket.doc.d.ts +25 -0
- package/dist_ts/db/documents/classes.email-traffic-bucket.doc.js +200 -0
- package/dist_ts/db/documents/classes.smtp-account.doc.d.ts +31 -0
- package/dist_ts/db/documents/classes.smtp-account.doc.js +176 -0
- package/dist_ts/db/documents/index.d.ts +3 -0
- package/dist_ts/db/documents/index.js +4 -1
- package/dist_ts/email/classes.accepted-email-spool.d.ts +1 -0
- package/dist_ts/email/classes.accepted-email-spool.js +9 -1
- package/dist_ts/email/classes.email-settings.manager.d.ts +7 -0
- package/dist_ts/email/classes.email-settings.manager.js +30 -1
- package/dist_ts/email/classes.smtp-account.manager.d.ts +110 -0
- package/dist_ts/email/classes.smtp-account.manager.js +507 -0
- package/dist_ts/email/classes.workapp-mail-manager.d.ts +23 -4
- package/dist_ts/email/classes.workapp-mail-manager.js +39 -46
- package/dist_ts/email/index.d.ts +2 -0
- package/dist_ts/email/index.js +3 -1
- package/dist_ts/email/smtp-scram.d.ts +13 -0
- package/dist_ts/email/smtp-scram.js +19 -0
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +19 -0
- package/dist_ts/monitoring/classes.metricsmanager.js +240 -44
- package/dist_ts/opsserver/classes.opsserver.d.ts +1 -0
- package/dist_ts/opsserver/classes.opsserver.js +3 -1
- package/dist_ts/opsserver/handlers/admin.handler.d.ts +1 -0
- package/dist_ts/opsserver/handlers/admin.handler.js +61 -14
- package/dist_ts/opsserver/handlers/email-settings.handler.js +14 -2
- package/dist_ts/opsserver/handlers/index.d.ts +1 -0
- package/dist_ts/opsserver/handlers/index.js +2 -1
- package/dist_ts/opsserver/handlers/security.handler.js +21 -3
- package/dist_ts/opsserver/handlers/smtp-account.handler.d.ts +20 -0
- package/dist_ts/opsserver/handlers/smtp-account.handler.js +155 -0
- package/dist_ts/opsserver/handlers/stats.handler.js +27 -10
- package/dist_ts/security/classes.authentication-event-manager.d.ts +35 -0
- package/dist_ts/security/classes.authentication-event-manager.js +185 -0
- package/dist_ts/security/index.d.ts +1 -0
- package/dist_ts/security/index.js +2 -1
- package/dist_ts_interfaces/data/email-settings.d.ts +10 -0
- package/dist_ts_interfaces/data/index.d.ts +1 -0
- package/dist_ts_interfaces/data/index.js +2 -1
- package/dist_ts_interfaces/data/route-management.d.ts +1 -1
- package/dist_ts_interfaces/data/route-management.js +3 -1
- package/dist_ts_interfaces/data/smtp-account.d.ts +50 -0
- package/dist_ts_interfaces/data/smtp-account.js +9 -0
- package/dist_ts_interfaces/data/stats.d.ts +16 -0
- package/dist_ts_interfaces/requests/index.d.ts +1 -0
- package/dist_ts_interfaces/requests/index.js +2 -1
- package/dist_ts_interfaces/requests/smtp-accounts.d.ts +125 -0
- package/dist_ts_interfaces/requests/smtp-accounts.js +2 -0
- package/dist_ts_migrations/index.js +186 -13
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate/smtp-accounts.d.ts +38 -0
- package/dist_ts_web/appstate/smtp-accounts.js +94 -0
- package/dist_ts_web/appstate.d.ts +1 -0
- package/dist_ts_web/appstate.js +2 -1
- package/dist_ts_web/elements/email/index.d.ts +1 -0
- package/dist_ts_web/elements/email/index.js +2 -1
- package/dist_ts_web/elements/email/ops-view-smtp-accounts.d.ts +25 -0
- package/dist_ts_web/elements/email/ops-view-smtp-accounts.js +598 -0
- package/dist_ts_web/elements/ops-dashboard.js +3 -1
- package/dist_ts_web/elements/overview/ops-view-overview.js +3 -2
- package/dist_ts_web/elements/security/ops-view-security-authentication.js +20 -13
- package/dist_ts_web/elements/security/ops-view-security-overview.js +8 -11
- package/dist_ts_web/router.js +2 -2
- package/package.json +2 -2
- package/readme.md +20 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +66 -8
- package/ts/db/documents/classes.authentication-event.doc.ts +248 -0
- package/ts/db/documents/classes.email-traffic-bucket.doc.ts +161 -0
- package/ts/db/documents/classes.smtp-account.doc.ts +103 -0
- package/ts/db/documents/index.ts +3 -0
- package/ts/email/classes.accepted-email-spool.ts +8 -0
- package/ts/email/classes.email-settings.manager.ts +34 -0
- package/ts/email/classes.smtp-account.manager.ts +601 -0
- package/ts/email/classes.workapp-mail-manager.ts +53 -55
- package/ts/email/index.ts +2 -0
- package/ts/email/smtp-scram.ts +24 -0
- package/ts/monitoring/classes.metricsmanager.ts +287 -50
- package/ts/opsserver/classes.opsserver.ts +2 -0
- package/ts/opsserver/handlers/admin.handler.ts +74 -15
- package/ts/opsserver/handlers/email-settings.handler.ts +13 -1
- package/ts/opsserver/handlers/index.ts +1 -0
- package/ts/opsserver/handlers/security.handler.ts +23 -2
- package/ts/opsserver/handlers/smtp-account.handler.ts +199 -0
- package/ts/opsserver/handlers/stats.handler.ts +29 -9
- package/ts/security/classes.authentication-event-manager.ts +221 -0
- package/ts/security/index.ts +1 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate/smtp-accounts.ts +143 -0
- package/ts_web/appstate.ts +1 -0
- package/ts_web/elements/email/index.ts +1 -0
- package/ts_web/elements/email/ops-view-smtp-accounts.ts +586 -0
- package/ts_web/elements/ops-dashboard.ts +2 -0
- package/ts_web/elements/overview/ops-view-overview.ts +2 -1
- package/ts_web/elements/security/ops-view-security-authentication.ts +20 -13
- package/ts_web/elements/security/ops-view-security-overview.ts +7 -12
- 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
|
+
}
|
package/ts/db/documents/index.ts
CHANGED
|
@@ -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,
|