@serve.zone/dcrouter 16.4.1 → 17.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 (82) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +852 -852
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +5 -1
  5. package/dist_ts/classes.dcrouter.js +42 -9
  6. package/dist_ts/db/documents/classes.dns-record.doc.d.ts +4 -0
  7. package/dist_ts/db/documents/classes.dns-record.doc.js +33 -2
  8. package/dist_ts/db/documents/classes.email-domain.doc.d.ts +5 -1
  9. package/dist_ts/db/documents/classes.email-domain.doc.js +26 -2
  10. package/dist_ts/db/documents/classes.smartmta-storage.doc.d.ts +8 -0
  11. package/dist_ts/db/documents/classes.smartmta-storage.doc.js +91 -0
  12. package/dist_ts/db/documents/index.d.ts +1 -0
  13. package/dist_ts/db/documents/index.js +2 -1
  14. package/dist_ts/dns/manager.dns.d.ts +6 -0
  15. package/dist_ts/dns/manager.dns.js +81 -32
  16. package/dist_ts/dns/providers/cloudflare.provider.d.ts +2 -0
  17. package/dist_ts/dns/providers/cloudflare.provider.js +45 -28
  18. package/dist_ts/email/classes.email-domain.manager.d.ts +43 -38
  19. package/dist_ts/email/classes.email-domain.manager.js +391 -324
  20. package/dist_ts/email/classes.email-settings.manager.js +2 -1
  21. package/dist_ts/email/classes.mail-dns-sync.d.ts +58 -17
  22. package/dist_ts/email/classes.mail-dns-sync.js +857 -141
  23. package/dist_ts/email/classes.mail-edge-eligibility.d.ts +55 -0
  24. package/dist_ts/email/classes.mail-edge-eligibility.js +168 -0
  25. package/dist_ts/email/classes.mail-egress-coordinator.d.ts +3 -1
  26. package/dist_ts/email/classes.mail-egress-coordinator.js +43 -22
  27. package/dist_ts/email/classes.smartmta-blob-storage-manager.d.ts +27 -0
  28. package/dist_ts/email/classes.smartmta-blob-storage-manager.js +109 -0
  29. package/dist_ts/email/classes.smartmta-storage-manager.d.ts +6 -8
  30. package/dist_ts/email/classes.smartmta-storage-manager.js +63 -86
  31. package/dist_ts/email/classes.workapp-mail-manager.d.ts +3 -0
  32. package/dist_ts/email/classes.workapp-mail-manager.js +63 -14
  33. package/dist_ts/email/index.d.ts +3 -0
  34. package/dist_ts/email/index.js +4 -1
  35. package/dist_ts/email/smartmta-storage-policy.d.ts +9 -0
  36. package/dist_ts/email/smartmta-storage-policy.js +58 -0
  37. package/dist_ts/opsserver/handlers/email-domain.handler.d.ts +1 -0
  38. package/dist_ts/opsserver/handlers/email-domain.handler.js +138 -22
  39. package/dist_ts/opsserver/handlers/stats.handler.js +3 -5
  40. package/dist_ts/plugins.d.ts +2 -1
  41. package/dist_ts/plugins.js +3 -2
  42. package/dist_ts/remoteingress/classes.hub-lifecycle.js +2 -1
  43. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +6 -0
  44. package/dist_ts/remoteingress/classes.tunnel-manager.js +40 -2
  45. package/dist_ts_interfaces/data/dns-record.d.ts +6 -0
  46. package/dist_ts_interfaces/data/email-domain.d.ts +81 -0
  47. package/dist_ts_interfaces/requests/email-domains.d.ts +25 -17
  48. package/dist_ts_migrations/index.d.ts +2 -0
  49. package/dist_ts_migrations/index.js +441 -16
  50. package/dist_ts_web/00_commitinfo_data.js +1 -1
  51. package/dist_ts_web/appstate/email-domains.d.ts +16 -0
  52. package/dist_ts_web/appstate/email-domains.js +140 -19
  53. package/dist_ts_web/elements/email/ops-view-email-domains.d.ts +1 -0
  54. package/dist_ts_web/elements/email/ops-view-email-domains.js +36 -13
  55. package/package.json +4 -3
  56. package/readme.md +13 -1
  57. package/ts/00_commitinfo_data.ts +1 -1
  58. package/ts/classes.dcrouter.ts +55 -11
  59. package/ts/db/documents/classes.dns-record.doc.ts +20 -0
  60. package/ts/db/documents/classes.email-domain.doc.ts +14 -0
  61. package/ts/db/documents/classes.smartmta-storage.doc.ts +25 -0
  62. package/ts/db/documents/index.ts +1 -0
  63. package/ts/dns/manager.dns.ts +89 -29
  64. package/ts/dns/providers/cloudflare.provider.ts +46 -27
  65. package/ts/email/classes.email-domain.manager.ts +416 -368
  66. package/ts/email/classes.email-settings.manager.ts +1 -0
  67. package/ts/email/classes.mail-dns-sync.ts +913 -146
  68. package/ts/email/classes.mail-edge-eligibility.ts +205 -0
  69. package/ts/email/classes.mail-egress-coordinator.ts +46 -23
  70. package/ts/email/classes.smartmta-blob-storage-manager.ts +138 -0
  71. package/ts/email/classes.smartmta-storage-manager.ts +86 -83
  72. package/ts/email/classes.workapp-mail-manager.ts +82 -16
  73. package/ts/email/index.ts +3 -0
  74. package/ts/email/smartmta-storage-policy.ts +73 -0
  75. package/ts/opsserver/handlers/email-domain.handler.ts +154 -21
  76. package/ts/opsserver/handlers/stats.handler.ts +2 -4
  77. package/ts/plugins.ts +2 -1
  78. package/ts/remoteingress/classes.hub-lifecycle.ts +1 -0
  79. package/ts/remoteingress/classes.tunnel-manager.ts +53 -7
  80. package/ts_web/00_commitinfo_data.ts +1 -1
  81. package/ts_web/appstate/email-domains.ts +187 -18
  82. package/ts_web/elements/email/ops-view-email-domains.ts +44 -12
@@ -0,0 +1,55 @@
1
+ import type { IRemoteIngress } from '../../dist_ts_interfaces/data/remoteingress.js';
2
+ import type { EmailDomainDoc } from '../db/documents/classes.email-domain.doc.js';
3
+ import type { DcRouter } from '../classes.dcrouter.js';
4
+ export declare const MAIL_EGRESS_IDENTITY_MAX_AGE_MS = 45000;
5
+ export interface IMailEgressIdentity {
6
+ edgeId: string;
7
+ family: 4 | 6;
8
+ address: string;
9
+ heloHostname: string;
10
+ proof: 'sourceBound';
11
+ /** Edge-side time at which the configured source address was successfully bound. */
12
+ observedAt: number;
13
+ /** Hub-side heartbeat receipt time. */
14
+ hubReceivedAt: number;
15
+ }
16
+ export interface IMailEgressIdentitySnapshot {
17
+ supported: boolean;
18
+ reason?: string;
19
+ identities: IMailEgressIdentity[];
20
+ }
21
+ /** Boundary implemented against a released RemoteIngress identity-proof API. */
22
+ export interface IEgressIdentitySource {
23
+ getSnapshot(): Promise<IMailEgressIdentitySnapshot>;
24
+ }
25
+ /**
26
+ * Reads the versioned RemoteIngress identity capability through TunnelManager.
27
+ * Older hubs do not expose `egressIdentityV1`; they remain explicitly
28
+ * unsupported instead of falling back to configured or peer addresses.
29
+ */
30
+ export declare class ReleasedRemoteIngressEgressIdentitySource implements IEgressIdentitySource {
31
+ private dcRouterRef;
32
+ constructor(dcRouterRef: DcRouter);
33
+ getSnapshot(): Promise<IMailEgressIdentitySnapshot>;
34
+ }
35
+ export interface IEligibleMailEdge {
36
+ edge: IRemoteIngress;
37
+ hostname: string;
38
+ identities: IMailEgressIdentity[];
39
+ }
40
+ export interface IMailEdgeEligibilityResult {
41
+ supported: boolean;
42
+ reason?: string;
43
+ edges: IEligibleMailEdge[];
44
+ }
45
+ /** Shared topology predicate used by DNS publication and outbound selection. */
46
+ export declare class MailEdgeEligibility {
47
+ private dcRouterRef;
48
+ private identitySource;
49
+ private lastUnscopedResult;
50
+ constructor(dcRouterRef: DcRouter, identitySource: IEgressIdentitySource);
51
+ resolveForDomain(doc?: EmailDomainDoc): Promise<IMailEdgeEligibilityResult>;
52
+ getLastUnscopedResult(): IMailEdgeEligibilityResult;
53
+ private recordUnscoped;
54
+ resolveActiveForDomain(doc: EmailDomainDoc): Promise<IMailEdgeEligibilityResult>;
55
+ }
@@ -0,0 +1,168 @@
1
+ import { REMOTE_INGRESS_MAIL_TAG } from '../../dist_ts_interfaces/data/remoteingress.js';
2
+ export const MAIL_EGRESS_IDENTITY_MAX_AGE_MS = 45_000;
3
+ /**
4
+ * Reads the versioned RemoteIngress identity capability through TunnelManager.
5
+ * Older hubs do not expose `egressIdentityV1`; they remain explicitly
6
+ * unsupported instead of falling back to configured or peer addresses.
7
+ */
8
+ export class ReleasedRemoteIngressEgressIdentitySource {
9
+ dcRouterRef;
10
+ constructor(dcRouterRef) {
11
+ this.dcRouterRef = dcRouterRef;
12
+ }
13
+ async getSnapshot() {
14
+ const status = await this.dcRouterRef.tunnelManager?.getAuthoritativeHubStatus();
15
+ const connectedEdges = status?.connectedEdges ?? [];
16
+ const capableEdges = connectedEdges.filter((edge) => (Array.isArray(edge.capabilities) && edge.capabilities.includes('egressIdentityV1')));
17
+ if (capableEdges.length > 0) {
18
+ const identities = [];
19
+ for (const edge of capableEdges) {
20
+ const report = edge.egressIdentity;
21
+ if (!report || report.proofMethod !== 'localSocketBind')
22
+ continue;
23
+ for (const [family, observation] of [[4, report.ipv4], [6, report.ipv6]]) {
24
+ if (!observation || observation.stale === true)
25
+ continue;
26
+ if (typeof observation.address !== 'string'
27
+ || !Number.isFinite(observation.edgeObservedAtUnixMs)
28
+ || !Number.isFinite(observation.hubReceivedAtUnixMs))
29
+ continue;
30
+ const configured = this.dcRouterRef.remoteIngressManager?.getEdge(String(edge.edgeId));
31
+ const heloHostname = configured?.mailHostname?.trim();
32
+ if (!heloHostname)
33
+ continue;
34
+ identities.push({
35
+ edgeId: String(edge.edgeId),
36
+ family,
37
+ address: observation.address,
38
+ heloHostname,
39
+ proof: 'sourceBound',
40
+ observedAt: observation.edgeObservedAtUnixMs,
41
+ hubReceivedAt: observation.hubReceivedAtUnixMs,
42
+ });
43
+ }
44
+ }
45
+ return { supported: true, identities };
46
+ }
47
+ return {
48
+ supported: false,
49
+ reason: 'RemoteIngress egress identity proof is unavailable until the capability release is consumed',
50
+ identities: [],
51
+ };
52
+ }
53
+ }
54
+ /** Shared topology predicate used by DNS publication and outbound selection. */
55
+ export class MailEdgeEligibility {
56
+ dcRouterRef;
57
+ identitySource;
58
+ lastUnscopedResult = {
59
+ supported: false,
60
+ reason: 'mail edge eligibility has not been evaluated yet',
61
+ edges: [],
62
+ };
63
+ constructor(dcRouterRef, identitySource) {
64
+ this.dcRouterRef = dcRouterRef;
65
+ this.identitySource = identitySource;
66
+ }
67
+ async resolveForDomain(doc) {
68
+ const snapshot = await this.identitySource.getSnapshot();
69
+ if (!snapshot.supported) {
70
+ return this.recordUnscoped(doc, { supported: false, reason: snapshot.reason, edges: [] });
71
+ }
72
+ const manager = this.dcRouterRef.remoteIngressManager;
73
+ const tunnelManager = this.dcRouterRef.tunnelManager;
74
+ if (!manager || !tunnelManager) {
75
+ return this.recordUnscoped(doc, { supported: true, reason: 'RemoteIngress hub is not running', edges: [] });
76
+ }
77
+ const pin = doc?.remoteIngress?.edgeFilter || [];
78
+ const pinIds = pin.length > 0
79
+ ? new Set(manager.resolveEdgesByFilter(pin).map((edge) => edge.id))
80
+ : undefined;
81
+ const identitiesByEdge = new Map();
82
+ const now = Date.now();
83
+ for (const identity of snapshot.identities) {
84
+ if (identity.proof !== 'sourceBound')
85
+ continue;
86
+ if (now - identity.observedAt > MAIL_EGRESS_IDENTITY_MAX_AGE_MS)
87
+ continue;
88
+ if (now - identity.hubReceivedAt > MAIL_EGRESS_IDENTITY_MAX_AGE_MS)
89
+ continue;
90
+ const entries = identitiesByEdge.get(identity.edgeId) || [];
91
+ entries.push(identity);
92
+ identitiesByEdge.set(identity.edgeId, entries);
93
+ }
94
+ const edges = [];
95
+ for (const edge of manager.getAllEdges()) {
96
+ if (!edge.enabled || !edge.tags?.includes(REMOTE_INGRESS_MAIL_TAG))
97
+ continue;
98
+ // A domain pin narrows the mail-tagged pool; it never replaces the mail tag.
99
+ if (pinIds && !pinIds.has(edge.id))
100
+ continue;
101
+ if (!edge.egress?.enabled || !edge.egress.allowedPorts?.includes(25))
102
+ continue;
103
+ const status = tunnelManager.getEdgeStatus(edge.id);
104
+ if (!status?.connected || !status.lastHeartbeat)
105
+ continue;
106
+ if (now - status.lastHeartbeat > MAIL_EGRESS_IDENTITY_MAX_AGE_MS)
107
+ continue;
108
+ if (status.egressEnabled !== true || !status.capabilities?.includes('egressTcpV1'))
109
+ continue;
110
+ const nativeQuic = status.transportMode === 'quic'
111
+ || (status.transportMode === 'quicWithFallback' && status.fallbackUsed === false);
112
+ if (!nativeQuic)
113
+ continue;
114
+ const hostname = edge.mailHostname?.toLowerCase().replace(/\.$/, '');
115
+ if (!hostname)
116
+ continue;
117
+ const identities = (identitiesByEdge.get(edge.id) || []).filter((identity) => {
118
+ if (identity.heloHostname.toLowerCase().replace(/\.$/, '') !== hostname)
119
+ return false;
120
+ return identity.family === 4
121
+ ? Boolean(edge.publicIp && edge.publicIp === identity.address)
122
+ : Boolean(edge.publicIpV6 && edge.publicIpV6 === identity.address);
123
+ });
124
+ if (identities.length > 0) {
125
+ edges.push({ edge, hostname, identities });
126
+ }
127
+ }
128
+ edges.sort((left, right) => left.edge.id.localeCompare(right.edge.id));
129
+ return this.recordUnscoped(doc, {
130
+ supported: true,
131
+ ...(edges.length === 0 ? { reason: 'no live mail-tagged edge has a fresh source-bound identity' } : {}),
132
+ edges,
133
+ });
134
+ }
135
+ getLastUnscopedResult() {
136
+ return this.lastUnscopedResult;
137
+ }
138
+ recordUnscoped(doc, result) {
139
+ if (!doc)
140
+ this.lastUnscopedResult = result;
141
+ return result;
142
+ }
143
+ async resolveActiveForDomain(doc) {
144
+ const live = await this.resolveForDomain(doc);
145
+ const active = doc.reconciliation?.activeRevision;
146
+ if (!live.supported || !active) {
147
+ return {
148
+ supported: live.supported,
149
+ reason: live.reason || 'email domain has no validated active DNS revision',
150
+ edges: [],
151
+ };
152
+ }
153
+ const activeByEdge = new Map(active.edgeIdentities.map((identity) => [identity.edgeId, identity]));
154
+ const edges = live.edges.filter((candidate) => {
155
+ const activeIdentity = activeByEdge.get(candidate.edge.id);
156
+ if (!activeIdentity || activeIdentity.hostname !== candidate.hostname)
157
+ return false;
158
+ return candidate.identities.length > 0 && candidate.identities.every((identity) => ((identity.family === 4 && identity.address === activeIdentity.ipv4)
159
+ || (identity.family === 6 && identity.address === activeIdentity.ipv6)));
160
+ });
161
+ return {
162
+ supported: live.supported,
163
+ ...(edges.length === 0 ? { reason: 'no live edge is present in the validated active DNS revision' } : {}),
164
+ edges,
165
+ };
166
+ }
167
+ }
168
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWlsLWVkZ2UtZWxpZ2liaWxpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9lbWFpbC9jbGFzc2VzLm1haWwtZWRnZS1lbGlnaWJpbGl0eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUtwRixNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxNQUFNLENBQUM7QUF5QnREOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8seUNBQXlDO0lBQ2hDO0lBQXBCLFlBQW9CLFdBQXFCO1FBQXJCLGdCQUFXLEdBQVgsV0FBVyxDQUFVO0lBQUcsQ0FBQztJQUV0QyxLQUFLLENBQUMsV0FBVztRQUN0QixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxFQUFFLHlCQUF5QixFQUFFLENBQUM7UUFDakYsTUFBTSxjQUFjLEdBQUcsTUFBTSxFQUFFLGNBQWMsSUFBSSxFQUFFLENBQUM7UUFDcEQsTUFBTSxZQUFZLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FDbkQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FDbkYsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVCLE1BQU0sVUFBVSxHQUEwQixFQUFFLENBQUM7WUFDN0MsS0FBSyxNQUFNLElBQUksSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztnQkFDbkMsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsV0FBVyxLQUFLLGlCQUFpQjtvQkFBRSxTQUFTO2dCQUNsRSxLQUFL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
@@ -1,6 +1,7 @@
1
1
  import type { IOutboundConnectionProxy, IOutboundConnectionProxyContext } from '@push.rocks/smartmta';
2
2
  import type { IEmailOutboundEgressStatus, TEmailOutboundMode } from '../../dist_ts_interfaces/data/email-settings.js';
3
3
  import type { DcRouter } from '../classes.dcrouter.js';
4
+ import type { MailEdgeEligibility } from './classes.mail-edge-eligibility.js';
4
5
  /**
5
6
  * Routes outbound SMTP deliveries over RemoteIngress edges: resolves the
6
7
  * outbound mode per attempt (no silent direct fallback), maps sender-domain
@@ -9,8 +10,9 @@ import type { DcRouter } from '../classes.dcrouter.js';
9
10
  */
10
11
  export declare class MailEgressCoordinator {
11
12
  private dcRouterRef;
13
+ private edgeEligibility;
12
14
  private dnsClient?;
13
- constructor(dcRouterRef: DcRouter);
15
+ constructor(dcRouterRef: DcRouter, edgeEligibility: MailEdgeEligibility);
14
16
  /**
15
17
  * smartmta connectionProxyProvider. Wired unconditionally so the outbound
16
18
  * mode is resolved per delivery attempt: a failed/late settings manager
@@ -1,6 +1,5 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { logger } from '../logger.js';
3
- import { REMOTE_INGRESS_MAIL_TAG } from '../../dist_ts_interfaces/data/remoteingress.js';
4
3
  /**
5
4
  * Routes outbound SMTP deliveries over RemoteIngress edges: resolves the
6
5
  * outbound mode per attempt (no silent direct fallback), maps sender-domain
@@ -9,9 +8,11 @@ import { REMOTE_INGRESS_MAIL_TAG } from '../../dist_ts_interfaces/data/remoteing
9
8
  */
10
9
  export class MailEgressCoordinator {
11
10
  dcRouterRef;
11
+ edgeEligibility;
12
12
  dnsClient;
13
- constructor(dcRouterRef) {
13
+ constructor(dcRouterRef, edgeEligibility) {
14
14
  this.dcRouterRef = dcRouterRef;
15
+ this.edgeEligibility = edgeEligibility;
15
16
  }
16
17
  /**
17
18
  * smartmta connectionProxyProvider. Wired unconditionally so the outbound
@@ -22,6 +23,9 @@ export class MailEgressCoordinator {
22
23
  async provideConnectionProxy(context) {
23
24
  const mode = this.resolveOutboundModeStrict();
24
25
  if (mode === 'direct') {
26
+ if (context.senderDomain && await this.dcRouterRef.emailDomainManager?.getByDomain(context.senderDomain)) {
27
+ throw new Error(`Managed sender domain ${context.senderDomain} has no validated direct-egress identity policy; refusing direct hub delivery`);
28
+ }
25
29
  return null;
26
30
  }
27
31
  return await this.createRemoteIngressConnectionProxy(context);
@@ -44,11 +48,14 @@ export class MailEgressCoordinator {
44
48
  * Readiness of the RemoteIngress outbound mail egress path (mail-tagged edges).
45
49
  */
46
50
  getOutboundEgressStatus() {
47
- const tunnelManager = this.dcRouterRef.tunnelManager;
48
- if (!tunnelManager) {
49
- return { ready: false, eligibleEdgeCount: 0, reason: 'RemoteIngress hub is not running' };
50
- }
51
- return tunnelManager.getEgressReadiness([REMOTE_INGRESS_MAIL_TAG]);
51
+ const eligibility = this.edgeEligibility.getLastUnscopedResult();
52
+ return {
53
+ ready: eligibility.supported && eligibility.edges.length > 0,
54
+ eligibleEdgeCount: eligibility.edges.length,
55
+ ...(eligibility.edges.length === 0
56
+ ? { reason: eligibility.reason || 'no validated RemoteIngress mail edge is available' }
57
+ : {}),
58
+ };
52
59
  }
53
60
  /**
54
61
  * Post-start preflight: with remoteIngress outbound (the default), mail
@@ -74,15 +81,17 @@ export class MailEgressCoordinator {
74
81
  throw new Error('RemoteIngress outbound SMTP egress is enabled, but the hub is not running');
75
82
  }
76
83
  await this.assertTargetIsNotOwnMailEdge(context);
77
- // Per-domain pinning: a sender domain with a configured edgeFilter uses only
78
- // matching edges; everything else uses the mail-tagged edge pool.
79
- let edgeFilter = [REMOTE_INGRESS_MAIL_TAG];
80
- if (context.senderDomain && this.dcRouterRef.emailDomainManager) {
81
- const domain = await this.dcRouterRef.emailDomainManager.getByDomain(context.senderDomain);
82
- if (domain?.remoteIngress?.edgeFilter?.length) {
83
- edgeFilter = domain.remoteIngress.edgeFilter;
84
- }
84
+ const managedDoc = context.senderDomain
85
+ ? await (await import('../db/documents/classes.email-domain.doc.js')).EmailDomainDoc.findByDomain(context.senderDomain)
86
+ : null;
87
+ const eligible = managedDoc
88
+ ? await this.edgeEligibility.resolveActiveForDomain(managedDoc)
89
+ : await this.edgeEligibility.resolveForDomain();
90
+ if (!eligible.supported || eligible.edges.length === 0) {
91
+ throw new Error(`Outbound SMTP is not eligible${context.senderDomain ? ` for ${context.senderDomain}` : ''}: ${eligible.reason || 'no validated mail edge'}`);
85
92
  }
93
+ const eligibleById = new Map(eligible.edges.map((candidate) => [candidate.edge.id, candidate]));
94
+ const edgeFilter = [...eligibleById.keys()];
86
95
  const connectionTimeoutMs = this.dcRouterRef.options.emailConfig?.outbound?.connectionTimeout ?? 30_000;
87
96
  const proxy = await tunnelManager.startEgressTcpProxy({
88
97
  logicalHost: context.host,
@@ -92,12 +101,17 @@ export class MailEgressCoordinator {
92
101
  acceptTimeoutMs: connectionTimeoutMs,
93
102
  edgeFilter,
94
103
  });
104
+ const selected = eligibleById.get(proxy.edgeId);
105
+ if (!selected) {
106
+ await tunnelManager.stopEgressTcpProxy(proxy.proxyId).catch(() => undefined);
107
+ throw new Error(`RemoteIngress selected edge ${proxy.edgeId} outside the validated mail pool`);
108
+ }
95
109
  let closed = false;
96
110
  return {
97
111
  connectHost: proxy.listenHost,
98
112
  connectPort: proxy.listenPort,
99
113
  poolKey: `remoteIngress:${proxy.edgeId}:${context.host}:${context.port}`,
100
- ehloHostname: this.dcRouterRef.remoteIngressManager?.getEdge(proxy.edgeId)?.mailHostname,
114
+ ehloHostname: selected.hostname,
101
115
  close: async () => {
102
116
  if (closed) {
103
117
  return;
@@ -122,9 +136,13 @@ export class MailEgressCoordinator {
122
136
  * allowed to become an availability hazard.
123
137
  */
124
138
  async assertTargetIsNotOwnMailEdge(context) {
125
- const edgeIps = new Set((this.dcRouterRef.remoteIngressManager?.getAllEdges?.() || [])
126
- .map((edge) => edge.publicIp)
127
- .filter((ip) => Boolean(ip)));
139
+ const edgeIps = new Set();
140
+ for (const edge of this.dcRouterRef.remoteIngressManager?.getAllEdges?.() || []) {
141
+ if (edge.publicIp)
142
+ edgeIps.add(edge.publicIp);
143
+ if (edge.publicIpV6)
144
+ edgeIps.add(edge.publicIpV6);
145
+ }
128
146
  if (edgeIps.size === 0) {
129
147
  return;
130
148
  }
@@ -137,8 +155,11 @@ export class MailEgressCoordinator {
137
155
  if (!this.dnsClient) {
138
156
  this.dnsClient = new plugins.smartdns.dnsClientMod.Smartdns({});
139
157
  }
140
- const records = await this.dnsClient.getRecordsA(context.host);
141
- targetIps = (records || []).map((record) => record.value);
158
+ const [aRecords, aaaaRecords] = await Promise.all([
159
+ this.dnsClient.getRecordsA(context.host),
160
+ this.dnsClient.getRecordsAAAA(context.host),
161
+ ]);
162
+ targetIps = [...(aRecords || []), ...(aaaaRecords || [])].map((record) => record.value);
142
163
  }
143
164
  catch {
144
165
  return;
@@ -150,4 +171,4 @@ export class MailEgressCoordinator {
150
171
  }
151
172
  }
152
173
  }
153
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWlsLWVncmVzcy1jb29yZGluYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMubWFpbC1lZ3Jlc3MtY29vcmRpbmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUlwRjs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFHWjtJQUZaLFNBQVMsQ0FBMEM7SUFFM0QsWUFBb0IsV0FBcUI7UUFBckIsZ0JBQVcsR0FBWCxXQUFXLENBQVU7SUFBRyxDQUFDO0lBRTdDOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLHNCQUFzQixDQUNqQyxPQUF3QztRQUV4QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUM5QyxJQUFJLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN0QixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLGtDQUFrQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRDs7OztPQUlHO0lBQ0kseUJBQXlCO1FBQzlCLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1lBQzFDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUNqRSxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQy9DLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUM7UUFDcEQsQ0FBQztRQUNELE1BQU0sSUFB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
174
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWlsLWVncmVzcy1jb29yZGluYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMubWFpbC1lZ3Jlc3MtY29vcmRpbmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUt0Qzs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFJdEI7SUFDQTtJQUpGLFNBQVMsQ0FBMEM7SUFFM0QsWUFDVSxXQUFxQixFQUNyQixlQUFvQztRQURwQyxnQkFBVyxHQUFYLFdBQVcsQ0FBVTtRQUNyQixvQkFBZSxHQUFmLGVBQWUsQ0FBcUI7SUFDM0MsQ0FBQztJQUVKOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLHNCQUFzQixDQUNqQyxPQUF3QztRQUV4QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUM5QyxJQUFJLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN0QixJQUFJLE9BQU8sQ0FBQyxZQUFZLElBQUksTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLGtCQUFrQixFQUFFLFdBQVcsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDekcsTUFBTSxJQUFJLEtBQUssQ0FDYix5QkFBeUIsT0FBTyxDQUFDLFlBQVksK0VBQStFLENBQzdILENBQUM7WUFDSixDQUFDO1lBQ0QsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQ0QsT0FBTyxNQUFNLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLHlCQUF5QjtRQUM5QixJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztZQUMxQyxPQUFPLElBQUksQ0FB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
@@ -0,0 +1,27 @@
1
+ import * as plugins from '../plugins.js';
2
+ import type { IBlobStorageManager } from '@push.rocks/smartmta';
3
+ type TBlobBucket = Pick<plugins.smartbucket.Bucket, 'fastExists' | 'fastGet' | 'fastPut' | 'fastRemove' | 'listAllObjects'>;
4
+ export interface ISmartMtaBlobStorageConfig {
5
+ storageDescriptor: plugins.tsclass.storage.IStorageDescriptor;
6
+ bucketName: string;
7
+ objectPrefix?: string;
8
+ createBucketIfMissing?: boolean;
9
+ }
10
+ /**
11
+ * SmartMTA blob persistence backed by a SmartBucket bucket.
12
+ *
13
+ * The adapter accepts only SmartMTA queue and attachment namespaces and never
14
+ * maps object keys to local filesystem paths.
15
+ */
16
+ export declare class SmartMtaBlobStorageManager implements IBlobStorageManager {
17
+ private readonly bucketRef;
18
+ private readonly objectPrefix;
19
+ constructor(bucketRef: TBlobBucket, objectPrefix?: string);
20
+ static create(configArg: ISmartMtaBlobStorageConfig): Promise<SmartMtaBlobStorageManager>;
21
+ get(keyArg: string): Promise<Buffer | null>;
22
+ set(keyArg: string, valueArg: Buffer): Promise<void>;
23
+ list(prefixArg: string): Promise<string[]>;
24
+ delete(keyArg: string): Promise<void>;
25
+ private toObjectKey;
26
+ }
27
+ export {};
@@ -0,0 +1,109 @@
1
+ import * as plugins from '../plugins.js';
2
+ const SMARTMTA_BLOB_NAMESPACES = [
3
+ '/email/queue/',
4
+ '/email/attachments/',
5
+ ];
6
+ const DEFAULT_OBJECT_PREFIX = 'dcrouter/smartmta/';
7
+ const MAX_STORAGE_KEY_BYTES = 1024;
8
+ function normalizeObjectPrefix(prefixArg = DEFAULT_OBJECT_PREFIX) {
9
+ const prefix = prefixArg.trim().replace(/^\/+|\/+$/g, '');
10
+ if (!prefix || prefix.includes('\\') || prefix.includes('\0')) {
11
+ throw new Error('SmartMTA blob objectPrefix must be a non-empty object-key prefix');
12
+ }
13
+ const segments = prefix.split('/');
14
+ if (segments.some((segment) => !segment || segment === '.' || segment === '..')) {
15
+ throw new Error('SmartMTA blob objectPrefix contains an invalid path segment');
16
+ }
17
+ return `${prefix}/`;
18
+ }
19
+ function normalizeBlobKey(keyArg, allowNamespaceRoot = false) {
20
+ if (typeof keyArg !== 'string' ||
21
+ !keyArg.startsWith('/') ||
22
+ keyArg.includes('\\') ||
23
+ keyArg.includes('\0') ||
24
+ Buffer.byteLength(keyArg, 'utf8') > MAX_STORAGE_KEY_BYTES) {
25
+ throw new Error('Invalid SmartMTA blob storage key');
26
+ }
27
+ const namespace = SMARTMTA_BLOB_NAMESPACES.find((candidate) => keyArg.startsWith(candidate));
28
+ if (!namespace) {
29
+ throw new Error(`Unsupported SmartMTA blob storage namespace: ${keyArg}`);
30
+ }
31
+ const remainder = keyArg.slice(namespace.length);
32
+ if (!allowNamespaceRoot && !remainder) {
33
+ throw new Error('SmartMTA blob storage key must identify an object');
34
+ }
35
+ if (remainder && remainder.split('/').some((segment) => !segment || segment === '.' || segment === '..')) {
36
+ throw new Error('SmartMTA blob storage key contains an invalid path segment');
37
+ }
38
+ return keyArg;
39
+ }
40
+ /**
41
+ * SmartMTA blob persistence backed by a SmartBucket bucket.
42
+ *
43
+ * The adapter accepts only SmartMTA queue and attachment namespaces and never
44
+ * maps object keys to local filesystem paths.
45
+ */
46
+ export class SmartMtaBlobStorageManager {
47
+ bucketRef;
48
+ objectPrefix;
49
+ constructor(bucketRef, objectPrefix = DEFAULT_OBJECT_PREFIX) {
50
+ this.bucketRef = bucketRef;
51
+ this.objectPrefix = normalizeObjectPrefix(objectPrefix);
52
+ }
53
+ static async create(configArg) {
54
+ const bucketName = configArg.bucketName?.trim();
55
+ if (!bucketName) {
56
+ throw new Error('SmartMTA blob storage requires a bucketName');
57
+ }
58
+ const smartBucket = new plugins.smartbucket.SmartBucket(configArg.storageDescriptor);
59
+ let bucket;
60
+ if (configArg.createBucketIfMissing) {
61
+ bucket = await smartBucket.bucketExists(bucketName)
62
+ ? await smartBucket.getBucketByName(bucketName)
63
+ : await smartBucket.createBucket(bucketName);
64
+ }
65
+ else {
66
+ bucket = await smartBucket.getBucketByName(bucketName);
67
+ }
68
+ return new SmartMtaBlobStorageManager(bucket, configArg.objectPrefix);
69
+ }
70
+ async get(keyArg) {
71
+ const objectKey = this.toObjectKey(normalizeBlobKey(keyArg));
72
+ if (!(await this.bucketRef.fastExists({ path: objectKey }))) {
73
+ return null;
74
+ }
75
+ return Buffer.from(await this.bucketRef.fastGet({ path: objectKey }));
76
+ }
77
+ async set(keyArg, valueArg) {
78
+ if (!Buffer.isBuffer(valueArg)) {
79
+ throw new TypeError('SmartMTA blob storage values must be Buffers');
80
+ }
81
+ const objectKey = this.toObjectKey(normalizeBlobKey(keyArg));
82
+ await this.bucketRef.fastPut({
83
+ path: objectKey,
84
+ contents: Buffer.from(valueArg),
85
+ overwrite: true,
86
+ });
87
+ }
88
+ async list(prefixArg) {
89
+ const prefix = normalizeBlobKey(prefixArg, true);
90
+ const objectPrefix = this.toObjectKey(prefix);
91
+ const keys = [];
92
+ for await (const objectKey of this.bucketRef.listAllObjects(objectPrefix)) {
93
+ if (!objectKey.startsWith(this.objectPrefix)) {
94
+ throw new Error(`SmartBucket returned an object outside the configured prefix: ${objectKey}`);
95
+ }
96
+ const key = `/${objectKey.slice(this.objectPrefix.length)}`;
97
+ keys.push(normalizeBlobKey(key));
98
+ }
99
+ return keys.sort();
100
+ }
101
+ async delete(keyArg) {
102
+ const objectKey = this.toObjectKey(normalizeBlobKey(keyArg));
103
+ await this.bucketRef.fastRemove({ path: objectKey });
104
+ }
105
+ toObjectKey(keyArg) {
106
+ return `${this.objectPrefix}${keyArg.slice(1)}`;
107
+ }
108
+ }
109
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zbWFydG10YS1ibG9iLXN0b3JhZ2UtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuc21hcnRtdGEtYmxvYi1zdG9yYWdlLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFHekMsTUFBTSx3QkFBd0IsR0FBRztJQUMvQixlQUFlO0lBQ2YscUJBQXFCO0NBQ2IsQ0FBQztBQUNYLE1BQU0scUJBQXFCLEdBQUcsb0JBQW9CLENBQUM7QUFDbkQsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUM7QUFjbkMsU0FBUyxxQkFBcUIsQ0FBQyxTQUFTLEdBQUcscUJBQXFCO0lBQzlELE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFELElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDOUQsTUFBTSxJQUFJLEtBQUssQ0FBQyxrRUFBa0UsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ25DLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLElBQUksT0FBTyxLQUFLLEdBQUcsSUFBSSxPQUFPLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNoRixNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUNELE9BQU8sR0FBRyxNQUFNLEdBQUcsQ0FBQztBQUN0QixDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FB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
@@ -1,11 +1,9 @@
1
- import type { IStorageManagerLike } from '@push.rocks/smartmta';
2
- export declare class SmartMtaStorageManager implements IStorageManagerLike {
3
- private rootDir;
4
- private readonly resolvedRootDir;
5
- constructor(rootDir: string);
6
- private normalizeKey;
7
- private resolvePathForKey;
8
- private toStorageKey;
1
+ import * as plugins from '../plugins.js';
2
+ import type { IStorageManager } from '@push.rocks/smartmta';
3
+ export declare class SmartMtaStorageManager implements IStorageManager {
4
+ private readonly collection;
5
+ constructor(smartdataDb: plugins.smartdata.SmartdataDb);
6
+ private validateDocument;
9
7
  get(key: string): Promise<string | null>;
10
8
  set(key: string, value: string): Promise<void>;
11
9
  list(prefix: string): Promise<string[]>;