@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.
- 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 +5 -1
- package/dist_ts/classes.dcrouter.js +42 -9
- 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/db/documents/classes.smartmta-storage.doc.d.ts +8 -0
- package/dist_ts/db/documents/classes.smartmta-storage.doc.js +91 -0
- package/dist_ts/db/documents/index.d.ts +1 -0
- package/dist_ts/db/documents/index.js +2 -1
- 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.email-settings.manager.js +2 -1
- 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.smartmta-blob-storage-manager.d.ts +27 -0
- package/dist_ts/email/classes.smartmta-blob-storage-manager.js +109 -0
- package/dist_ts/email/classes.smartmta-storage-manager.d.ts +6 -8
- package/dist_ts/email/classes.smartmta-storage-manager.js +63 -86
- package/dist_ts/email/classes.workapp-mail-manager.d.ts +3 -0
- package/dist_ts/email/classes.workapp-mail-manager.js +63 -14
- package/dist_ts/email/index.d.ts +3 -0
- package/dist_ts/email/index.js +4 -1
- package/dist_ts/email/smartmta-storage-policy.d.ts +9 -0
- package/dist_ts/email/smartmta-storage-policy.js +58 -0
- 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/opsserver/handlers/stats.handler.js +3 -5
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- 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.d.ts +2 -0
- package/dist_ts_migrations/index.js +441 -16
- 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 +4 -3
- package/readme.md +13 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +55 -11
- package/ts/db/documents/classes.dns-record.doc.ts +20 -0
- package/ts/db/documents/classes.email-domain.doc.ts +14 -0
- package/ts/db/documents/classes.smartmta-storage.doc.ts +25 -0
- package/ts/db/documents/index.ts +1 -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.email-settings.manager.ts +1 -0
- 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.smartmta-blob-storage-manager.ts +138 -0
- package/ts/email/classes.smartmta-storage-manager.ts +86 -83
- package/ts/email/classes.workapp-mail-manager.ts +82 -16
- package/ts/email/index.ts +3 -0
- package/ts/email/smartmta-storage-policy.ts +73 -0
- package/ts/opsserver/handlers/email-domain.handler.ts +154 -21
- package/ts/opsserver/handlers/stats.handler.ts +2 -4
- package/ts/plugins.ts +2 -1
- 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
|
@@ -1,196 +1,912 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
1
2
|
import { logger } from '../logger.js';
|
|
2
3
|
import { DnsRecordDoc } from '../db/documents/classes.dns-record.doc.js';
|
|
3
4
|
import { DomainDoc } from '../db/documents/classes.domain.doc.js';
|
|
4
5
|
import { EmailDomainDoc } from '../db/documents/classes.email-domain.doc.js';
|
|
5
|
-
|
|
6
|
+
import { MailEdgeEligibility, ReleasedRemoteIngressEgressIdentitySource, } from './classes.mail-edge-eligibility.js';
|
|
7
|
+
export const MAIL_DNS_SYNC_CREATED_BY = 'mail-dns-reconciler';
|
|
8
|
+
export const MAIL_DNS_MANAGED_BY = 'mail-dns-reconciler';
|
|
9
|
+
export const MAIL_DNS_RETRY_INTERVAL_MS = 5 * 60_000;
|
|
10
|
+
function normalizeHostname(value) {
|
|
11
|
+
return value.trim().toLowerCase().replace(/\.$/, '');
|
|
12
|
+
}
|
|
13
|
+
function normalizeMx(value) {
|
|
14
|
+
const [priority, exchange = ''] = value.trim().split(/\s+/);
|
|
15
|
+
return `${Number(priority)} ${normalizeHostname(exchange)}`;
|
|
16
|
+
}
|
|
17
|
+
function expandIpv6(address) {
|
|
18
|
+
let normalized = address.toLowerCase();
|
|
19
|
+
if (normalized.includes('.')) {
|
|
20
|
+
const lastColon = normalized.lastIndexOf(':');
|
|
21
|
+
const ipv4 = normalized.slice(lastColon + 1).split('.').map(Number);
|
|
22
|
+
if (ipv4.length !== 4 || ipv4.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
normalized = `${normalized.slice(0, lastColon)}:${((ipv4[0] << 8) | ipv4[1]).toString(16)}:${((ipv4[2] << 8) | ipv4[3]).toString(16)}`;
|
|
26
|
+
}
|
|
27
|
+
const halves = normalized.split('::');
|
|
28
|
+
if (halves.length > 2)
|
|
29
|
+
return undefined;
|
|
30
|
+
const left = halves[0] ? halves[0].split(':') : [];
|
|
31
|
+
const right = halves[1] ? halves[1].split(':') : [];
|
|
32
|
+
const missing = 8 - left.length - right.length;
|
|
33
|
+
if ((halves.length === 1 && missing !== 0) || missing < 0)
|
|
34
|
+
return undefined;
|
|
35
|
+
const groups = [...left, ...Array.from({ length: missing }, () => '0'), ...right];
|
|
36
|
+
if (groups.length !== 8 || groups.some((group) => !/^[0-9a-f]{1,4}$/.test(group)))
|
|
37
|
+
return undefined;
|
|
38
|
+
return groups.map((group) => group.padStart(4, '0'));
|
|
39
|
+
}
|
|
40
|
+
export function toReverseDnsName(address) {
|
|
41
|
+
const family = plugins.smartnetwork.getIpVersion(address);
|
|
42
|
+
if (family === 4) {
|
|
43
|
+
return `${address.split('.').reverse().join('.')}.in-addr.arpa`;
|
|
44
|
+
}
|
|
45
|
+
if (family === 6) {
|
|
46
|
+
const groups = expandIpv6(address);
|
|
47
|
+
if (!groups)
|
|
48
|
+
throw new Error(`Invalid IPv6 address: ${address}`);
|
|
49
|
+
return `${groups.join('').split('').reverse().join('.')}.ip6.arpa`;
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Invalid IP address: ${address}`);
|
|
52
|
+
}
|
|
53
|
+
export class SmartDnsMailVerifier {
|
|
54
|
+
client;
|
|
55
|
+
getClient() {
|
|
56
|
+
this.client ||= new plugins.smartdns.dnsClientMod.Smartdns({});
|
|
57
|
+
return this.client;
|
|
58
|
+
}
|
|
59
|
+
async verifyRecord(intent) {
|
|
60
|
+
try {
|
|
61
|
+
const records = await this.getClient().getRecords(intent.name, intent.type);
|
|
62
|
+
const values = (records || []).map((record) => String(record.value).trim());
|
|
63
|
+
if (intent.type === 'MX') {
|
|
64
|
+
return values.some((value) => normalizeMx(value) === normalizeMx(intent.value))
|
|
65
|
+
? { valid: true }
|
|
66
|
+
: { valid: false, reason: `MX ${intent.value} has not propagated` };
|
|
67
|
+
}
|
|
68
|
+
if (intent.type === 'TXT') {
|
|
69
|
+
const exact = values.filter((value) => value === intent.value.trim());
|
|
70
|
+
const relevant = intent.value.startsWith('v=spf1')
|
|
71
|
+
? values.filter((value) => value.toLowerCase().startsWith('v=spf1'))
|
|
72
|
+
: intent.value.startsWith('v=DMARC1')
|
|
73
|
+
? values.filter((value) => value.toLowerCase().startsWith('v=dmarc1'))
|
|
74
|
+
: values;
|
|
75
|
+
return exact.length === 1 && relevant.length === 1
|
|
76
|
+
? { valid: true }
|
|
77
|
+
: { valid: false, reason: `TXT ${intent.name} is missing, conflicting, or duplicated` };
|
|
78
|
+
}
|
|
79
|
+
const exact = values.filter((value) => normalizeHostname(value) === normalizeHostname(intent.value));
|
|
80
|
+
return exact.length === 1 && values.length === 1
|
|
81
|
+
? { valid: true }
|
|
82
|
+
: { valid: false, reason: `${intent.type} ${intent.name} is missing, conflicting, or duplicated` };
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return { valid: false, reason: `DNS lookup failed: ${error.message}` };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async verifyMxSet(intents) {
|
|
89
|
+
if (intents.length === 0)
|
|
90
|
+
return { valid: false, reason: 'No desired MX records' };
|
|
91
|
+
try {
|
|
92
|
+
const records = await this.getClient().getRecords(intents[0].name, 'MX');
|
|
93
|
+
const actual = (records || []).map((record) => normalizeMx(String(record.value))).sort();
|
|
94
|
+
const desired = intents.map((intent) => normalizeMx(intent.value)).sort();
|
|
95
|
+
return actual.length === desired.length && actual.every((value, index) => value === desired[index])
|
|
96
|
+
? { valid: true }
|
|
97
|
+
: {
|
|
98
|
+
valid: false,
|
|
99
|
+
reason: `MX set for ${intents[0].name} does not exactly match priorities and exchanges`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
return { valid: false, reason: `MX lookup failed: ${error.message}` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async verifyForwardConfirmedIdentity(identity) {
|
|
107
|
+
const checks = [];
|
|
108
|
+
if (identity.ipv4)
|
|
109
|
+
checks.push({ family: 'A', address: identity.ipv4 });
|
|
110
|
+
if (identity.ipv6)
|
|
111
|
+
checks.push({ family: 'AAAA', address: identity.ipv6 });
|
|
112
|
+
try {
|
|
113
|
+
for (const check of checks) {
|
|
114
|
+
const ptrRecords = await this.getClient().getRecords(toReverseDnsName(check.address), 'PTR');
|
|
115
|
+
const ptrNames = (ptrRecords || []).map((record) => normalizeHostname(String(record.value)));
|
|
116
|
+
if (ptrNames.length !== 1 || ptrNames[0] !== normalizeHostname(identity.hostname)) {
|
|
117
|
+
return {
|
|
118
|
+
valid: false,
|
|
119
|
+
reason: `PTR for ${check.address} must be exactly ${identity.hostname}`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const forwardRecords = await this.getClient().getRecords(identity.hostname, check.family);
|
|
123
|
+
const forwardIps = (forwardRecords || []).map((record) => String(record.value));
|
|
124
|
+
if (!forwardIps.includes(check.address)) {
|
|
125
|
+
return {
|
|
126
|
+
valid: false,
|
|
127
|
+
reason: `${check.family} ${identity.hostname} does not resolve back to ${check.address}`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return checks.length > 0
|
|
132
|
+
? { valid: true }
|
|
133
|
+
: { valid: false, reason: `No source-bound address is available for ${identity.edgeId}` };
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
return { valid: false, reason: `FCrDNS lookup failed: ${error.message}` };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
destroy() {
|
|
140
|
+
this.client?.destroy();
|
|
141
|
+
this.client = undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
6
144
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (a) shared mail hostname → publicIp/publicIpV6 of every enabled mail edge,
|
|
10
|
-
* (b) each edge's mailHostname → that edge's IPs (FCrDNS for outbound EHLO),
|
|
11
|
-
* (c) mx.<domain> → the pinned edges' IPs for every pinned email domain.
|
|
12
|
-
* Records are DB-backed DnsRecordDoc rows owned via createdBy 'mail-edge-sync';
|
|
13
|
-
* provider-hosted zones (e.g. Cloudflare) are written through DnsManager's
|
|
14
|
-
* provider path, dcrouter-authoritative zones serve immediately.
|
|
145
|
+
* Sole owner of managed mail DNS. API, topology, timer, and startup events only
|
|
146
|
+
* mark this globally serialized reconciler dirty.
|
|
15
147
|
*/
|
|
16
148
|
export class MailDnsSync {
|
|
17
149
|
dcRouterRef;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
150
|
+
verifier;
|
|
151
|
+
started = false;
|
|
152
|
+
stopped = false;
|
|
153
|
+
dirty = false;
|
|
154
|
+
runPromise;
|
|
155
|
+
retryTimer;
|
|
156
|
+
edgeEligibility;
|
|
157
|
+
constructor(dcRouterRef, edgeEligibility, verifier = new SmartDnsMailVerifier()) {
|
|
21
158
|
this.dcRouterRef = dcRouterRef;
|
|
159
|
+
this.verifier = verifier;
|
|
160
|
+
this.edgeEligibility = edgeEligibility
|
|
161
|
+
|| dcRouterRef.mailEdgeEligibility
|
|
162
|
+
|| new MailEdgeEligibility(dcRouterRef, new ReleasedRemoteIngressEgressIdentitySource(dcRouterRef));
|
|
163
|
+
}
|
|
164
|
+
async start() {
|
|
165
|
+
if (this.started) {
|
|
166
|
+
await this.runPromise;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.started = true;
|
|
170
|
+
this.stopped = false;
|
|
171
|
+
this.retryTimer = setInterval(() => this.requestSync('periodic retry'), MAIL_DNS_RETRY_INTERVAL_MS);
|
|
172
|
+
this.dirty = true;
|
|
173
|
+
try {
|
|
174
|
+
await this.kick('startup');
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (this.retryTimer)
|
|
178
|
+
clearInterval(this.retryTimer);
|
|
179
|
+
this.retryTimer = undefined;
|
|
180
|
+
this.started = false;
|
|
181
|
+
this.dirty = false;
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async stop() {
|
|
186
|
+
this.stopped = true;
|
|
187
|
+
this.started = false;
|
|
188
|
+
this.dirty = false;
|
|
189
|
+
if (this.retryTimer) {
|
|
190
|
+
clearInterval(this.retryTimer);
|
|
191
|
+
this.retryTimer = undefined;
|
|
192
|
+
}
|
|
193
|
+
await this.runPromise?.catch(() => undefined);
|
|
194
|
+
this.verifier.destroy?.();
|
|
22
195
|
}
|
|
23
|
-
/** Fire-and-forget trigger for CRUD hooks; failures are logged, not thrown. */
|
|
24
196
|
requestSync(reason) {
|
|
25
|
-
this.
|
|
26
|
-
|
|
197
|
+
if (this.stopped)
|
|
198
|
+
return;
|
|
199
|
+
this.dirty = true;
|
|
200
|
+
if (!this.started)
|
|
201
|
+
return;
|
|
202
|
+
this.kick(reason).catch((error) => {
|
|
203
|
+
logger.log('error', `MailDnsSync failed (${reason}): ${error.message}`);
|
|
27
204
|
});
|
|
28
205
|
}
|
|
29
|
-
/** Coalescing entry point
|
|
206
|
+
/** Coalescing entry point used by API actions that need the durable outcome. */
|
|
30
207
|
async sync(reason) {
|
|
31
|
-
if (this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
208
|
+
if (this.stopped)
|
|
209
|
+
throw new Error('MailDnsSync is stopped');
|
|
210
|
+
this.dirty = true;
|
|
211
|
+
await this.kick(reason);
|
|
212
|
+
}
|
|
213
|
+
async kick(reason) {
|
|
214
|
+
if (this.runPromise)
|
|
215
|
+
return await this.runPromise;
|
|
216
|
+
// Defer execution one microtask so runPromise is assigned before the first
|
|
217
|
+
// awaited provider/eligibility hook can synchronously enqueue another event.
|
|
218
|
+
this.runPromise = Promise.resolve().then(() => this.runLoop(reason, false)).finally(() => {
|
|
219
|
+
this.runPromise = undefined;
|
|
220
|
+
if (this.dirty && this.started && !this.stopped) {
|
|
221
|
+
this.requestSync(`${reason} (follow-up)`);
|
|
40
222
|
}
|
|
41
223
|
});
|
|
42
|
-
return this.
|
|
224
|
+
return await this.runPromise;
|
|
225
|
+
}
|
|
226
|
+
async runLoop(reason, singlePass) {
|
|
227
|
+
do {
|
|
228
|
+
this.dirty = false;
|
|
229
|
+
await this.reconcile(reason);
|
|
230
|
+
if (singlePass)
|
|
231
|
+
break;
|
|
232
|
+
// An event during the run leaves dirty=true and forces exactly one
|
|
233
|
+
// immediate follow-up; repeated events coalesce into that pass.
|
|
234
|
+
} while (this.dirty && !this.stopped);
|
|
43
235
|
}
|
|
44
236
|
async reconcile(reason) {
|
|
45
|
-
if (this.dcRouterRef.options.dbConfig?.enabled === false)
|
|
237
|
+
if (this.dcRouterRef.options.dbConfig?.enabled === false)
|
|
46
238
|
return;
|
|
47
|
-
}
|
|
48
239
|
const dnsManager = this.dcRouterRef.dnsManager;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Without both managers the edge registry / record store is not
|
|
52
|
-
// authoritative — skip entirely rather than delete managed records.
|
|
240
|
+
if (!dnsManager) {
|
|
241
|
+
logger.log('warn', `MailDnsSync (${reason}): DnsManager unavailable; retry intent retained`);
|
|
53
242
|
return;
|
|
54
243
|
}
|
|
55
|
-
|
|
244
|
+
// Refresh the broad operational status independently from per-domain pins.
|
|
245
|
+
await this.edgeEligibility.resolveForDomain();
|
|
56
246
|
const zones = await DomainDoc.findAll();
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
unplacedNames.add(record.name);
|
|
247
|
+
const docs = await EmailDomainDoc.findAll();
|
|
248
|
+
const plans = [];
|
|
249
|
+
for (const loadedDoc of docs) {
|
|
250
|
+
const doc = await this.dcRouterRef.emailDomainManager?.stageDkimRotationIfDue?.(loadedDoc.id)
|
|
251
|
+
|| loadedDoc;
|
|
252
|
+
if (doc.reconciliation?.lifecycleStatus === 'deleting') {
|
|
253
|
+
await this.persistDeletingAttempt(doc);
|
|
65
254
|
continue;
|
|
66
255
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
256
|
+
const plan = await this.buildPlan(doc, zones);
|
|
257
|
+
await this.persistDesiredPlan(plan);
|
|
258
|
+
plans.push(plan);
|
|
71
259
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
.filter((record) => record.createdBy === MAIL_DNS_SYNC_CREATED_BY);
|
|
77
|
-
let created = 0;
|
|
78
|
-
let deleted = 0;
|
|
79
|
-
for (const record of existing) {
|
|
80
|
-
const key = `${record.domainId}|${record.name}|${record.type}|${record.value}`;
|
|
81
|
-
if (placed.has(key)) {
|
|
82
|
-
placed.delete(key); // already present — nothing to create
|
|
83
|
-
continue;
|
|
260
|
+
const uniqueIntents = new Map();
|
|
261
|
+
for (const plan of plans) {
|
|
262
|
+
for (const intent of plan.intents) {
|
|
263
|
+
uniqueIntents.set(intent.key, intent);
|
|
84
264
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
265
|
+
}
|
|
266
|
+
const zoneErrors = await this.reconcileZones([...uniqueIntents.values()], zones);
|
|
267
|
+
for (const plan of plans) {
|
|
268
|
+
const errors = [...plan.preliminaryErrors];
|
|
269
|
+
for (const intent of plan.intents) {
|
|
270
|
+
const outcome = uniqueIntents.get(intent.key);
|
|
271
|
+
if (outcome)
|
|
272
|
+
Object.assign(intent, outcome);
|
|
273
|
+
if (intent.error)
|
|
274
|
+
errors.push(intent.error);
|
|
91
275
|
}
|
|
276
|
+
await this.validateAndActivate(plan, errors, zoneErrors);
|
|
92
277
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
278
|
+
await this.cleanupStaleManagedRecords(zones);
|
|
279
|
+
await this.finalizeDeletingDomains();
|
|
280
|
+
await this.dcRouterRef.emailDomainManager?.syncManagedDomainsToRuntime();
|
|
281
|
+
await this.dcRouterRef.workAppMailManager?.applyStoredIdentitiesToRuntime();
|
|
282
|
+
}
|
|
283
|
+
async buildPlan(doc, zones) {
|
|
284
|
+
const now = new Date().toISOString();
|
|
285
|
+
const eligibility = await this.edgeEligibility.resolveForDomain(doc);
|
|
286
|
+
const preliminaryErrors = [
|
|
287
|
+
...(doc.reconciliation?.errors || []).filter((error) => error.code === 'DKIM_ROTATION_STAGE_FAILED'),
|
|
288
|
+
];
|
|
289
|
+
if (!eligibility.supported) {
|
|
290
|
+
preliminaryErrors.push({
|
|
291
|
+
code: 'EGRESS_IDENTITY_PROOF_UNAVAILABLE',
|
|
292
|
+
message: eligibility.reason || 'RemoteIngress egress identity proof is unavailable',
|
|
293
|
+
retryable: true,
|
|
102
294
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
295
|
+
}
|
|
296
|
+
else if (eligibility.edges.length === 0) {
|
|
297
|
+
preliminaryErrors.push({
|
|
298
|
+
code: 'NO_ELIGIBLE_MAIL_EDGE',
|
|
299
|
+
message: eligibility.reason || 'No eligible mail edge is connected',
|
|
300
|
+
retryable: true,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
const activeDkim = this.getActiveDkim(doc);
|
|
304
|
+
const upstreamSelectorCapability = this.dcRouterRef.emailDomainManager?.supportsSelectorCorrectSigning?.() === true;
|
|
305
|
+
const selectorCorrectSigningSupported = ((!activeDkim || activeDkim.selector === 'default') && !doc.pendingDkim) || upstreamSelectorCapability;
|
|
306
|
+
if (!activeDkim) {
|
|
307
|
+
preliminaryErrors.push({
|
|
308
|
+
code: 'DKIM_KEY_UNAVAILABLE',
|
|
309
|
+
message: `No usable active DKIM key exists for ${doc.domain}`,
|
|
310
|
+
retryable: false,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
else if (!selectorCorrectSigningSupported) {
|
|
314
|
+
preliminaryErrors.push({
|
|
315
|
+
code: 'SMARTMTA_SELECTOR_SIGNING_UNSUPPORTED',
|
|
316
|
+
message: 'The consumed SmartMTA release cannot safely sign with a non-default selector',
|
|
317
|
+
retryable: false,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const edgeIdentities = eligibility.edges.map((candidate) => this.toDomainEdgeIdentity(candidate));
|
|
321
|
+
const mxSlots = this.allocateMxSlots(doc, eligibility.edges);
|
|
322
|
+
if (eligibility.edges.length >= 2 && mxSlots.length < 2) {
|
|
323
|
+
preliminaryErrors.push({
|
|
324
|
+
code: 'INSUFFICIENT_DISTINCT_MX_IDENTITIES',
|
|
325
|
+
message: 'At least two eligible mail edges exist but they do not provide two distinct MX hostnames',
|
|
326
|
+
retryable: false,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
const revisionId = plugins.smartunique.shortId();
|
|
330
|
+
const intents = [];
|
|
331
|
+
for (const candidate of eligibility.edges) {
|
|
332
|
+
for (const identity of candidate.identities) {
|
|
333
|
+
const type = identity.family === 4 ? 'A' : 'AAAA';
|
|
334
|
+
intents.push(this.intentForName(zones, {
|
|
335
|
+
key: `mail-topology:${candidate.edge.id}:${type}:${candidate.hostname}:${identity.address}`,
|
|
336
|
+
ownerType: 'topology',
|
|
337
|
+
ownerId: `topology:${candidate.edge.id}`,
|
|
338
|
+
name: candidate.hostname,
|
|
339
|
+
type,
|
|
340
|
+
value: identity.address,
|
|
341
|
+
ttl: 300,
|
|
342
|
+
}));
|
|
108
343
|
}
|
|
109
344
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
345
|
+
if (eligibility.edges.length > 0) {
|
|
346
|
+
for (const slot of mxSlots) {
|
|
347
|
+
intents.push(this.intentForName(zones, {
|
|
348
|
+
key: `mail-domain:${doc.id}:mx:${slot.priority}:${slot.edgeId}:${slot.hostname}`,
|
|
349
|
+
ownerType: 'domain',
|
|
350
|
+
ownerId: `domain:${doc.id}`,
|
|
351
|
+
name: doc.domain,
|
|
352
|
+
type: 'MX',
|
|
353
|
+
value: `${slot.priority} ${slot.hostname}`,
|
|
354
|
+
ttl: 300,
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
const spfIdentities = [
|
|
358
|
+
...edgeIdentities,
|
|
359
|
+
...(doc.reconciliation?.activeRevision?.edgeIdentities || []),
|
|
360
|
+
];
|
|
361
|
+
intents.push(this.intentForName(zones, {
|
|
362
|
+
key: `mail-domain:${doc.id}:spf`,
|
|
363
|
+
ownerType: 'domain',
|
|
364
|
+
ownerId: `domain:${doc.id}`,
|
|
365
|
+
name: doc.domain,
|
|
366
|
+
type: 'TXT',
|
|
367
|
+
value: this.buildSpfValue(spfIdentities),
|
|
368
|
+
ttl: 300,
|
|
369
|
+
}));
|
|
112
370
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
if (!
|
|
119
|
-
|
|
120
|
-
const normalizedName = name.toLowerCase();
|
|
121
|
-
if (edge.publicIp) {
|
|
122
|
-
desired.push({ name: normalizedName, type: 'A', value: edge.publicIp });
|
|
371
|
+
if (activeDkim)
|
|
372
|
+
intents.push(this.buildDkimIntent(doc, activeDkim, zones));
|
|
373
|
+
if (doc.pendingDkim)
|
|
374
|
+
intents.push(this.buildDkimIntent(doc, doc.pendingDkim, zones));
|
|
375
|
+
for (const retiring of doc.retiringDkim || []) {
|
|
376
|
+
if (!retiring.retireAfter || Date.parse(retiring.retireAfter) > Date.now()) {
|
|
377
|
+
intents.push(this.buildDkimIntent(doc, retiring, zones));
|
|
123
378
|
}
|
|
124
|
-
|
|
125
|
-
|
|
379
|
+
}
|
|
380
|
+
intents.push(this.intentForName(zones, {
|
|
381
|
+
key: `mail-domain:${doc.id}:dmarc`,
|
|
382
|
+
ownerType: 'domain',
|
|
383
|
+
ownerId: `domain:${doc.id}`,
|
|
384
|
+
name: `_dmarc.${doc.domain}`,
|
|
385
|
+
type: 'TXT',
|
|
386
|
+
value: `v=DMARC1; p=none; rua=mailto:dmarc@${doc.domain}`,
|
|
387
|
+
ttl: 3600,
|
|
388
|
+
}));
|
|
389
|
+
for (const intent of intents) {
|
|
390
|
+
if (!intent.domainId) {
|
|
391
|
+
intent.status = 'failed';
|
|
392
|
+
intent.error = {
|
|
393
|
+
code: 'DNS_ZONE_UNMANAGED',
|
|
394
|
+
message: `No managed DNS zone covers ${intent.name}`,
|
|
395
|
+
recordKey: intent.key,
|
|
396
|
+
retryable: false,
|
|
397
|
+
};
|
|
126
398
|
}
|
|
399
|
+
}
|
|
400
|
+
const revision = {
|
|
401
|
+
id: revisionId,
|
|
402
|
+
createdAt: now,
|
|
403
|
+
selector: doc.pendingDkim?.selector || activeDkim?.selector || doc.dkim.selector || 'default',
|
|
404
|
+
edgeIdentities,
|
|
405
|
+
mxSlots,
|
|
406
|
+
recordKeys: intents.map((intent) => intent.key),
|
|
407
|
+
};
|
|
408
|
+
return {
|
|
409
|
+
doc,
|
|
410
|
+
revision,
|
|
411
|
+
intents,
|
|
412
|
+
preliminaryErrors,
|
|
413
|
+
egressIdentitySupported: eligibility.supported,
|
|
414
|
+
selectorCorrectSigningSupported,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
getActiveDkim(doc) {
|
|
418
|
+
if (doc.activeDkim?.publicKey)
|
|
419
|
+
return doc.activeDkim;
|
|
420
|
+
const publicKey = doc.dkim?.publicKey?.trim();
|
|
421
|
+
if (!publicKey)
|
|
422
|
+
return undefined;
|
|
423
|
+
return {
|
|
424
|
+
selector: doc.dkim.selector || 'default',
|
|
425
|
+
keySize: doc.dkim.keySize || 2048,
|
|
426
|
+
publicKey,
|
|
427
|
+
createdAt: doc.createdAt,
|
|
127
428
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
429
|
+
}
|
|
430
|
+
buildDkimIntent(doc, material, zones) {
|
|
431
|
+
return this.intentForName(zones, {
|
|
432
|
+
key: `mail-domain:${doc.id}:dkim:${material.selector}`,
|
|
433
|
+
ownerType: 'domain',
|
|
434
|
+
ownerId: `domain:${doc.id}`,
|
|
435
|
+
name: `${material.selector}._domainkey.${doc.domain}`,
|
|
436
|
+
type: 'TXT',
|
|
437
|
+
value: `v=DKIM1; h=sha256; k=rsa; p=${material.publicKey}`,
|
|
438
|
+
ttl: 3600,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
intentForName(zones, input) {
|
|
442
|
+
return {
|
|
443
|
+
...input,
|
|
444
|
+
domainId: this.findZoneForName(input.name, zones)?.id || '',
|
|
445
|
+
status: 'pending',
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
toDomainEdgeIdentity(candidate) {
|
|
449
|
+
const ipv4 = candidate.identities.find((identity) => identity.family === 4);
|
|
450
|
+
const ipv6 = candidate.identities.find((identity) => identity.family === 6);
|
|
451
|
+
const observedAt = Math.min(...candidate.identities.map((identity) => identity.observedAt));
|
|
452
|
+
const hubReceivedAt = Math.min(...candidate.identities.map((identity) => identity.hubReceivedAt));
|
|
453
|
+
return {
|
|
454
|
+
edgeId: candidate.edge.id,
|
|
455
|
+
hostname: candidate.hostname,
|
|
456
|
+
...(ipv4 ? { ipv4: ipv4.address } : {}),
|
|
457
|
+
...(ipv6 ? { ipv6: ipv6.address } : {}),
|
|
458
|
+
observedAt: new Date(observedAt).toISOString(),
|
|
459
|
+
hubReceivedAt: new Date(hubReceivedAt).toISOString(),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
allocateMxSlots(doc, candidates) {
|
|
463
|
+
if (candidates.length === 1) {
|
|
464
|
+
return [{
|
|
465
|
+
priority: 10,
|
|
466
|
+
edgeId: candidates[0].edge.id,
|
|
467
|
+
hostname: candidates[0].hostname,
|
|
468
|
+
}];
|
|
469
|
+
}
|
|
470
|
+
const byId = new Map(candidates.map((candidate) => [candidate.edge.id, candidate]));
|
|
471
|
+
const result = [];
|
|
472
|
+
const usedEdges = new Set();
|
|
473
|
+
const usedHostnames = new Set();
|
|
474
|
+
const previous = [
|
|
475
|
+
...(doc.reconciliation?.activeRevision?.mxSlots || []),
|
|
476
|
+
...(doc.reconciliation?.pendingRevision?.mxSlots || []),
|
|
477
|
+
];
|
|
478
|
+
for (const priority of [10, 20]) {
|
|
479
|
+
const old = previous.find((slot) => slot.priority === priority);
|
|
480
|
+
const candidate = old ? byId.get(old.edgeId) : undefined;
|
|
481
|
+
if (!candidate || candidate.hostname !== old?.hostname)
|
|
482
|
+
continue;
|
|
483
|
+
if (usedEdges.has(candidate.edge.id) || usedHostnames.has(candidate.hostname))
|
|
137
484
|
continue;
|
|
138
|
-
|
|
485
|
+
result.push({ priority, edgeId: candidate.edge.id, hostname: candidate.hostname });
|
|
486
|
+
usedEdges.add(candidate.edge.id);
|
|
487
|
+
usedHostnames.add(candidate.hostname);
|
|
139
488
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
if (!
|
|
489
|
+
for (const priority of [10, 20]) {
|
|
490
|
+
if (result.some((slot) => slot.priority === priority))
|
|
491
|
+
continue;
|
|
492
|
+
const candidate = candidates.find((entry) => (!usedEdges.has(entry.edge.id) && !usedHostnames.has(entry.hostname)));
|
|
493
|
+
if (!candidate)
|
|
494
|
+
continue;
|
|
495
|
+
result.push({ priority, edgeId: candidate.edge.id, hostname: candidate.hostname });
|
|
496
|
+
usedEdges.add(candidate.edge.id);
|
|
497
|
+
usedHostnames.add(candidate.hostname);
|
|
498
|
+
}
|
|
499
|
+
return result.sort((left, right) => left.priority - right.priority);
|
|
500
|
+
}
|
|
501
|
+
buildSpfValue(identities) {
|
|
502
|
+
const terms = new Set();
|
|
503
|
+
for (const identity of identities) {
|
|
504
|
+
if (identity.ipv4)
|
|
505
|
+
terms.add(`ip4:${identity.ipv4}`);
|
|
506
|
+
if (identity.ipv6)
|
|
507
|
+
terms.add(`ip6:${identity.ipv6}`);
|
|
508
|
+
}
|
|
509
|
+
return `v=spf1 ${[...terms].sort().join(' ')} -all`.replace(/\s+/g, ' ').trim();
|
|
510
|
+
}
|
|
511
|
+
async persistDesiredPlan(plan) {
|
|
512
|
+
const previous = plan.doc.reconciliation;
|
|
513
|
+
const previousSignature = JSON.stringify((previous?.intents || []).map((intent) => [intent.key, intent.value]));
|
|
514
|
+
const nextSignature = JSON.stringify(plan.intents.map((intent) => [intent.key, intent.value]));
|
|
515
|
+
const generation = (previous?.desiredGeneration || 0) + (previousSignature === nextSignature ? 0 : 1);
|
|
516
|
+
plan.doc.reconciliation = {
|
|
517
|
+
lifecycleStatus: previous?.lifecycleStatus === 'active' ? 'active' : 'pending',
|
|
518
|
+
desiredGeneration: Math.max(generation, 1),
|
|
519
|
+
activeRevision: previous?.activeRevision,
|
|
520
|
+
pendingRevision: plan.revision,
|
|
521
|
+
intents: plan.intents,
|
|
522
|
+
errors: plan.preliminaryErrors,
|
|
523
|
+
capability: {
|
|
524
|
+
egressIdentityProof: plan.egressIdentitySupported ? 'supported' : 'unsupported',
|
|
525
|
+
selectorCorrectSigning: plan.selectorCorrectSigningSupported ? 'supported' : 'unsupported',
|
|
526
|
+
},
|
|
527
|
+
lastAttemptAt: new Date().toISOString(),
|
|
528
|
+
retryAt: new Date(Date.now() + MAIL_DNS_RETRY_INTERVAL_MS).toISOString(),
|
|
529
|
+
};
|
|
530
|
+
plan.doc.updatedAt = new Date().toISOString();
|
|
531
|
+
await plan.doc.save();
|
|
532
|
+
}
|
|
533
|
+
async persistDeletingAttempt(doc) {
|
|
534
|
+
doc.reconciliation = {
|
|
535
|
+
...(doc.reconciliation || {
|
|
536
|
+
lifecycleStatus: 'deleting',
|
|
537
|
+
desiredGeneration: 1,
|
|
538
|
+
intents: [],
|
|
539
|
+
errors: [],
|
|
540
|
+
}),
|
|
541
|
+
lifecycleStatus: 'deleting',
|
|
542
|
+
intents: [],
|
|
543
|
+
errors: (doc.reconciliation?.errors || []).filter((error) => error.code !== 'DNS_CLEANUP_FAILED'),
|
|
544
|
+
lastAttemptAt: new Date().toISOString(),
|
|
545
|
+
retryAt: new Date(Date.now() + MAIL_DNS_RETRY_INTERVAL_MS).toISOString(),
|
|
546
|
+
};
|
|
547
|
+
await doc.save();
|
|
548
|
+
}
|
|
549
|
+
async reconcileZones(intents, zones) {
|
|
550
|
+
const errors = new Map();
|
|
551
|
+
const byZone = new Map();
|
|
552
|
+
for (const intent of intents) {
|
|
553
|
+
if (!intent.domainId || intent.error)
|
|
145
554
|
continue;
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
555
|
+
const group = byZone.get(intent.domainId) || [];
|
|
556
|
+
group.push(intent);
|
|
557
|
+
byZone.set(intent.domainId, group);
|
|
558
|
+
}
|
|
559
|
+
for (const [zoneId, zoneIntents] of byZone) {
|
|
560
|
+
const zone = zones.find((candidate) => candidate.id === zoneId);
|
|
561
|
+
if (!zone)
|
|
149
562
|
continue;
|
|
563
|
+
try {
|
|
564
|
+
if (zone.source === 'provider') {
|
|
565
|
+
const result = await this.dcRouterRef.dnsManager.syncDomain(zone.id);
|
|
566
|
+
if (!result.success)
|
|
567
|
+
throw new Error(result.message || `Failed to refresh ${zone.name}`);
|
|
568
|
+
}
|
|
569
|
+
for (const intent of this.sortIntents(zoneIntents)) {
|
|
570
|
+
await this.reconcileIntent(intent, zoneIntents);
|
|
571
|
+
}
|
|
150
572
|
}
|
|
151
|
-
|
|
152
|
-
|
|
573
|
+
catch (error) {
|
|
574
|
+
const outcome = {
|
|
575
|
+
code: 'DNS_PROVIDER_ZONE_FAILED',
|
|
576
|
+
message: `DNS zone ${zone.name} reconciliation failed: ${error.message}`,
|
|
577
|
+
retryable: true,
|
|
578
|
+
};
|
|
579
|
+
errors.set(zone.id, outcome);
|
|
580
|
+
for (const intent of zoneIntents) {
|
|
581
|
+
intent.status = 'failed';
|
|
582
|
+
intent.error = { ...outcome, recordKey: intent.key };
|
|
583
|
+
}
|
|
153
584
|
}
|
|
154
585
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return
|
|
586
|
+
return errors;
|
|
587
|
+
}
|
|
588
|
+
sortIntents(intents) {
|
|
589
|
+
const rank = (intent) => {
|
|
590
|
+
if (intent.type === 'A' || intent.type === 'AAAA')
|
|
591
|
+
return 0;
|
|
592
|
+
if (intent.type === 'TXT' && intent.name.includes('._domainkey.'))
|
|
593
|
+
return 1;
|
|
594
|
+
if (intent.type === 'TXT')
|
|
595
|
+
return 2;
|
|
596
|
+
return 3; // MX is exposed only after identity/auth records exist.
|
|
597
|
+
};
|
|
598
|
+
return [...intents].sort((left, right) => rank(left) - rank(right) || left.key.localeCompare(right.key));
|
|
599
|
+
}
|
|
600
|
+
async reconcileIntent(intent, zoneIntents) {
|
|
601
|
+
const records = await DnsRecordDoc.findByDomainId(intent.domainId);
|
|
602
|
+
const rrset = records.filter((record) => (record.name.toLowerCase() === intent.name.toLowerCase() && record.type === intent.type));
|
|
603
|
+
const exact = rrset.filter((record) => this.valuesEqual(intent.type, record.value, intent.value));
|
|
604
|
+
const desiredValues = zoneIntents
|
|
605
|
+
.filter((candidate) => candidate.name.toLowerCase() === intent.name.toLowerCase() && candidate.type === intent.type)
|
|
606
|
+
.map((candidate) => candidate.value);
|
|
607
|
+
const unmanaged = rrset.filter((record) => (record.managedBy !== MAIL_DNS_MANAGED_BY && this.isRelevantUnmanagedTxt(intent, record.value)));
|
|
608
|
+
const exactUnmanaged = exact.filter((record) => record.managedBy !== MAIL_DNS_MANAGED_BY);
|
|
609
|
+
const conflictingUnmanaged = unmanaged.filter((record) => (!desiredValues.some((desired) => this.valuesEqual(intent.type, record.value, desired))));
|
|
610
|
+
if (conflictingUnmanaged.length > 0 || (intent.type === 'TXT' && exactUnmanaged.length > 1)) {
|
|
611
|
+
intent.status = 'conflict';
|
|
612
|
+
intent.error = {
|
|
613
|
+
code: 'DNS_UNMANAGED_CONFLICT',
|
|
614
|
+
message: `Unmanaged ${intent.type} record conflicts with ${intent.name}`,
|
|
615
|
+
recordKey: intent.key,
|
|
616
|
+
retryable: false,
|
|
617
|
+
};
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (exactUnmanaged.length === 1) {
|
|
621
|
+
// Exact operator record satisfies the intent without adoption/deletion.
|
|
622
|
+
// Remove only a dcrouter-owned duplicate of this same intent; other MX
|
|
623
|
+
// values in the desired RRset remain independently managed.
|
|
624
|
+
const ownedDuplicates = rrset.filter((record) => (record.managedBy === MAIL_DNS_MANAGED_BY
|
|
625
|
+
&& (record.managedRecordKey === intent.key
|
|
626
|
+
|| this.valuesEqual(intent.type, record.value, intent.value))));
|
|
627
|
+
for (const duplicate of ownedDuplicates) {
|
|
628
|
+
const result = await this.dcRouterRef.dnsManager.deleteRecord(duplicate.id);
|
|
629
|
+
if (!result.success)
|
|
630
|
+
throw new Error(result.message || `Failed to delete duplicate ${intent.key}`);
|
|
161
631
|
}
|
|
162
|
-
|
|
632
|
+
intent.status = 'satisfied';
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
let managed = rrset.find((record) => record.managedRecordKey === intent.key);
|
|
636
|
+
if (!managed) {
|
|
637
|
+
const adoptable = exact.find((record) => record.managedBy === MAIL_DNS_MANAGED_BY);
|
|
638
|
+
if (adoptable) {
|
|
639
|
+
adoptable.managedOwnerId = intent.ownerId;
|
|
640
|
+
adoptable.managedRecordKey = intent.key;
|
|
641
|
+
await adoptable.save();
|
|
642
|
+
managed = adoptable;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (managed) {
|
|
646
|
+
if (!this.valuesEqual(intent.type, managed.value, intent.value) || managed.name !== intent.name) {
|
|
647
|
+
const result = await this.dcRouterRef.dnsManager.updateRecord({
|
|
648
|
+
id: managed.id,
|
|
649
|
+
name: intent.name,
|
|
650
|
+
value: intent.value,
|
|
651
|
+
ttl: intent.ttl,
|
|
652
|
+
});
|
|
653
|
+
if (!result.success)
|
|
654
|
+
throw new Error(result.message || `Failed to update ${intent.key}`);
|
|
655
|
+
}
|
|
656
|
+
intent.providerRecordId = managed.providerRecordId;
|
|
657
|
+
intent.status = 'satisfied';
|
|
658
|
+
intent.lastAttemptAt = new Date().toISOString();
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
const result = await this.dcRouterRef.dnsManager.createRecord({
|
|
662
|
+
domainId: intent.domainId,
|
|
663
|
+
name: intent.name,
|
|
664
|
+
type: intent.type,
|
|
665
|
+
value: intent.value,
|
|
666
|
+
ttl: intent.ttl,
|
|
667
|
+
createdBy: MAIL_DNS_SYNC_CREATED_BY,
|
|
668
|
+
managedBy: MAIL_DNS_MANAGED_BY,
|
|
669
|
+
managedOwnerId: intent.ownerId,
|
|
670
|
+
managedRecordKey: intent.key,
|
|
163
671
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
672
|
+
if (!result.success)
|
|
673
|
+
throw new Error(result.message || `Failed to create ${intent.key}`);
|
|
674
|
+
intent.status = 'satisfied';
|
|
675
|
+
intent.lastAttemptAt = new Date().toISOString();
|
|
676
|
+
}
|
|
677
|
+
valuesEqual(type, left, right) {
|
|
678
|
+
if (type === 'MX')
|
|
679
|
+
return normalizeMx(left) === normalizeMx(right);
|
|
680
|
+
if (type === 'A' || type === 'AAAA')
|
|
681
|
+
return left.trim() === right.trim();
|
|
682
|
+
return left.trim() === right.trim();
|
|
683
|
+
}
|
|
684
|
+
isRelevantUnmanagedTxt(intent, value) {
|
|
685
|
+
if (intent.type !== 'TXT')
|
|
171
686
|
return true;
|
|
687
|
+
const normalizedIntent = intent.value.trim().toLowerCase();
|
|
688
|
+
const normalizedValue = value.trim().toLowerCase();
|
|
689
|
+
if (normalizedIntent.startsWith('v=spf1'))
|
|
690
|
+
return normalizedValue.startsWith('v=spf1');
|
|
691
|
+
if (normalizedIntent.startsWith('v=dmarc1'))
|
|
692
|
+
return normalizedValue.startsWith('v=dmarc1');
|
|
693
|
+
if (normalizedIntent.startsWith('v=dkim1'))
|
|
694
|
+
return normalizedValue.startsWith('v=dkim1');
|
|
695
|
+
return this.valuesEqual(intent.type, value, intent.value);
|
|
696
|
+
}
|
|
697
|
+
async validateAndActivate(plan, errors, zoneErrors) {
|
|
698
|
+
const verifiable = plan.intents.filter((intent) => (!intent.error && !zoneErrors.has(intent.domainId)));
|
|
699
|
+
const markResult = (intent, result) => {
|
|
700
|
+
if (result.valid) {
|
|
701
|
+
intent.status = 'valid';
|
|
702
|
+
intent.validatedAt = new Date().toISOString();
|
|
703
|
+
intent.error = undefined;
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
intent.status = 'pending';
|
|
707
|
+
intent.error = {
|
|
708
|
+
code: 'DNS_PROPAGATION_PENDING',
|
|
709
|
+
message: result.reason || `${intent.type} ${intent.name} has not propagated`,
|
|
710
|
+
recordKey: intent.key,
|
|
711
|
+
retryable: true,
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
const mxByName = new Map();
|
|
716
|
+
for (const intent of verifiable.filter((candidate) => candidate.type === 'MX')) {
|
|
717
|
+
const group = mxByName.get(intent.name) || [];
|
|
718
|
+
group.push(intent);
|
|
719
|
+
mxByName.set(intent.name, group);
|
|
720
|
+
}
|
|
721
|
+
await Promise.all([
|
|
722
|
+
...verifiable.filter((intent) => intent.type !== 'MX').map(async (intent) => {
|
|
723
|
+
const result = await this.verifier.verifyRecord(intent)
|
|
724
|
+
.catch((error) => ({ valid: false, reason: error.message }));
|
|
725
|
+
markResult(intent, result);
|
|
726
|
+
}),
|
|
727
|
+
...[...mxByName.values()].map(async (intents) => {
|
|
728
|
+
const previousMx = (plan.doc.reconciliation?.activeRevision?.mxSlots || [])
|
|
729
|
+
.map((slot) => `${slot.priority} ${slot.hostname}`).sort();
|
|
730
|
+
const desiredMx = intents.map((intent) => normalizeMx(intent.value)).sort();
|
|
731
|
+
const isMakeBeforeBreakTransition = previousMx.length > 0
|
|
732
|
+
&& JSON.stringify(previousMx) !== JSON.stringify(desiredMx);
|
|
733
|
+
const result = await (this.verifier.verifyMxSet && !isMakeBeforeBreakTransition
|
|
734
|
+
? this.verifier.verifyMxSet(intents)
|
|
735
|
+
: Promise.all(intents.map((intent) => this.verifier.verifyRecord(intent))).then((results) => ({
|
|
736
|
+
valid: results.every((entry) => entry.valid),
|
|
737
|
+
reason: results.find((entry) => !entry.valid)?.reason,
|
|
738
|
+
})))
|
|
739
|
+
.catch((error) => ({ valid: false, reason: error.message }));
|
|
740
|
+
for (const intent of intents)
|
|
741
|
+
markResult(intent, result);
|
|
742
|
+
}),
|
|
743
|
+
]);
|
|
744
|
+
for (const intent of plan.intents) {
|
|
745
|
+
if (intent.error && !errors.some((error) => error.code === intent.error.code && error.recordKey === intent.key)) {
|
|
746
|
+
errors.push(intent.error);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
if (plan.egressIdentitySupported && plan.revision.edgeIdentities.length > 0) {
|
|
750
|
+
const identityResults = await Promise.all(plan.revision.edgeIdentities.map(async (identity) => ({
|
|
751
|
+
identity,
|
|
752
|
+
result: await this.verifier.verifyForwardConfirmedIdentity(identity)
|
|
753
|
+
.catch((error) => ({ valid: false, reason: error.message })),
|
|
754
|
+
})));
|
|
755
|
+
for (const { identity, result } of identityResults) {
|
|
756
|
+
if (!result.valid) {
|
|
757
|
+
errors.push({
|
|
758
|
+
code: 'FCRDNS_INVALID',
|
|
759
|
+
message: result.reason || `FCrDNS validation failed for ${identity.edgeId}`,
|
|
760
|
+
retryable: true,
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const canActivate = plan.egressIdentitySupported
|
|
766
|
+
&& plan.revision.edgeIdentities.length > 0
|
|
767
|
+
&& (plan.revision.edgeIdentities.length >= 2
|
|
768
|
+
? plan.revision.mxSlots.length === 2
|
|
769
|
+
: plan.revision.mxSlots.length === 1)
|
|
770
|
+
&& plan.selectorCorrectSigningSupported
|
|
771
|
+
&& Boolean(this.getActiveDkim(plan.doc))
|
|
772
|
+
&& plan.intents.length > 0
|
|
773
|
+
&& plan.intents.every((intent) => intent.status === 'valid')
|
|
774
|
+
&& errors.length === 0;
|
|
775
|
+
const hasPermanentError = errors.some((error) => error.retryable === false)
|
|
776
|
+
|| errors.some((error) => ['DNS_PROVIDER_ZONE_FAILED', 'DNS_UNMANAGED_CONFLICT'].includes(error.code));
|
|
777
|
+
const previousActive = plan.doc.reconciliation?.activeRevision;
|
|
778
|
+
const topologyChanged = Boolean(previousActive) && JSON.stringify({
|
|
779
|
+
selector: previousActive?.selector,
|
|
780
|
+
edgeIdentities: previousActive?.edgeIdentities,
|
|
781
|
+
mxSlots: previousActive?.mxSlots,
|
|
782
|
+
}) !== JSON.stringify({
|
|
783
|
+
selector: plan.revision.selector,
|
|
784
|
+
edgeIdentities: plan.revision.edgeIdentities,
|
|
785
|
+
mxSlots: plan.revision.mxSlots,
|
|
172
786
|
});
|
|
787
|
+
const now = new Date().toISOString();
|
|
788
|
+
if (canActivate && plan.doc.pendingDkim) {
|
|
789
|
+
this.promotePendingDkim(plan.doc, now);
|
|
790
|
+
}
|
|
791
|
+
plan.doc.reconciliation = {
|
|
792
|
+
lifecycleStatus: canActivate ? 'active' : hasPermanentError ? 'failed' : 'pending',
|
|
793
|
+
desiredGeneration: plan.doc.reconciliation?.desiredGeneration || 1,
|
|
794
|
+
activeRevision: canActivate
|
|
795
|
+
? { ...plan.revision, activatedAt: now }
|
|
796
|
+
: plan.doc.reconciliation?.activeRevision,
|
|
797
|
+
pendingRevision: canActivate ? undefined : plan.revision,
|
|
798
|
+
intents: plan.intents,
|
|
799
|
+
errors,
|
|
800
|
+
capability: {
|
|
801
|
+
egressIdentityProof: plan.egressIdentitySupported ? 'supported' : 'unsupported',
|
|
802
|
+
selectorCorrectSigning: plan.selectorCorrectSigningSupported ? 'supported' : 'unsupported',
|
|
803
|
+
},
|
|
804
|
+
lastAttemptAt: now,
|
|
805
|
+
...(canActivate ? { lastSuccessAt: now } : { retryAt: new Date(Date.now() + MAIL_DNS_RETRY_INTERVAL_MS).toISOString() }),
|
|
806
|
+
};
|
|
807
|
+
plan.doc.dnsStatus = {
|
|
808
|
+
mx: this.statusForIntent(plan.intents, (intent) => intent.type === 'MX'),
|
|
809
|
+
spf: this.statusForIntent(plan.intents, (intent) => intent.type === 'TXT' && intent.value.startsWith('v=spf1')),
|
|
810
|
+
dkim: this.statusForIntent(plan.intents, (intent) => intent.type === 'TXT' && intent.name.includes('._domainkey.')),
|
|
811
|
+
dmarc: this.statusForIntent(plan.intents, (intent) => intent.type === 'TXT' && intent.value.startsWith('v=DMARC1')),
|
|
812
|
+
lastCheckedAt: now,
|
|
813
|
+
};
|
|
814
|
+
plan.doc.updatedAt = now;
|
|
815
|
+
await plan.doc.save();
|
|
816
|
+
if (canActivate && topologyChanged) {
|
|
817
|
+
// The transition SPF intentionally authorizes old + new identities. Run
|
|
818
|
+
// one immediate follow-up to contract it to the newly active revision.
|
|
819
|
+
this.dirty = true;
|
|
820
|
+
}
|
|
173
821
|
}
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
822
|
+
promotePendingDkim(doc, now) {
|
|
823
|
+
const pending = doc.pendingDkim;
|
|
824
|
+
if (!pending)
|
|
825
|
+
return;
|
|
826
|
+
const previous = this.getActiveDkim(doc);
|
|
827
|
+
const overlapDays = Math.max(1, doc.dkim.retirementOverlapDays || 30);
|
|
828
|
+
const retiring = (doc.retiringDkim || []).filter((material) => (material.selector !== pending.selector
|
|
829
|
+
&& (!material.retireAfter || Date.parse(material.retireAfter) > Date.now())));
|
|
830
|
+
if (previous && previous.selector !== pending.selector) {
|
|
831
|
+
retiring.push({
|
|
832
|
+
...previous,
|
|
833
|
+
retireAfter: new Date(Date.now() + overlapDays * 86_400_000).toISOString(),
|
|
834
|
+
});
|
|
179
835
|
}
|
|
180
|
-
|
|
836
|
+
doc.activeDkim = { ...pending, validatedAt: now, promotedAt: now };
|
|
837
|
+
doc.pendingDkim = undefined;
|
|
838
|
+
doc.retiringDkim = retiring;
|
|
839
|
+
doc.dkim.selector = pending.selector;
|
|
840
|
+
doc.dkim.keySize = pending.keySize;
|
|
841
|
+
doc.dkim.publicKey = pending.publicKey;
|
|
842
|
+
doc.dkim.lastRotatedAt = now;
|
|
181
843
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
844
|
+
statusForIntent(intents, predicate) {
|
|
845
|
+
const selected = intents.filter(predicate);
|
|
846
|
+
if (selected.length === 0)
|
|
847
|
+
return 'missing';
|
|
848
|
+
if (selected.every((intent) => intent.status === 'valid'))
|
|
849
|
+
return 'valid';
|
|
850
|
+
if (selected.some((intent) => intent.status === 'conflict' || intent.status === 'failed'))
|
|
851
|
+
return 'invalid';
|
|
852
|
+
return 'missing';
|
|
853
|
+
}
|
|
854
|
+
async cleanupStaleManagedRecords(zones) {
|
|
855
|
+
const docs = await EmailDomainDoc.findAll();
|
|
856
|
+
const keep = new Set();
|
|
857
|
+
for (const doc of docs) {
|
|
858
|
+
if (doc.reconciliation?.lifecycleStatus === 'deleting')
|
|
859
|
+
continue;
|
|
860
|
+
for (const intent of doc.reconciliation?.intents || [])
|
|
861
|
+
keep.add(intent.key);
|
|
862
|
+
if (doc.reconciliation?.lifecycleStatus !== 'active') {
|
|
863
|
+
for (const key of doc.reconciliation?.activeRevision?.recordKeys || [])
|
|
864
|
+
keep.add(key);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
const managed = (await DnsRecordDoc.findAll()).filter((record) => record.managedBy === MAIL_DNS_MANAGED_BY);
|
|
868
|
+
for (const record of managed) {
|
|
869
|
+
if (record.managedRecordKey && keep.has(record.managedRecordKey))
|
|
870
|
+
continue;
|
|
871
|
+
try {
|
|
872
|
+
const result = await this.dcRouterRef.dnsManager.deleteRecord(record.id);
|
|
873
|
+
if (!result.success)
|
|
874
|
+
throw new Error(result.message || 'delete failed');
|
|
875
|
+
}
|
|
876
|
+
catch (error) {
|
|
877
|
+
const ownerId = record.managedOwnerId?.replace(/^domain:/, '');
|
|
878
|
+
const owner = ownerId ? docs.find((doc) => doc.id === ownerId) : undefined;
|
|
879
|
+
if (owner?.reconciliation) {
|
|
880
|
+
owner.reconciliation.errors.push({
|
|
881
|
+
code: 'DNS_CLEANUP_FAILED',
|
|
882
|
+
message: `Failed to delete ${record.type} ${record.name}: ${error.message}`,
|
|
883
|
+
recordKey: record.managedRecordKey,
|
|
884
|
+
retryable: true,
|
|
885
|
+
});
|
|
886
|
+
owner.reconciliation.retryAt = new Date(Date.now() + MAIL_DNS_RETRY_INTERVAL_MS).toISOString();
|
|
887
|
+
await owner.save();
|
|
190
888
|
}
|
|
191
889
|
}
|
|
192
890
|
}
|
|
193
|
-
|
|
891
|
+
}
|
|
892
|
+
async finalizeDeletingDomains() {
|
|
893
|
+
const docs = await EmailDomainDoc.findAll();
|
|
894
|
+
const records = await DnsRecordDoc.findAll();
|
|
895
|
+
for (const doc of docs) {
|
|
896
|
+
if (doc.reconciliation?.lifecycleStatus !== 'deleting')
|
|
897
|
+
continue;
|
|
898
|
+
const owned = records.some((record) => (record.managedBy === MAIL_DNS_MANAGED_BY && record.managedOwnerId === `domain:${doc.id}`));
|
|
899
|
+
if (owned || doc.reconciliation.errors.some((error) => error.code === 'DNS_CLEANUP_FAILED'))
|
|
900
|
+
continue;
|
|
901
|
+
await doc.delete();
|
|
902
|
+
logger.log('info', `Email domain deletion finalized: ${doc.domain}`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
findZoneForName(name, zones) {
|
|
906
|
+
const normalized = normalizeHostname(name);
|
|
907
|
+
return [...zones]
|
|
908
|
+
.filter((zone) => normalized === normalizeHostname(zone.name) || normalized.endsWith(`.${normalizeHostname(zone.name)}`))
|
|
909
|
+
.sort((left, right) => right.name.length - left.name.length)[0];
|
|
194
910
|
}
|
|
195
911
|
}
|
|
196
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWlsLWRucy1zeW5jLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZW1haWwvY2xhc3Nlcy5tYWlsLWRucy1zeW5jLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFJN0UsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsZ0JBQWdCLENBQUM7QUFRekQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFJRjtJQUhaLFlBQVksQ0FBaUI7SUFDN0IsWUFBWSxHQUFHLEtBQUssQ0FBQztJQUU3QixZQUFvQixXQUFxQjtRQUFyQixnQkFBVyxHQUFYLFdBQVcsQ0FBVTtJQUFHLENBQUM7SUFFN0MsK0VBQStFO0lBQ3hFLFdBQVcsQ0FBQyxNQUFjO1FBQy9CLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBWSxFQUFFLEVBQUU7WUFDdkMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsdUJBQXVCLE1BQU0sTUFBTyxHQUFhLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNuRixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxnRkFBZ0Y7SUFDekUsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFjO1FBQzlCLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1lBQ3pCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztRQUMzQixDQUFDO1FBQ0QsSUFBSSxDQUFDLFlBQVksR0FBRyxJ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
|
|
912
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWlsLWRucy1zeW5jLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZW1haWwvY2xhc3Nlcy5tYWlsLWRucy1zeW5jLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFXN0UsT0FBTyxFQUNMLG1CQUFtQixFQUNuQix5Q0FBeUMsR0FFMUMsTUFBTSxvQ0FBb0MsQ0FBQztBQUU1QyxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxxQkFBcUIsQ0FBQztBQUM5RCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxxQkFBcUIsQ0FBQztBQUN6RCxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDO0FBaUJyRCxTQUFTLGlCQUFpQixDQUFDLEtBQWE7SUFDdEMsT0FBTyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztBQUN2RCxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsS0FBYTtJQUNoQyxNQUFNLENBQUMsUUFBUSxFQUFFLFFBQVEsR0FBRyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVELE9BQU8sR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksaUJBQWlCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztBQUM5RCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsT0FBZTtJQUNqQyxJQUFJLFVBQVUsR0FBRyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDdkMsSUFBSSxVQUFVLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDN0IsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5QyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BFLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDaEcsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUNELFVBQVUsR0FBRyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDekksQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdEMsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUN4QyxNQUFN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
|