@serve.zone/dcrouter 16.4.0 → 16.5.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.
- package/deno.json +1 -1
- package/dist_serve/bundle.js +852 -852
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +2 -1
- package/dist_ts/classes.dcrouter.js +20 -4
- package/dist_ts/db/documents/classes.cached.email.js +2 -2
- package/dist_ts/db/documents/classes.dns-record.doc.d.ts +4 -0
- package/dist_ts/db/documents/classes.dns-record.doc.js +33 -2
- package/dist_ts/db/documents/classes.email-domain.doc.d.ts +5 -1
- package/dist_ts/db/documents/classes.email-domain.doc.js +26 -2
- package/dist_ts/dns/manager.dns.d.ts +6 -0
- package/dist_ts/dns/manager.dns.js +81 -32
- package/dist_ts/dns/providers/cloudflare.provider.d.ts +2 -0
- package/dist_ts/dns/providers/cloudflare.provider.js +45 -28
- package/dist_ts/email/classes.email-domain.manager.d.ts +43 -38
- package/dist_ts/email/classes.email-domain.manager.js +391 -324
- package/dist_ts/email/classes.mail-dns-sync.d.ts +58 -17
- package/dist_ts/email/classes.mail-dns-sync.js +857 -141
- package/dist_ts/email/classes.mail-edge-eligibility.d.ts +55 -0
- package/dist_ts/email/classes.mail-edge-eligibility.js +168 -0
- package/dist_ts/email/classes.mail-egress-coordinator.d.ts +3 -1
- package/dist_ts/email/classes.mail-egress-coordinator.js +43 -22
- package/dist_ts/email/classes.workapp-mail-manager.d.ts +3 -0
- package/dist_ts/email/classes.workapp-mail-manager.js +58 -12
- package/dist_ts/email/index.d.ts +1 -0
- package/dist_ts/email/index.js +2 -1
- package/dist_ts/opsserver/handlers/email-domain.handler.d.ts +1 -0
- package/dist_ts/opsserver/handlers/email-domain.handler.js +138 -22
- package/dist_ts/remoteingress/classes.hub-lifecycle.js +2 -1
- package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +6 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.js +40 -2
- package/dist_ts_interfaces/data/dns-record.d.ts +6 -0
- package/dist_ts_interfaces/data/email-domain.d.ts +81 -0
- package/dist_ts_interfaces/requests/email-domains.d.ts +25 -17
- package/dist_ts_migrations/index.js +185 -9
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate/email-domains.d.ts +16 -0
- package/dist_ts_web/appstate/email-domains.js +140 -19
- package/dist_ts_web/elements/email/ops-view-email-domains.d.ts +1 -0
- package/dist_ts_web/elements/email/ops-view-email-domains.js +36 -13
- package/package.json +7 -7
- package/readme.md +13 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +22 -3
- package/ts/db/documents/classes.cached.email.ts +1 -0
- package/ts/db/documents/classes.dns-record.doc.ts +20 -0
- package/ts/db/documents/classes.email-domain.doc.ts +14 -0
- package/ts/dns/manager.dns.ts +89 -29
- package/ts/dns/providers/cloudflare.provider.ts +46 -27
- package/ts/email/classes.email-domain.manager.ts +416 -368
- package/ts/email/classes.mail-dns-sync.ts +913 -146
- package/ts/email/classes.mail-edge-eligibility.ts +205 -0
- package/ts/email/classes.mail-egress-coordinator.ts +46 -23
- package/ts/email/classes.workapp-mail-manager.ts +69 -13
- package/ts/email/index.ts +1 -0
- package/ts/opsserver/handlers/email-domain.handler.ts +154 -21
- package/ts/remoteingress/classes.hub-lifecycle.ts +1 -0
- package/ts/remoteingress/classes.tunnel-manager.ts +53 -7
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate/email-domains.ts +187 -18
- package/ts_web/elements/email/ops-view-email-domains.ts +44 -12
|
@@ -3,18 +3,18 @@ import { logger } from '../logger.js';
|
|
|
3
3
|
import { EmailDomainDoc } from '../db/documents/classes.email-domain.doc.js';
|
|
4
4
|
import { DomainDoc } from '../db/documents/classes.domain.doc.js';
|
|
5
5
|
import { DnsRecordDoc } from '../db/documents/classes.dns-record.doc.js';
|
|
6
|
-
import { buildEmailDnsRecords } from './email-dns-records.js';
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Wires smartmta's DKIMCreator (key generation) with dcrouter's DnsManager
|
|
11
|
-
* (record creation for dcrouter-hosted and provider-managed zones) to provide
|
|
12
|
-
* a single entry point for setting up an email domain from A to Z.
|
|
7
|
+
* Persists managed email domains and projects them into SmartMTA. DNS mutation
|
|
8
|
+
* is delegated exclusively to MailDnsSync.
|
|
13
9
|
*/
|
|
14
10
|
export class EmailDomainManager {
|
|
15
11
|
dcRouter; // DcRouter — avoids circular import
|
|
16
12
|
baseEmailDomains = [];
|
|
17
|
-
|
|
13
|
+
mutationChain = Promise.resolve();
|
|
14
|
+
/** Explicit upstream capability marker; absence is deliberately fail-closed. */
|
|
15
|
+
get selectorCorrectSigningCapability() {
|
|
16
|
+
return plugins.smartmta.smartMtaCapabilities?.selectorCorrectDkimSigning === true;
|
|
17
|
+
}
|
|
18
18
|
constructor(dcRouterRef) {
|
|
19
19
|
this.dcRouter = dcRouterRef;
|
|
20
20
|
this.setBaseEmailDomains(this.dcRouter.options?.emailConfig?.domains);
|
|
@@ -23,28 +23,28 @@ export class EmailDomainManager {
|
|
|
23
23
|
this.baseEmailDomains = (domains || [])
|
|
24
24
|
.map((domainConfig) => JSON.parse(JSON.stringify(domainConfig)));
|
|
25
25
|
}
|
|
26
|
-
get dnsManager() {
|
|
27
|
-
return this.dcRouter.dnsManager;
|
|
28
|
-
}
|
|
29
26
|
get dkimCreator() {
|
|
30
27
|
return this.dcRouter.emailServer?.dkimCreator;
|
|
31
28
|
}
|
|
32
|
-
get emailHostname() {
|
|
33
|
-
return this.dcRouter.options?.emailConfig?.hostname || this.dcRouter.options?.tls?.domain || 'localhost';
|
|
34
|
-
}
|
|
35
29
|
async start() {
|
|
30
|
+
// Inbound projection is safe before the SMTP server exists. DNS scheduling
|
|
31
|
+
// starts later, after DNS, RemoteIngress, tunnel, and DKIM dependencies.
|
|
36
32
|
await this.syncManagedDomainsToRuntime();
|
|
37
33
|
}
|
|
38
34
|
async stop() {
|
|
39
|
-
this.
|
|
40
|
-
|
|
35
|
+
await this.mutationChain.catch(() => undefined);
|
|
36
|
+
}
|
|
37
|
+
supportsSelectorCorrectSigning() {
|
|
38
|
+
return this.selectorCorrectSigningCapability;
|
|
39
|
+
}
|
|
40
|
+
async runMutationExclusive(action) {
|
|
41
|
+
const result = this.mutationChain.catch(() => undefined).then(action);
|
|
42
|
+
this.mutationChain = result.then(() => undefined, () => undefined);
|
|
43
|
+
return await result;
|
|
41
44
|
}
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
// CRUD
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
45
|
async getAll() {
|
|
46
46
|
const docs = await EmailDomainDoc.findAll();
|
|
47
|
-
return docs.map((
|
|
47
|
+
return docs.map((doc) => this.docToInterface(doc));
|
|
48
48
|
}
|
|
49
49
|
async getById(id) {
|
|
50
50
|
const doc = await EmailDomainDoc.findById(id);
|
|
@@ -62,324 +62,389 @@ export class EmailDomainManager {
|
|
|
62
62
|
if (this.isDomainAlreadyConfigured(normalizedDomain))
|
|
63
63
|
return null;
|
|
64
64
|
const linkedDomain = await this.findLinkedDnsDomain(normalizedDomain);
|
|
65
|
-
if (!linkedDomain)
|
|
65
|
+
if (!linkedDomain)
|
|
66
66
|
throw new Error(`DNS domain not found for email domain: ${normalizedDomain}`);
|
|
67
|
-
}
|
|
68
67
|
const subdomain = normalizedDomain === linkedDomain.name
|
|
69
68
|
? undefined
|
|
70
69
|
: normalizedDomain.slice(0, -(linkedDomain.name.length + 1));
|
|
71
|
-
return await this.createEmailDomain({
|
|
72
|
-
linkedDomainId: linkedDomain.id,
|
|
73
|
-
subdomain,
|
|
74
|
-
});
|
|
70
|
+
return await this.createEmailDomain({ linkedDomainId: linkedDomain.id, subdomain });
|
|
75
71
|
}
|
|
76
72
|
async createEmailDomain(opts) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
73
|
+
const created = await this.runMutationExclusive(async () => {
|
|
74
|
+
const domainDoc = await DomainDoc.findById(opts.linkedDomainId);
|
|
75
|
+
if (!domainDoc)
|
|
76
|
+
throw new Error(`DNS domain not found: ${opts.linkedDomainId}`);
|
|
77
|
+
const subdomain = opts.subdomain?.trim().toLowerCase() || undefined;
|
|
78
|
+
const domainName = (subdomain ? `${subdomain}.${domainDoc.name}` : domainDoc.name).toLowerCase();
|
|
79
|
+
if (this.isDomainAlreadyConfigured(domainName)) {
|
|
80
|
+
throw new Error(`Email domain already configured for ${domainName}`);
|
|
81
|
+
}
|
|
82
|
+
if (await EmailDomainDoc.findByDomain(domainName)) {
|
|
83
|
+
throw new Error(`Email domain already exists for ${domainName}`);
|
|
84
|
+
}
|
|
85
|
+
const selector = opts.dkimSelector?.trim() || 'default';
|
|
86
|
+
if (selector !== 'default' && !this.selectorCorrectSigningCapability) {
|
|
87
|
+
throw this.capabilityError('SMARTMTA_SELECTOR_SIGNING_UNSUPPORTED', 'Custom DKIM selectors are disabled until the selector-correct SmartMTA release is consumed');
|
|
88
|
+
}
|
|
89
|
+
if (opts.rotateKeys && !this.selectorCorrectSigningCapability) {
|
|
90
|
+
throw this.capabilityError('SMARTMTA_DKIM_ROTATION_UNSUPPORTED', 'Automatic DKIM rotation is disabled until the selector-correct SmartMTA release is consumed');
|
|
91
|
+
}
|
|
92
|
+
if (!this.dkimCreator) {
|
|
93
|
+
throw new Error('DKIM key creator is not ready; email domain was not persisted');
|
|
94
|
+
}
|
|
95
|
+
const keySize = opts.dkimKeySize || 2048;
|
|
96
|
+
await this.dkimCreator.handleDKIMKeysForSelector(domainName, selector, keySize);
|
|
97
|
+
const dnsRecord = await this.dkimCreator.getDNSRecordForDomain(domainName, selector);
|
|
98
|
+
const publicKey = this.extractDkimPublicKey(dnsRecord?.value);
|
|
99
|
+
if (!publicKey) {
|
|
100
|
+
throw new Error(`DKIM key generation for ${domainName} returned no usable public key; email domain was not persisted`);
|
|
101
|
+
}
|
|
102
|
+
const now = new Date().toISOString();
|
|
103
|
+
const activeDkim = {
|
|
104
|
+
selector,
|
|
105
|
+
keySize,
|
|
106
|
+
publicKey,
|
|
107
|
+
createdAt: now,
|
|
108
|
+
};
|
|
109
|
+
const doc = new EmailDomainDoc();
|
|
110
|
+
doc.id = plugins.smartunique.shortId();
|
|
111
|
+
doc.domain = domainName;
|
|
112
|
+
doc.linkedDomainId = opts.linkedDomainId;
|
|
113
|
+
doc.subdomain = subdomain;
|
|
114
|
+
doc.dkim = {
|
|
115
|
+
selector,
|
|
116
|
+
keySize,
|
|
117
|
+
publicKey,
|
|
118
|
+
rotateKeys: opts.rotateKeys ?? false,
|
|
119
|
+
rotationIntervalDays: opts.rotationIntervalDays ?? 90,
|
|
120
|
+
retirementOverlapDays: 30,
|
|
121
|
+
};
|
|
122
|
+
doc.activeDkim = activeDkim;
|
|
123
|
+
doc.retiringDkim = [];
|
|
124
|
+
doc.remoteIngress = this.normalizeRemoteIngressPin(opts.remoteIngress, domainName);
|
|
125
|
+
doc.dnsStatus = { mx: 'unchecked', spf: 'unchecked', dkim: 'unchecked', dmarc: 'unchecked' };
|
|
126
|
+
doc.reconciliation = {
|
|
127
|
+
lifecycleStatus: 'pending',
|
|
128
|
+
desiredGeneration: 1,
|
|
129
|
+
intents: [],
|
|
130
|
+
errors: [{
|
|
131
|
+
code: 'RECONCILIATION_PENDING',
|
|
132
|
+
message: 'Initial DNS reconciliation has not completed',
|
|
133
|
+
retryable: true,
|
|
134
|
+
}],
|
|
135
|
+
capability: {
|
|
136
|
+
egressIdentityProof: 'unsupported',
|
|
137
|
+
selectorCorrectSigning: selector === 'default' || this.selectorCorrectSigningCapability
|
|
138
|
+
? 'supported'
|
|
139
|
+
: 'unsupported',
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
doc.createdAt = now;
|
|
143
|
+
doc.updatedAt = now;
|
|
99
144
|
try {
|
|
100
|
-
await
|
|
101
|
-
const dnsRecord = await this.dkimCreator.getDNSRecordForDomain(domainName, selector);
|
|
102
|
-
// Extract public key from the DNS record value
|
|
103
|
-
const match = dnsRecord?.value?.match(/p=([A-Za-z0-9+/=]+)/);
|
|
104
|
-
publicKey = match ? match[1] : undefined;
|
|
105
|
-
logger.log('info', `DKIM keys generated for ${domainName} (selector: ${selector})`);
|
|
145
|
+
await doc.save();
|
|
106
146
|
}
|
|
107
|
-
catch (
|
|
108
|
-
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error?.code === 11000 || error?.codeName === 'DuplicateKey') {
|
|
149
|
+
throw new Error(`Email domain already exists for ${domainName}`);
|
|
150
|
+
}
|
|
151
|
+
throw error;
|
|
109
152
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
keySize,
|
|
120
|
-
publicKey,
|
|
121
|
-
rotateKeys: opts.rotateKeys ?? false,
|
|
122
|
-
rotationIntervalDays: opts.rotationIntervalDays ?? 90,
|
|
123
|
-
};
|
|
124
|
-
doc.dnsStatus = {
|
|
125
|
-
mx: 'unchecked',
|
|
126
|
-
spf: 'unchecked',
|
|
127
|
-
dkim: 'unchecked',
|
|
128
|
-
dmarc: 'unchecked',
|
|
129
|
-
};
|
|
130
|
-
doc.remoteIngress = this.normalizeRemoteIngressPin(opts.remoteIngress, domainName);
|
|
131
|
-
doc.createdAt = now;
|
|
132
|
-
doc.updatedAt = now;
|
|
133
|
-
await doc.save();
|
|
134
|
-
await this.syncManagedDomainsToRuntime();
|
|
135
|
-
this.dcRouter.mailDnsSync?.requestSync(`email domain created: ${domainName}`);
|
|
136
|
-
logger.log('info', `Email domain created: ${domainName}`);
|
|
137
|
-
return this.docToInterface(doc);
|
|
153
|
+
await this.syncManagedDomainsToRuntime();
|
|
154
|
+
return { id: doc.id, domainName };
|
|
155
|
+
});
|
|
156
|
+
await this.dcRouter.mailDnsSync?.sync(`email domain created: ${created.domainName}`);
|
|
157
|
+
const current = await EmailDomainDoc.findById(created.id);
|
|
158
|
+
if (!current)
|
|
159
|
+
throw new Error(`Email domain disappeared during reconciliation: ${created.domainName}`);
|
|
160
|
+
logger.log('info', `Email domain created in ${current.reconciliation?.lifecycleStatus || 'pending'} state: ${created.domainName}`);
|
|
161
|
+
return this.docToInterface(current);
|
|
138
162
|
}
|
|
139
163
|
async updateEmailDomain(id, changes) {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
const mutation = await this.runMutationExclusive(async () => {
|
|
165
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
166
|
+
if (!doc)
|
|
167
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
168
|
+
if (changes.rotateKeys === true && !this.selectorCorrectSigningCapability) {
|
|
169
|
+
return {
|
|
170
|
+
kind: 'result',
|
|
171
|
+
result: this.unsupportedResult(doc, 'SMARTMTA_DKIM_ROTATION_UNSUPPORTED', 'Automatic DKIM rotation is disabled until the selector-correct SmartMTA release is consumed'),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (changes.rotateKeys !== undefined)
|
|
175
|
+
doc.dkim.rotateKeys = changes.rotateKeys;
|
|
176
|
+
if (changes.rotationIntervalDays !== undefined)
|
|
177
|
+
doc.dkim.rotationIntervalDays = changes.rotationIntervalDays;
|
|
178
|
+
if (changes.rateLimits !== undefined)
|
|
179
|
+
doc.rateLimits = changes.rateLimits;
|
|
180
|
+
if (changes.remoteIngress !== undefined) {
|
|
181
|
+
doc.remoteIngress = changes.remoteIngress === null
|
|
182
|
+
? undefined
|
|
183
|
+
: this.normalizeRemoteIngressPin(changes.remoteIngress, doc.domain);
|
|
184
|
+
}
|
|
185
|
+
doc.reconciliation = this.invalidateReconciliation(doc, 'EMAIL_DOMAIN_CONFIGURATION_CHANGED');
|
|
186
|
+
doc.updatedAt = new Date().toISOString();
|
|
187
|
+
await doc.save();
|
|
188
|
+
await this.syncManagedDomainsToRuntime();
|
|
189
|
+
return { kind: 'sync', domainName: doc.domain };
|
|
190
|
+
});
|
|
191
|
+
if (mutation.kind === 'result')
|
|
192
|
+
return mutation.result;
|
|
193
|
+
await this.dcRouter.mailDnsSync?.sync(`email domain updated: ${mutation.domainName}`);
|
|
194
|
+
const current = await EmailDomainDoc.findById(id);
|
|
195
|
+
if (!current)
|
|
196
|
+
throw new Error(`Email domain disappeared during reconciliation: ${id}`);
|
|
197
|
+
return this.resultForDoc(current, !this.hasDnsMutationFailure(current));
|
|
173
198
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
199
|
+
async deleteEmailDomain(id) {
|
|
200
|
+
const mutation = await this.runMutationExclusive(async () => {
|
|
201
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
202
|
+
if (!doc)
|
|
203
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
204
|
+
const bindings = await this.dcRouter.workAppMailManager?.listMailAddressBindings({ domain: doc.domain }) || [];
|
|
205
|
+
if (bindings.length > 0) {
|
|
206
|
+
return {
|
|
207
|
+
kind: 'result',
|
|
208
|
+
result: {
|
|
209
|
+
success: false,
|
|
210
|
+
lifecycleStatus: doc.reconciliation?.lifecycleStatus || 'pending',
|
|
211
|
+
code: 'EMAIL_DOMAIN_HAS_BINDINGS',
|
|
212
|
+
message: `Email domain ${doc.domain} still has ${bindings.length} WorkApp mail binding(s)`,
|
|
213
|
+
errors: [{
|
|
214
|
+
code: 'EMAIL_DOMAIN_HAS_BINDINGS',
|
|
215
|
+
message: 'Delete all WorkApp mail bindings before deleting the email domain',
|
|
216
|
+
retryable: false,
|
|
217
|
+
}],
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const now = new Date().toISOString();
|
|
222
|
+
doc.reconciliation = {
|
|
223
|
+
...(doc.reconciliation || { desiredGeneration: 1, intents: [], errors: [] }),
|
|
224
|
+
lifecycleStatus: 'deleting',
|
|
225
|
+
intents: [],
|
|
226
|
+
errors: [],
|
|
227
|
+
deletingAt: now,
|
|
228
|
+
retryAt: new Date(Date.now() + 300_000).toISOString(),
|
|
229
|
+
};
|
|
230
|
+
doc.updatedAt = now;
|
|
231
|
+
await doc.save();
|
|
232
|
+
await this.syncManagedDomainsToRuntime();
|
|
233
|
+
return { kind: 'sync', domainName: doc.domain };
|
|
234
|
+
});
|
|
235
|
+
if (mutation.kind === 'result')
|
|
236
|
+
return mutation.result;
|
|
237
|
+
await this.dcRouter.mailDnsSync?.sync(`email domain deleting: ${mutation.domainName}`);
|
|
238
|
+
const remaining = await EmailDomainDoc.findById(id);
|
|
239
|
+
if (!remaining) {
|
|
240
|
+
return { success: true, lifecycleStatus: 'deleting', message: `Email domain ${mutation.domainName} deleted` };
|
|
179
241
|
}
|
|
180
|
-
return this.
|
|
242
|
+
return this.resultForDoc(remaining, remaining.reconciliation?.errors.length === 0);
|
|
181
243
|
}
|
|
182
|
-
async deleteEmailDomain(id) {
|
|
183
|
-
const doc = await EmailDomainDoc.findById(id);
|
|
184
|
-
if (!doc)
|
|
185
|
-
throw new Error(`Email domain not found: ${id}`);
|
|
186
|
-
await doc.delete();
|
|
187
|
-
await this.syncManagedDomainsToRuntime();
|
|
188
|
-
this.dcRouter.mailDnsSync?.requestSync(`email domain deleted: ${doc.domain}`);
|
|
189
|
-
logger.log('info', `Email domain deleted: ${doc.domain}`);
|
|
190
|
-
}
|
|
191
|
-
// ---------------------------------------------------------------------------
|
|
192
|
-
// DNS record computation
|
|
193
|
-
// ---------------------------------------------------------------------------
|
|
194
|
-
/**
|
|
195
|
-
* Compute the 4 required DNS records for an email domain.
|
|
196
|
-
*/
|
|
197
244
|
async getRequiredDnsRecords(id) {
|
|
198
245
|
const doc = await EmailDomainDoc.findById(id);
|
|
199
246
|
if (!doc)
|
|
200
247
|
throw new Error(`Email domain not found: ${id}`);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
catch (err) {
|
|
214
|
-
logger.log('warn', `Failed to load DKIM DNS record for ${domain}: ${err.message}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const records = buildEmailDnsRecords({
|
|
218
|
-
domain,
|
|
219
|
-
hostname,
|
|
220
|
-
selector,
|
|
221
|
-
dkimValue,
|
|
222
|
-
statuses: doc.dnsStatus,
|
|
223
|
-
});
|
|
224
|
-
for (const edge of pinnedEdges) {
|
|
225
|
-
if (edge.publicIp) {
|
|
226
|
-
records.push({ type: 'A', name: hostname, value: edge.publicIp, status: doc.dnsStatus.mx });
|
|
227
|
-
}
|
|
228
|
-
if (edge.publicIpV6) {
|
|
229
|
-
records.push({ type: 'AAAA', name: hostname, value: edge.publicIpV6, status: doc.dnsStatus.mx });
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return records;
|
|
233
|
-
}
|
|
234
|
-
// ---------------------------------------------------------------------------
|
|
235
|
-
// DNS provisioning
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
|
-
/**
|
|
238
|
-
* Auto-create missing DNS records via the linked domain's DNS path.
|
|
239
|
-
*/
|
|
248
|
+
return (doc.reconciliation?.intents || []).map((intent) => ({
|
|
249
|
+
type: intent.type,
|
|
250
|
+
name: intent.name,
|
|
251
|
+
value: intent.value,
|
|
252
|
+
status: intent.status === 'valid'
|
|
253
|
+
? 'valid'
|
|
254
|
+
: intent.status === 'conflict' || intent.status === 'failed'
|
|
255
|
+
? 'invalid'
|
|
256
|
+
: 'missing',
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
240
259
|
async provisionDnsRecords(id) {
|
|
260
|
+
const before = new Set((await DnsRecordDoc.findAll()).filter((record) => record.managedBy === 'mail-dns-reconciler').map((record) => record.id));
|
|
261
|
+
await this.dcRouter.mailDnsSync?.sync(`manual provision: ${id}`);
|
|
241
262
|
const doc = await EmailDomainDoc.findById(id);
|
|
242
263
|
if (!doc)
|
|
243
264
|
throw new Error(`Email domain not found: ${id}`);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
// Get existing DNS records for the linked domain
|
|
249
|
-
const existingRecords = await DnsRecordDoc.findByDomainId(domainId);
|
|
250
|
-
let provisioned = 0;
|
|
251
|
-
for (const required of requiredRecords) {
|
|
252
|
-
// Check if a matching record already exists
|
|
253
|
-
const exists = existingRecords.some((r) => this.recordMatchesRequired(r, required));
|
|
254
|
-
if (!exists) {
|
|
255
|
-
try {
|
|
256
|
-
await this.dnsManager.createRecord({
|
|
257
|
-
domainId,
|
|
258
|
-
name: required.name,
|
|
259
|
-
type: required.type,
|
|
260
|
-
value: required.value,
|
|
261
|
-
ttl: 3600,
|
|
262
|
-
createdBy: 'email-domain-manager',
|
|
263
|
-
});
|
|
264
|
-
provisioned++;
|
|
265
|
-
logger.log('info', `Provisioned ${required.type} record for ${required.name}`);
|
|
266
|
-
}
|
|
267
|
-
catch (err) {
|
|
268
|
-
logger.log('warn', `Failed to provision ${required.type} for ${required.name}: ${err.message}`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
// Re-validate after provisioning
|
|
273
|
-
await this.validateDns(id);
|
|
274
|
-
return provisioned;
|
|
275
|
-
}
|
|
276
|
-
// ---------------------------------------------------------------------------
|
|
277
|
-
// DNS validation
|
|
278
|
-
// ---------------------------------------------------------------------------
|
|
279
|
-
/**
|
|
280
|
-
* Validate DNS records via live lookups.
|
|
281
|
-
*/
|
|
265
|
+
const provisioned = (await DnsRecordDoc.findAll())
|
|
266
|
+
.filter((record) => record.managedBy === 'mail-dns-reconciler' && !before.has(record.id)).length;
|
|
267
|
+
return { ...this.resultForDoc(doc, !this.hasDnsMutationFailure(doc)), provisioned };
|
|
268
|
+
}
|
|
282
269
|
async validateDns(id) {
|
|
270
|
+
await this.dcRouter.mailDnsSync?.sync(`manual validation: ${id}`);
|
|
283
271
|
const doc = await EmailDomainDoc.findById(id);
|
|
284
272
|
if (!doc)
|
|
285
273
|
throw new Error(`Email domain not found: ${id}`);
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const spfRecord = requiredRecords.find((record) => record.name === domain && record.value.startsWith('v=spf1'));
|
|
293
|
-
const dkimRecord = requiredRecords.find((record) => record.name === `${selector}._domainkey.${domain}`);
|
|
294
|
-
const dmarcRecord = requiredRecords.find((record) => record.name === `_dmarc.${domain}`);
|
|
295
|
-
doc.dnsStatus.mx = await this.checkMx(dnsClient, domain, mxRecord?.value);
|
|
296
|
-
// Pinned domains: the MX host's A records must cover the pinned edges' IPs.
|
|
297
|
-
const requiredARecords = requiredRecords.filter((record) => record.type === 'A');
|
|
298
|
-
if (doc.dnsStatus.mx === 'valid' && requiredARecords.length > 0) {
|
|
299
|
-
const mxHostname = mxRecord?.value?.split(/\s+/)[1] || `mx.${domain}`;
|
|
300
|
-
const aStatus = await this.checkARecords(dnsClient, mxHostname, requiredARecords.map((record) => record.value));
|
|
301
|
-
if (aStatus !== 'valid') {
|
|
302
|
-
doc.dnsStatus.mx = aStatus;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
// SPF check
|
|
306
|
-
doc.dnsStatus.spf = await this.checkTxtRecord(dnsClient, domain, spfRecord?.value);
|
|
307
|
-
// DKIM check
|
|
308
|
-
doc.dnsStatus.dkim = await this.checkTxtRecord(dnsClient, `${selector}._domainkey.${domain}`, dkimRecord?.value);
|
|
309
|
-
// DMARC check
|
|
310
|
-
doc.dnsStatus.dmarc = await this.checkTxtRecord(dnsClient, `_dmarc.${domain}`, dmarcRecord?.value);
|
|
311
|
-
doc.dnsStatus.lastCheckedAt = new Date().toISOString();
|
|
312
|
-
doc.updatedAt = new Date().toISOString();
|
|
313
|
-
await doc.save();
|
|
314
|
-
return this.getRequiredDnsRecords(id);
|
|
315
|
-
}
|
|
316
|
-
recordMatchesRequired(record, required) {
|
|
317
|
-
if (record.type !== required.type || record.name.toLowerCase() !== required.name.toLowerCase()) {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
return record.value.trim() === required.value.trim();
|
|
274
|
+
const records = await this.getRequiredDnsRecords(id);
|
|
275
|
+
return {
|
|
276
|
+
...this.resultForDoc(doc, doc.reconciliation?.lifecycleStatus === 'active'),
|
|
277
|
+
domain: this.docToInterface(doc),
|
|
278
|
+
records,
|
|
279
|
+
};
|
|
321
280
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (!
|
|
325
|
-
|
|
281
|
+
async getOutboundReadiness(domainName) {
|
|
282
|
+
const doc = await EmailDomainDoc.findByDomain(domainName.toLowerCase());
|
|
283
|
+
if (!doc)
|
|
284
|
+
return { ready: true, edgeIds: [] }; // unmanaged/static domain policy
|
|
285
|
+
const activeDkim = this.getActiveDkim(doc);
|
|
286
|
+
if (!activeDkim)
|
|
287
|
+
return { ready: false, reason: 'no usable active DKIM key', edgeIds: [] };
|
|
288
|
+
if (activeDkim.selector !== 'default' && !this.selectorCorrectSigningCapability) {
|
|
289
|
+
return { ready: false, reason: 'SmartMTA selector-correct signing capability is unavailable', edgeIds: [] };
|
|
326
290
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
/** 'pref exchange' normalized for comparison: numeric pref, lowercased exchange, no trailing dot. */
|
|
330
|
-
normalizeMxValue(value) {
|
|
331
|
-
const [pref, exchange = ''] = value.trim().split(/\s+/);
|
|
332
|
-
return `${Number(pref)} ${exchange.toLowerCase().replace(/\.$/, '')}`;
|
|
333
|
-
}
|
|
334
|
-
async checkMx(dnsClient, domain, expectedValue) {
|
|
335
|
-
try {
|
|
336
|
-
const records = await dnsClient.getRecords(domain, 'MX');
|
|
337
|
-
if (!records || records.length === 0) {
|
|
338
|
-
return 'missing';
|
|
339
|
-
}
|
|
340
|
-
if (!expectedValue) {
|
|
341
|
-
return 'valid';
|
|
342
|
-
}
|
|
343
|
-
const expected = this.normalizeMxValue(expectedValue);
|
|
344
|
-
const found = records.some((record) => this.normalizeMxValue(record.value) === expected);
|
|
345
|
-
return found ? 'valid' : 'invalid';
|
|
291
|
+
if (!doc.reconciliation?.activeRevision) {
|
|
292
|
+
return { ready: false, reason: 'no validated active DNS revision', edgeIds: [] };
|
|
346
293
|
}
|
|
347
|
-
|
|
348
|
-
|
|
294
|
+
const live = await this.dcRouter.mailEdgeEligibility.resolveActiveForDomain(doc);
|
|
295
|
+
if (live.edges.length === 0) {
|
|
296
|
+
return { ready: false, reason: live.reason || 'no validated active egress edge is live', edgeIds: [] };
|
|
349
297
|
}
|
|
298
|
+
return {
|
|
299
|
+
ready: true,
|
|
300
|
+
edgeIds: live.edges.map((candidate) => candidate.edge.id),
|
|
301
|
+
selector: activeDkim.selector,
|
|
302
|
+
};
|
|
350
303
|
}
|
|
351
|
-
async
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
if (!
|
|
355
|
-
|
|
304
|
+
async requestDkimRotation(id) {
|
|
305
|
+
const mutation = await this.runMutationExclusive(async () => {
|
|
306
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
307
|
+
if (!doc)
|
|
308
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
309
|
+
if (!this.selectorCorrectSigningCapability) {
|
|
310
|
+
return {
|
|
311
|
+
kind: 'result',
|
|
312
|
+
result: this.unsupportedResult(doc, 'SMARTMTA_DKIM_ROTATION_UNSUPPORTED', 'DKIM rotation remains pending until the selector-correct SmartMTA release is consumed'),
|
|
313
|
+
};
|
|
356
314
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
315
|
+
if (doc.pendingDkim) {
|
|
316
|
+
return {
|
|
317
|
+
kind: 'result',
|
|
318
|
+
result: {
|
|
319
|
+
...this.resultForDoc(doc, true),
|
|
320
|
+
message: `Selector ${doc.pendingDkim.selector} is already staged`,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
await this.stageDkimRotation(doc);
|
|
325
|
+
return { kind: 'sync', domainName: doc.domain };
|
|
326
|
+
});
|
|
327
|
+
if (mutation.kind === 'result')
|
|
328
|
+
return mutation.result;
|
|
329
|
+
await this.dcRouter.mailDnsSync?.sync(`DKIM rotation staged: ${mutation.domainName}`);
|
|
330
|
+
const current = await EmailDomainDoc.findById(id);
|
|
331
|
+
if (!current)
|
|
332
|
+
throw new Error(`Email domain disappeared during reconciliation: ${id}`);
|
|
333
|
+
return this.resultForDoc(current, !this.hasDnsMutationFailure(current));
|
|
363
334
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
335
|
+
/** Called by the reconciler before planning so scheduled external rotation is durable first. */
|
|
336
|
+
async stageDkimRotationIfDue(id) {
|
|
337
|
+
return await this.runMutationExclusive(async () => {
|
|
338
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
339
|
+
if (!doc || !doc.dkim.rotateKeys || doc.pendingDkim || !this.selectorCorrectSigningCapability) {
|
|
340
|
+
return doc || undefined;
|
|
369
341
|
}
|
|
370
|
-
|
|
371
|
-
|
|
342
|
+
const active = this.getActiveDkim(doc);
|
|
343
|
+
const reference = Date.parse(active?.promotedAt || doc.dkim.lastRotatedAt || active?.createdAt || doc.createdAt);
|
|
344
|
+
const intervalMs = Math.max(1, doc.dkim.rotationIntervalDays || 90) * 86_400_000;
|
|
345
|
+
if (Number.isFinite(reference) && Date.now() - reference < intervalMs)
|
|
346
|
+
return doc;
|
|
347
|
+
try {
|
|
348
|
+
await this.stageDkimRotation(doc);
|
|
372
349
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
350
|
+
catch (error) {
|
|
351
|
+
doc.reconciliation = this.invalidateReconciliation(doc, 'DKIM_ROTATION_STAGE_FAILED');
|
|
352
|
+
doc.reconciliation.errors = [{
|
|
353
|
+
code: 'DKIM_ROTATION_STAGE_FAILED',
|
|
354
|
+
message: `Failed to stage DKIM rotation: ${error.message}`,
|
|
355
|
+
retryable: true,
|
|
356
|
+
}];
|
|
357
|
+
doc.updatedAt = new Date().toISOString();
|
|
358
|
+
await doc.save();
|
|
359
|
+
}
|
|
360
|
+
return doc;
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
async stageDkimRotation(doc) {
|
|
364
|
+
if (!this.dkimCreator)
|
|
365
|
+
throw new Error('DKIM key creator is not ready');
|
|
366
|
+
const selector = `s${new Date().toISOString().slice(0, 10).replace(/-/g, '')}-${plugins.smartunique.shortId()}`;
|
|
367
|
+
const keySize = doc.dkim.keySize || 2048;
|
|
368
|
+
await this.dkimCreator.handleDKIMKeysForSelector(doc.domain, selector, keySize);
|
|
369
|
+
const record = await this.dkimCreator.getDNSRecordForDomain(doc.domain, selector);
|
|
370
|
+
const publicKey = this.extractDkimPublicKey(record?.value);
|
|
371
|
+
if (!publicKey)
|
|
372
|
+
throw new Error(`DKIM rotation generated no public key for ${selector}`);
|
|
373
|
+
doc.pendingDkim = { selector, keySize, publicKey, createdAt: new Date().toISOString() };
|
|
374
|
+
doc.reconciliation = this.invalidateReconciliation(doc, 'DKIM_ROTATION_STAGED');
|
|
375
|
+
doc.updatedAt = new Date().toISOString();
|
|
376
|
+
await doc.save();
|
|
377
|
+
}
|
|
378
|
+
normalizeRemoteIngressPin(pin, domainName) {
|
|
379
|
+
const edgeFilter = [...new Set((pin?.edgeFilter || []).map((entry) => `${entry}`.trim()).filter(Boolean))];
|
|
380
|
+
if (edgeFilter.length === 0)
|
|
381
|
+
return undefined;
|
|
382
|
+
const manager = this.dcRouter.remoteIngressManager;
|
|
383
|
+
if (manager && manager.resolveEdgesByFilter(edgeFilter).length === 0) {
|
|
384
|
+
logger.log('warn', `Email domain ${domainName}: pin [${edgeFilter.join(', ')}] matches no enabled edge yet`);
|
|
378
385
|
}
|
|
386
|
+
return { edgeFilter };
|
|
387
|
+
}
|
|
388
|
+
extractDkimPublicKey(value) {
|
|
389
|
+
if (typeof value !== 'string')
|
|
390
|
+
return undefined;
|
|
391
|
+
return value.match(/(?:^|;)\s*p=([A-Za-z0-9+/=]+)(?:;|$)/)?.[1];
|
|
392
|
+
}
|
|
393
|
+
getActiveDkim(doc) {
|
|
394
|
+
if (doc.activeDkim?.publicKey)
|
|
395
|
+
return doc.activeDkim;
|
|
396
|
+
if (!doc.dkim?.publicKey)
|
|
397
|
+
return undefined;
|
|
398
|
+
return {
|
|
399
|
+
selector: doc.dkim.selector || 'default',
|
|
400
|
+
keySize: doc.dkim.keySize || 2048,
|
|
401
|
+
publicKey: doc.dkim.publicKey,
|
|
402
|
+
createdAt: doc.createdAt,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
invalidateReconciliation(doc, code) {
|
|
406
|
+
return {
|
|
407
|
+
...(doc.reconciliation || { desiredGeneration: 0, intents: [], errors: [] }),
|
|
408
|
+
lifecycleStatus: doc.reconciliation?.activeRevision ? 'active' : 'pending',
|
|
409
|
+
desiredGeneration: (doc.reconciliation?.desiredGeneration || 0) + 1,
|
|
410
|
+
errors: [{ code, message: 'DNS reconciliation is pending', retryable: true }],
|
|
411
|
+
retryAt: new Date().toISOString(),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
capabilityError(code, message) {
|
|
415
|
+
const error = new Error(message);
|
|
416
|
+
error.code = code;
|
|
417
|
+
error.capability = 'unsupported';
|
|
418
|
+
error.errors = [{ code, message, retryable: false }];
|
|
419
|
+
return error;
|
|
420
|
+
}
|
|
421
|
+
unsupportedResult(doc, code, message) {
|
|
422
|
+
return {
|
|
423
|
+
success: false,
|
|
424
|
+
lifecycleStatus: doc.reconciliation?.lifecycleStatus || 'pending',
|
|
425
|
+
code,
|
|
426
|
+
capability: 'unsupported',
|
|
427
|
+
message,
|
|
428
|
+
errors: [{ code, message, retryable: false }],
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
hasDnsMutationFailure(doc) {
|
|
432
|
+
return (doc.reconciliation?.intents || []).some((intent) => (intent.status === 'failed' || intent.status === 'conflict')) || (doc.reconciliation?.errors || []).some((error) => (['DNS_PROVIDER_ZONE_FAILED', 'DNS_UNMANAGED_CONFLICT', 'DNS_CLEANUP_FAILED'].includes(error.code)));
|
|
433
|
+
}
|
|
434
|
+
resultForDoc(doc, actionSucceeded) {
|
|
435
|
+
const state = doc.reconciliation;
|
|
436
|
+
const firstError = state?.errors[0];
|
|
437
|
+
return {
|
|
438
|
+
success: actionSucceeded,
|
|
439
|
+
lifecycleStatus: state?.lifecycleStatus || 'pending',
|
|
440
|
+
message: firstError?.message,
|
|
441
|
+
code: firstError?.code,
|
|
442
|
+
errors: state?.errors,
|
|
443
|
+
retryAt: state?.retryAt,
|
|
444
|
+
capability: state?.capability?.egressIdentityProof,
|
|
445
|
+
domain: this.docToInterface(doc),
|
|
446
|
+
};
|
|
379
447
|
}
|
|
380
|
-
// ---------------------------------------------------------------------------
|
|
381
|
-
// Helpers
|
|
382
|
-
// ---------------------------------------------------------------------------
|
|
383
448
|
docToInterface(doc) {
|
|
384
449
|
return {
|
|
385
450
|
id: doc.id,
|
|
@@ -390,52 +455,56 @@ export class EmailDomainManager {
|
|
|
390
455
|
rateLimits: doc.rateLimits,
|
|
391
456
|
remoteIngress: doc.remoteIngress,
|
|
392
457
|
dnsStatus: doc.dnsStatus,
|
|
458
|
+
reconciliation: doc.reconciliation,
|
|
459
|
+
activeDkim: doc.activeDkim,
|
|
460
|
+
pendingDkim: doc.pendingDkim,
|
|
461
|
+
retiringDkim: doc.retiringDkim,
|
|
393
462
|
createdAt: doc.createdAt,
|
|
394
463
|
updatedAt: doc.updatedAt,
|
|
395
464
|
};
|
|
396
465
|
}
|
|
397
466
|
isDomainAlreadyConfigured(domainName) {
|
|
398
|
-
|
|
399
|
-
.
|
|
400
|
-
return configuredDomains.includes(domainName.toLowerCase());
|
|
467
|
+
return (this.dcRouter.options?.emailConfig?.domains || [])
|
|
468
|
+
.some((domainConfig) => domainConfig.domain.toLowerCase() === domainName.toLowerCase());
|
|
401
469
|
}
|
|
402
470
|
async findLinkedDnsDomain(domainName) {
|
|
403
471
|
const domains = await DomainDoc.findAll();
|
|
404
472
|
return domains
|
|
405
473
|
.filter((domainDoc) => domainName === domainDoc.name || domainName.endsWith(`.${domainDoc.name}`))
|
|
406
|
-
.sort((
|
|
474
|
+
.sort((left, right) => right.name.length - left.name.length)[0] || null;
|
|
407
475
|
}
|
|
408
476
|
async buildManagedDomainConfigs() {
|
|
409
477
|
const docs = await EmailDomainDoc.findAll();
|
|
410
478
|
const managedConfigs = [];
|
|
411
479
|
for (const doc of docs) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
480
|
+
if (doc.reconciliation?.lifecycleStatus === 'deleting')
|
|
481
|
+
continue;
|
|
482
|
+
if (!await DomainDoc.findById(doc.linkedDomainId)) {
|
|
483
|
+
logger.log('warn', `Managed email domain ${doc.domain} has no linked DNS domain; keeping it out of runtime`);
|
|
415
484
|
continue;
|
|
416
485
|
}
|
|
486
|
+
const activeDkim = this.getActiveDkim(doc);
|
|
487
|
+
const dkimConfig = activeDkim && (activeDkim.selector === 'default' || this.selectorCorrectSigningCapability)
|
|
488
|
+
? {
|
|
489
|
+
selector: activeDkim.selector,
|
|
490
|
+
keySize: activeDkim.keySize,
|
|
491
|
+
// Dcrouter exclusively owns staged external rotation.
|
|
492
|
+
rotateKeys: false,
|
|
493
|
+
rotationInterval: doc.dkim.rotationIntervalDays,
|
|
494
|
+
}
|
|
495
|
+
: undefined;
|
|
417
496
|
managedConfigs.push({
|
|
418
497
|
domain: doc.domain,
|
|
419
|
-
// Always external-dns: DcRouter owns the DNS records for managed domains
|
|
420
|
-
// (email-domain-manager DnsRecordDocs). internal-dns would make smartmta
|
|
421
|
-
// self-register a conflicting MX (exchange = the domain itself) plus
|
|
422
|
-
// duplicate SPF/DKIM TXT handlers on the shared DNS server.
|
|
423
498
|
dnsMode: 'external-dns',
|
|
424
|
-
dkim: {
|
|
425
|
-
selector: doc.dkim.selector,
|
|
426
|
-
keySize: doc.dkim.keySize,
|
|
427
|
-
rotateKeys: doc.dkim.rotateKeys,
|
|
428
|
-
rotationInterval: doc.dkim.rotationIntervalDays,
|
|
429
|
-
},
|
|
499
|
+
...(dkimConfig ? { dkim: dkimConfig } : {}),
|
|
430
500
|
rateLimits: doc.rateLimits,
|
|
431
501
|
});
|
|
432
502
|
}
|
|
433
503
|
return managedConfigs;
|
|
434
504
|
}
|
|
435
505
|
async syncManagedDomainsToRuntime() {
|
|
436
|
-
if (!this.dcRouter.options?.emailConfig)
|
|
506
|
+
if (!this.dcRouter.options?.emailConfig)
|
|
437
507
|
return;
|
|
438
|
-
}
|
|
439
508
|
const mergedDomains = new Map();
|
|
440
509
|
for (const domainConfig of this.baseEmailDomains) {
|
|
441
510
|
mergedDomains.set(domainConfig.domain.toLowerCase(), JSON.parse(JSON.stringify(domainConfig)));
|
|
@@ -448,11 +517,9 @@ export class EmailDomainManager {
|
|
|
448
517
|
}
|
|
449
518
|
mergedDomains.set(key, managedConfig);
|
|
450
519
|
}
|
|
451
|
-
const domains =
|
|
520
|
+
const domains = [...mergedDomains.values()];
|
|
452
521
|
this.dcRouter.options.emailConfig.domains = domains;
|
|
453
|
-
|
|
454
|
-
this.dcRouter.emailServer.updateOptions({ domains });
|
|
455
|
-
}
|
|
522
|
+
this.dcRouter.emailServer?.updateOptions({ domains });
|
|
456
523
|
}
|
|
457
524
|
}
|
|
458
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lbWFpbC1kb21haW4ubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuZW1haWwtZG9tYWluLm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFFekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDN0UsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUl6RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU5RDs7Ozs7O0dBTUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBQ3JCLFFBQVEsQ0FBTSxDQUFDLG9DQUFvQztJQUNuRCxnQkFBZ0IsR0FBeUIsRUFBRSxDQUFDO0lBQzVDLFNBQVMsQ0FBMEM7SUFFM0QsWUFBWSxXQUFnQjtRQUMxQixJQUFJLENBQUMsUUFBUSxHQUFHLFdBQVcsQ0FBQztRQUM1QixJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE9BQTJDLENBQUMsQ0FBQztJQUM1RyxDQUFDO0lBRU0sbUJBQW1CLENBQUMsT0FBeUM7UUFDbEUsSUFBSSxDQUFDLGdCQUFnQixHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQzthQUNwQyxHQUFHLENBQUMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBdUIsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFFRCxJQUFZLFVBQVU7UUFDcEIsT0FBTyxJQUFJLENBQUMsUUFB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
|
|
525
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lbWFpbC1kb21haW4ubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuZW1haWwtZG9tYWluLm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFFekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDN0UsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQXVCekU7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGtCQUFrQjtJQUNyQixRQUFRLENBQU0sQ0FBQyxvQ0FBb0M7SUFDbkQsZ0JBQWdCLEdBQXlCLEVBQUUsQ0FBQztJQUM1QyxhQUFhLEdBQXFCLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1RCxnRkFBZ0Y7SUFDaEYsSUFBWSxnQ0FBZ0M7UUFDMUMsT0FBUSxPQUFPLENBQUMsUUFBZ0IsQ0FBQyxvQkFBb0IsRUFBRSwwQkFBMEIsS0FBSyxJQUFJLENBQUM7SUFDN0YsQ0FBQztJQUVELFlBQVksV0FBZ0I7UUFDMUIsSUFBSSxDQUFDLFFBQVEsR0FBRyxXQUFXLENBQUM7UUFDNUIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxPQUEyQyxDQUFDLENBQUM7SUFDNUcsQ0FBQztJQUVNLG1CQUFtQixDQUFDLE9BQXlDO1FBQ2xFLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7YUFDcEMsR0FBRyxDQUFDLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxT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
|