@serve.zone/dcrouter 13.10.0 → 13.11.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/dist_serve/bundle.js +1060 -958
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +2 -0
- package/dist_ts/classes.dcrouter.js +15 -1
- package/dist_ts/db/documents/classes.email-domain.doc.d.ts +16 -0
- package/dist_ts/db/documents/classes.email-domain.doc.js +118 -0
- package/dist_ts/db/documents/index.d.ts +1 -0
- package/dist_ts/db/documents/index.js +3 -1
- package/dist_ts/email/classes.email-domain.manager.d.ts +45 -0
- package/dist_ts/email/classes.email-domain.manager.js +272 -0
- package/dist_ts/email/index.d.ts +1 -0
- package/dist_ts/email/index.js +2 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +1 -0
- package/dist_ts/opsserver/classes.opsserver.js +3 -1
- package/dist_ts/opsserver/handlers/email-domain.handler.d.ts +16 -0
- package/dist_ts/opsserver/handlers/email-domain.handler.js +149 -0
- package/dist_ts/opsserver/handlers/index.d.ts +1 -0
- package/dist_ts/opsserver/handlers/index.js +2 -1
- package/dist_ts_interfaces/data/email-domain.d.ts +68 -0
- package/dist_ts_interfaces/data/email-domain.js +2 -0
- package/dist_ts_interfaces/data/index.d.ts +1 -0
- package/dist_ts_interfaces/data/index.js +2 -1
- package/dist_ts_interfaces/requests/email-domains.d.ts +140 -0
- package/dist_ts_interfaces/requests/email-domains.js +2 -0
- package/dist_ts_interfaces/requests/index.d.ts +1 -0
- package/dist_ts_interfaces/requests/index.js +2 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +20 -0
- package/dist_ts_web/appstate.js +81 -1
- package/dist_ts_web/elements/email/index.d.ts +1 -0
- package/dist_ts_web/elements/email/index.js +2 -1
- package/dist_ts_web/elements/email/ops-view-email-domains.d.ts +19 -0
- package/dist_ts_web/elements/email/ops-view-email-domains.js +403 -0
- package/dist_ts_web/elements/ops-dashboard.js +3 -1
- package/dist_ts_web/router.js +2 -2
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +17 -0
- package/ts/db/documents/classes.email-domain.doc.ts +53 -0
- package/ts/db/documents/index.ts +3 -0
- package/ts/email/classes.email-domain.manager.ts +316 -0
- package/ts/email/index.ts +1 -0
- package/ts/opsserver/classes.opsserver.ts +2 -0
- package/ts/opsserver/handlers/email-domain.handler.ts +194 -0
- package/ts/opsserver/handlers/index.ts +2 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +123 -0
- package/ts_web/elements/email/index.ts +1 -0
- package/ts_web/elements/email/ops-view-email-domains.ts +389 -0
- package/ts_web/elements/ops-dashboard.ts +2 -0
- package/ts_web/router.ts +1 -1
|
@@ -26,4 +26,6 @@ export * from './classes.domain.doc.js';
|
|
|
26
26
|
export * from './classes.dns-record.doc.js';
|
|
27
27
|
// ACME configuration (singleton)
|
|
28
28
|
export * from './classes.acme-config.doc.js';
|
|
29
|
-
|
|
29
|
+
// Email domain management
|
|
30
|
+
export * from './classes.email-domain.doc.js';
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9kYi9kb2N1bWVudHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsOEJBQThCO0FBQzlCLGNBQWMsMkJBQTJCLENBQUM7QUFDMUMsY0FBYyxtQ0FBbUMsQ0FBQztBQUVsRCwwQkFBMEI7QUFDMUIsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLGlDQUFpQyxDQUFDO0FBQ2hELGNBQWMsNEJBQTRCLENBQUM7QUFDM0MsY0FBYyxpQ0FBaUMsQ0FBQztBQUNoRCxjQUFjLGlDQUFpQyxDQUFDO0FBQ2hELGNBQWMsaUNBQWlDLENBQUM7QUFFaEQsdUJBQXVCO0FBQ3ZCLGNBQWMsa0NBQWtDLENBQUM7QUFDakQsY0FBYyw2QkFBNkIsQ0FBQztBQUU1QywrQkFBK0I7QUFDL0IsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsK0JBQStCLENBQUM7QUFFOUMsa0NBQWtDO0FBQ2xDLGNBQWMsc0NBQXNDLENBQUM7QUFFckQsMEJBQTBCO0FBQzFCLGNBQWMsZ0NBQWdDLENBQUM7QUFDL0MsY0FBYyxxQ0FBcUMsQ0FBQztBQUVwRCwyQ0FBMkM7QUFDM0MsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsNkJBQTZCLENBQUM7QUFFNUMsaUNBQWlDO0FBQ2pDLGNBQWMsOEJBQThCLENBQUM7QUFFN0MsMEJBQTBCO0FBQzFCLGNBQWMsK0JBQStCLENBQUMifQ==
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { IEmailDomain, IEmailDnsRecord } from '../../dist_ts_interfaces/data/email-domain.js';
|
|
2
|
+
/**
|
|
3
|
+
* EmailDomainManager — orchestrates email domain setup.
|
|
4
|
+
*
|
|
5
|
+
* Wires smartmta's DKIMCreator (key generation) with dcrouter's DnsManager
|
|
6
|
+
* (record creation for dcrouter-hosted and provider-managed zones) to provide
|
|
7
|
+
* a single entry point for setting up an email domain from A to Z.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EmailDomainManager {
|
|
10
|
+
private dcRouter;
|
|
11
|
+
constructor(dcRouterRef: any);
|
|
12
|
+
private get dnsManager();
|
|
13
|
+
private get dkimCreator();
|
|
14
|
+
private get emailHostname();
|
|
15
|
+
getAll(): Promise<IEmailDomain[]>;
|
|
16
|
+
getById(id: string): Promise<IEmailDomain | null>;
|
|
17
|
+
createEmailDomain(opts: {
|
|
18
|
+
linkedDomainId: string;
|
|
19
|
+
dkimSelector?: string;
|
|
20
|
+
dkimKeySize?: number;
|
|
21
|
+
rotateKeys?: boolean;
|
|
22
|
+
rotationIntervalDays?: number;
|
|
23
|
+
}): Promise<IEmailDomain>;
|
|
24
|
+
updateEmailDomain(id: string, changes: {
|
|
25
|
+
rotateKeys?: boolean;
|
|
26
|
+
rotationIntervalDays?: number;
|
|
27
|
+
rateLimits?: IEmailDomain['rateLimits'];
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
deleteEmailDomain(id: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Compute the 4 required DNS records for an email domain.
|
|
32
|
+
*/
|
|
33
|
+
getRequiredDnsRecords(id: string): Promise<IEmailDnsRecord[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Auto-create missing DNS records via the linked domain's DNS path.
|
|
36
|
+
*/
|
|
37
|
+
provisionDnsRecords(id: string): Promise<number>;
|
|
38
|
+
/**
|
|
39
|
+
* Validate DNS records via live lookups.
|
|
40
|
+
*/
|
|
41
|
+
validateDns(id: string): Promise<IEmailDnsRecord[]>;
|
|
42
|
+
private checkMx;
|
|
43
|
+
private checkTxtRecord;
|
|
44
|
+
private docToInterface;
|
|
45
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { EmailDomainDoc } from '../db/documents/classes.email-domain.doc.js';
|
|
4
|
+
import { DomainDoc } from '../db/documents/classes.domain.doc.js';
|
|
5
|
+
import { DnsRecordDoc } from '../db/documents/classes.dns-record.doc.js';
|
|
6
|
+
/**
|
|
7
|
+
* EmailDomainManager — orchestrates email domain setup.
|
|
8
|
+
*
|
|
9
|
+
* Wires smartmta's DKIMCreator (key generation) with dcrouter's DnsManager
|
|
10
|
+
* (record creation for dcrouter-hosted and provider-managed zones) to provide
|
|
11
|
+
* a single entry point for setting up an email domain from A to Z.
|
|
12
|
+
*/
|
|
13
|
+
export class EmailDomainManager {
|
|
14
|
+
dcRouter; // DcRouter — avoids circular import
|
|
15
|
+
constructor(dcRouterRef) {
|
|
16
|
+
this.dcRouter = dcRouterRef;
|
|
17
|
+
}
|
|
18
|
+
get dnsManager() {
|
|
19
|
+
return this.dcRouter.dnsManager;
|
|
20
|
+
}
|
|
21
|
+
get dkimCreator() {
|
|
22
|
+
return this.dcRouter.emailServer?.dkimCreator;
|
|
23
|
+
}
|
|
24
|
+
get emailHostname() {
|
|
25
|
+
return this.dcRouter.options?.emailConfig?.hostname || this.dcRouter.options?.tls?.domain || 'localhost';
|
|
26
|
+
}
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// CRUD
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
async getAll() {
|
|
31
|
+
const docs = await EmailDomainDoc.findAll();
|
|
32
|
+
return docs.map((d) => this.docToInterface(d));
|
|
33
|
+
}
|
|
34
|
+
async getById(id) {
|
|
35
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
36
|
+
return doc ? this.docToInterface(doc) : null;
|
|
37
|
+
}
|
|
38
|
+
async createEmailDomain(opts) {
|
|
39
|
+
// Resolve the linked DNS domain
|
|
40
|
+
const domainDoc = await DomainDoc.findById(opts.linkedDomainId);
|
|
41
|
+
if (!domainDoc) {
|
|
42
|
+
throw new Error(`DNS domain not found: ${opts.linkedDomainId}`);
|
|
43
|
+
}
|
|
44
|
+
const domainName = domainDoc.name;
|
|
45
|
+
// Check for duplicates
|
|
46
|
+
const existing = await EmailDomainDoc.findByDomain(domainName);
|
|
47
|
+
if (existing) {
|
|
48
|
+
throw new Error(`Email domain already exists for ${domainName}`);
|
|
49
|
+
}
|
|
50
|
+
const selector = opts.dkimSelector || 'default';
|
|
51
|
+
const keySize = opts.dkimKeySize || 2048;
|
|
52
|
+
const now = new Date().toISOString();
|
|
53
|
+
// Generate DKIM keys
|
|
54
|
+
let publicKey;
|
|
55
|
+
if (this.dkimCreator) {
|
|
56
|
+
try {
|
|
57
|
+
await this.dkimCreator.handleDKIMKeysForDomain(domainName);
|
|
58
|
+
const dnsRecord = await this.dkimCreator.getDNSRecordForSelector(domainName, selector);
|
|
59
|
+
// Extract public key from the DNS record value
|
|
60
|
+
const match = dnsRecord?.value?.match(/p=([A-Za-z0-9+/=]+)/);
|
|
61
|
+
publicKey = match ? match[1] : undefined;
|
|
62
|
+
logger.log('info', `DKIM keys generated for ${domainName} (selector: ${selector})`);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
logger.log('warn', `DKIM key generation failed for ${domainName}: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Create the document
|
|
69
|
+
const doc = new EmailDomainDoc();
|
|
70
|
+
doc.id = plugins.smartunique.shortId();
|
|
71
|
+
doc.domain = domainName.toLowerCase();
|
|
72
|
+
doc.linkedDomainId = opts.linkedDomainId;
|
|
73
|
+
doc.dkim = {
|
|
74
|
+
selector,
|
|
75
|
+
keySize,
|
|
76
|
+
publicKey,
|
|
77
|
+
rotateKeys: opts.rotateKeys ?? false,
|
|
78
|
+
rotationIntervalDays: opts.rotationIntervalDays ?? 90,
|
|
79
|
+
};
|
|
80
|
+
doc.dnsStatus = {
|
|
81
|
+
mx: 'unchecked',
|
|
82
|
+
spf: 'unchecked',
|
|
83
|
+
dkim: 'unchecked',
|
|
84
|
+
dmarc: 'unchecked',
|
|
85
|
+
};
|
|
86
|
+
doc.createdAt = now;
|
|
87
|
+
doc.updatedAt = now;
|
|
88
|
+
await doc.save();
|
|
89
|
+
logger.log('info', `Email domain created: ${domainName}`);
|
|
90
|
+
return this.docToInterface(doc);
|
|
91
|
+
}
|
|
92
|
+
async updateEmailDomain(id, changes) {
|
|
93
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
94
|
+
if (!doc)
|
|
95
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
96
|
+
if (changes.rotateKeys !== undefined)
|
|
97
|
+
doc.dkim.rotateKeys = changes.rotateKeys;
|
|
98
|
+
if (changes.rotationIntervalDays !== undefined)
|
|
99
|
+
doc.dkim.rotationIntervalDays = changes.rotationIntervalDays;
|
|
100
|
+
if (changes.rateLimits !== undefined)
|
|
101
|
+
doc.rateLimits = changes.rateLimits;
|
|
102
|
+
doc.updatedAt = new Date().toISOString();
|
|
103
|
+
await doc.save();
|
|
104
|
+
}
|
|
105
|
+
async deleteEmailDomain(id) {
|
|
106
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
107
|
+
if (!doc)
|
|
108
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
109
|
+
await doc.delete();
|
|
110
|
+
logger.log('info', `Email domain deleted: ${doc.domain}`);
|
|
111
|
+
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// DNS record computation
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
/**
|
|
116
|
+
* Compute the 4 required DNS records for an email domain.
|
|
117
|
+
*/
|
|
118
|
+
async getRequiredDnsRecords(id) {
|
|
119
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
120
|
+
if (!doc)
|
|
121
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
122
|
+
const domain = doc.domain;
|
|
123
|
+
const selector = doc.dkim.selector;
|
|
124
|
+
const publicKey = doc.dkim.publicKey || '';
|
|
125
|
+
const hostname = this.emailHostname;
|
|
126
|
+
const records = [
|
|
127
|
+
{
|
|
128
|
+
type: 'MX',
|
|
129
|
+
name: domain,
|
|
130
|
+
value: `10 ${hostname}`,
|
|
131
|
+
status: doc.dnsStatus.mx,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
type: 'TXT',
|
|
135
|
+
name: domain,
|
|
136
|
+
value: 'v=spf1 a mx ~all',
|
|
137
|
+
status: doc.dnsStatus.spf,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'TXT',
|
|
141
|
+
name: `${selector}._domainkey.${domain}`,
|
|
142
|
+
value: `v=DKIM1; h=sha256; k=rsa; p=${publicKey}`,
|
|
143
|
+
status: doc.dnsStatus.dkim,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'TXT',
|
|
147
|
+
name: `_dmarc.${domain}`,
|
|
148
|
+
value: `v=DMARC1; p=none; rua=mailto:dmarc@${domain}`,
|
|
149
|
+
status: doc.dnsStatus.dmarc,
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
return records;
|
|
153
|
+
}
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// DNS provisioning
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* Auto-create missing DNS records via the linked domain's DNS path.
|
|
159
|
+
*/
|
|
160
|
+
async provisionDnsRecords(id) {
|
|
161
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
162
|
+
if (!doc)
|
|
163
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
164
|
+
if (!this.dnsManager)
|
|
165
|
+
throw new Error('DnsManager not available');
|
|
166
|
+
const requiredRecords = await this.getRequiredDnsRecords(id);
|
|
167
|
+
const domainId = doc.linkedDomainId;
|
|
168
|
+
// Get existing DNS records for the linked domain
|
|
169
|
+
const existingRecords = await DnsRecordDoc.findByDomainId(domainId);
|
|
170
|
+
let provisioned = 0;
|
|
171
|
+
for (const required of requiredRecords) {
|
|
172
|
+
// Check if a matching record already exists
|
|
173
|
+
const exists = existingRecords.some((r) => {
|
|
174
|
+
if (required.type === 'MX') {
|
|
175
|
+
return r.type === 'MX' && r.name.toLowerCase() === required.name.toLowerCase();
|
|
176
|
+
}
|
|
177
|
+
// For TXT records, match by name AND check value prefix (v=spf1, v=DKIM1, v=DMARC1)
|
|
178
|
+
if (r.type !== 'TXT' || r.name.toLowerCase() !== required.name.toLowerCase())
|
|
179
|
+
return false;
|
|
180
|
+
if (required.value.startsWith('v=spf1'))
|
|
181
|
+
return r.value.includes('v=spf1');
|
|
182
|
+
if (required.value.startsWith('v=DKIM1'))
|
|
183
|
+
return r.value.includes('v=DKIM1');
|
|
184
|
+
if (required.value.startsWith('v=DMARC1'))
|
|
185
|
+
return r.value.includes('v=DMARC1');
|
|
186
|
+
return false;
|
|
187
|
+
});
|
|
188
|
+
if (!exists) {
|
|
189
|
+
try {
|
|
190
|
+
await this.dnsManager.createRecord({
|
|
191
|
+
domainId,
|
|
192
|
+
name: required.name,
|
|
193
|
+
type: required.type,
|
|
194
|
+
value: required.value,
|
|
195
|
+
ttl: 3600,
|
|
196
|
+
createdBy: 'email-domain-manager',
|
|
197
|
+
});
|
|
198
|
+
provisioned++;
|
|
199
|
+
logger.log('info', `Provisioned ${required.type} record for ${required.name}`);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
logger.log('warn', `Failed to provision ${required.type} for ${required.name}: ${err.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Re-validate after provisioning
|
|
207
|
+
await this.validateDns(id);
|
|
208
|
+
return provisioned;
|
|
209
|
+
}
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// DNS validation
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
/**
|
|
214
|
+
* Validate DNS records via live lookups.
|
|
215
|
+
*/
|
|
216
|
+
async validateDns(id) {
|
|
217
|
+
const doc = await EmailDomainDoc.findById(id);
|
|
218
|
+
if (!doc)
|
|
219
|
+
throw new Error(`Email domain not found: ${id}`);
|
|
220
|
+
const domain = doc.domain;
|
|
221
|
+
const selector = doc.dkim.selector;
|
|
222
|
+
const resolver = new plugins.dns.promises.Resolver();
|
|
223
|
+
// MX check
|
|
224
|
+
doc.dnsStatus.mx = await this.checkMx(resolver, domain);
|
|
225
|
+
// SPF check
|
|
226
|
+
doc.dnsStatus.spf = await this.checkTxtRecord(resolver, domain, 'v=spf1');
|
|
227
|
+
// DKIM check
|
|
228
|
+
doc.dnsStatus.dkim = await this.checkTxtRecord(resolver, `${selector}._domainkey.${domain}`, 'v=DKIM1');
|
|
229
|
+
// DMARC check
|
|
230
|
+
doc.dnsStatus.dmarc = await this.checkTxtRecord(resolver, `_dmarc.${domain}`, 'v=DMARC1');
|
|
231
|
+
doc.dnsStatus.lastCheckedAt = new Date().toISOString();
|
|
232
|
+
doc.updatedAt = new Date().toISOString();
|
|
233
|
+
await doc.save();
|
|
234
|
+
return this.getRequiredDnsRecords(id);
|
|
235
|
+
}
|
|
236
|
+
async checkMx(resolver, domain) {
|
|
237
|
+
try {
|
|
238
|
+
const records = await resolver.resolveMx(domain);
|
|
239
|
+
return records && records.length > 0 ? 'valid' : 'missing';
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return 'missing';
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async checkTxtRecord(resolver, name, prefix) {
|
|
246
|
+
try {
|
|
247
|
+
const records = await resolver.resolveTxt(name);
|
|
248
|
+
const flat = records.map((r) => r.join(''));
|
|
249
|
+
const found = flat.some((r) => r.startsWith(prefix));
|
|
250
|
+
return found ? 'valid' : 'missing';
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return 'missing';
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
// Helpers
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
docToInterface(doc) {
|
|
260
|
+
return {
|
|
261
|
+
id: doc.id,
|
|
262
|
+
domain: doc.domain,
|
|
263
|
+
linkedDomainId: doc.linkedDomainId,
|
|
264
|
+
dkim: doc.dkim,
|
|
265
|
+
rateLimits: doc.rateLimits,
|
|
266
|
+
dnsStatus: doc.dnsStatus,
|
|
267
|
+
createdAt: doc.createdAt,
|
|
268
|
+
updatedAt: doc.updatedAt,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lbWFpbC1kb21haW4ubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuZW1haWwtZG9tYWluLm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDN0UsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUl6RTs7Ozs7O0dBTUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBQ3JCLFFBQVEsQ0FBTSxDQUFDLG9DQUFvQztJQUUzRCxZQUFZLFdBQWdCO1FBQzFCLElBQUksQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDO0lBQzlCLENBQUM7SUFFRCxJQUFZLFVBQVU7UUFDcEIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztJQUNsQyxDQUFDO0lBRUQsSUFBWSxXQUFXO1FBQ3JCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsV0FBVyxDQUFDO0lBQ2hELENBQUM7SUFFRCxJQUFZLGFBQWE7UUFDdkIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsUUFBUSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLElBQUksV0FBVyxDQUFDO0lBQzNHLENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsT0FBTztJQUNQLDhFQUE4RTtJQUV2RSxLQUFLLENBQUMsTUFBTTtRQUNqQixNQUFNLElBQUksR0FBRyxNQUFNLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUM1QyxPQUFP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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './classes.email-domain.manager.js';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from './classes.email-domain.manager.js';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9lbWFpbC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLG1DQUFtQyxDQUFDIn0=
|
|
@@ -32,6 +32,7 @@ export class OpsServer {
|
|
|
32
32
|
domainHandler;
|
|
33
33
|
dnsRecordHandler;
|
|
34
34
|
acmeConfigHandler;
|
|
35
|
+
emailDomainHandler;
|
|
35
36
|
constructor(dcRouterRefArg) {
|
|
36
37
|
this.dcRouterRef = dcRouterRefArg;
|
|
37
38
|
// Add our typedrouter to the dcRouter's main typedrouter
|
|
@@ -88,6 +89,7 @@ export class OpsServer {
|
|
|
88
89
|
this.domainHandler = new handlers.DomainHandler(this);
|
|
89
90
|
this.dnsRecordHandler = new handlers.DnsRecordHandler(this);
|
|
90
91
|
this.acmeConfigHandler = new handlers.AcmeConfigHandler(this);
|
|
92
|
+
this.emailDomainHandler = new handlers.EmailDomainHandler(this);
|
|
91
93
|
console.log('✅ OpsServer TypedRequest handlers initialized');
|
|
92
94
|
}
|
|
93
95
|
async stop() {
|
|
@@ -100,4 +102,4 @@ export class OpsServer {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
105
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcHNzZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9vcHNzZXJ2ZXIvY2xhc3Nlcy5vcHNzZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxLQUFLLEtBQUssTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxxQkFBcUIsQ0FBQztBQUNoRCxPQUFPLEtBQUssVUFBVSxNQUFNLDhCQUE4QixDQUFDO0FBQzNELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRWpGLE1BQU0sT0FBTyxTQUFTO0lBQ2IsV0FBVyxDQUFXO0lBQ3RCLE1BQU0sQ0FBMkQ7SUFFeEUsMkZBQTJGO0lBQ3BGLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFNUQsZ0ZBQWdGO0lBQ3pFLFVBQVUsR0FBRyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUF3RCxDQUFDO0lBQzFHLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUF3RCxDQUFDO0lBRWxILG9CQUFvQjtJQUNiLFlBQVksQ0FBeUI7SUFDcEMsYUFBYSxDQUEwQjtJQUN2QyxXQUFXLENBQXdCO0lBQ25DLGVBQWUsQ0FBNEI7SUFDM0MsWUFBWSxDQUF5QjtJQUNyQyxhQUFhLENBQTBCO0lBQ3ZDLGVBQWUsQ0FBNEI7SUFDM0Msa0JBQWtCLENBQStCO0lBQ2pELG9CQUFvQixDQUFpQztJQUNyRCxzQkFBc0IsQ0FBbUM7SUFDekQsZUFBZSxDQUE0QjtJQUMzQyxVQUFVLENBQXVCO0lBQ2pDLG9CQUFvQixDQUFpQztJQUNyRCxvQkFBb0IsQ0FBaUM7SUFDckQsb0JBQW9CLENBQWlDO0lBQ3JELFlBQVksQ0FBeUI7SUFDckMsa0JBQWtC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
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
|
+
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* CRUD + DNS provisioning handler for email domains.
|
|
6
|
+
*
|
|
7
|
+
* Auth: admin JWT or API token with `email-domains:read` / `email-domains:write` scope.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EmailDomainHandler {
|
|
10
|
+
private opsServerRef;
|
|
11
|
+
typedrouter: plugins.typedrequest.TypedRouter<interfaces.typedrequestInterfaces.ITypedRequest>;
|
|
12
|
+
constructor(opsServerRef: OpsServer);
|
|
13
|
+
private requireAuth;
|
|
14
|
+
private get manager();
|
|
15
|
+
private registerHandlers;
|
|
16
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* CRUD + DNS provisioning handler for email domains.
|
|
5
|
+
*
|
|
6
|
+
* Auth: admin JWT or API token with `email-domains:read` / `email-domains:write` scope.
|
|
7
|
+
*/
|
|
8
|
+
export class EmailDomainHandler {
|
|
9
|
+
opsServerRef;
|
|
10
|
+
typedrouter = new plugins.typedrequest.TypedRouter();
|
|
11
|
+
constructor(opsServerRef) {
|
|
12
|
+
this.opsServerRef = opsServerRef;
|
|
13
|
+
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
|
|
14
|
+
this.registerHandlers();
|
|
15
|
+
}
|
|
16
|
+
async requireAuth(request, requiredScope) {
|
|
17
|
+
if (request.identity?.jwt) {
|
|
18
|
+
try {
|
|
19
|
+
const isAdmin = await this.opsServerRef.adminHandler.adminIdentityGuard.exec({
|
|
20
|
+
identity: request.identity,
|
|
21
|
+
});
|
|
22
|
+
if (isAdmin)
|
|
23
|
+
return request.identity.userId;
|
|
24
|
+
}
|
|
25
|
+
catch { /* fall through */ }
|
|
26
|
+
}
|
|
27
|
+
if (request.apiToken) {
|
|
28
|
+
const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager;
|
|
29
|
+
if (tokenManager) {
|
|
30
|
+
const token = await tokenManager.validateToken(request.apiToken);
|
|
31
|
+
if (token) {
|
|
32
|
+
if (!requiredScope || tokenManager.hasScope(token, requiredScope)) {
|
|
33
|
+
return token.createdBy;
|
|
34
|
+
}
|
|
35
|
+
throw new plugins.typedrequest.TypedResponseError('insufficient scope');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw new plugins.typedrequest.TypedResponseError('unauthorized');
|
|
40
|
+
}
|
|
41
|
+
get manager() {
|
|
42
|
+
return this.opsServerRef.dcRouterRef.emailDomainManager;
|
|
43
|
+
}
|
|
44
|
+
registerHandlers() {
|
|
45
|
+
// List all email domains
|
|
46
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getEmailDomains', async (dataArg) => {
|
|
47
|
+
await this.requireAuth(dataArg, 'email-domains:read');
|
|
48
|
+
if (!this.manager)
|
|
49
|
+
return { domains: [] };
|
|
50
|
+
return { domains: await this.manager.getAll() };
|
|
51
|
+
}));
|
|
52
|
+
// Get single email domain
|
|
53
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getEmailDomain', async (dataArg) => {
|
|
54
|
+
await this.requireAuth(dataArg, 'email-domains:read');
|
|
55
|
+
if (!this.manager)
|
|
56
|
+
return { domain: null };
|
|
57
|
+
return { domain: await this.manager.getById(dataArg.id) };
|
|
58
|
+
}));
|
|
59
|
+
// Create email domain
|
|
60
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('createEmailDomain', async (dataArg) => {
|
|
61
|
+
await this.requireAuth(dataArg, 'email-domains:write');
|
|
62
|
+
if (!this.manager) {
|
|
63
|
+
return { success: false, message: 'EmailDomainManager not initialized' };
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const domain = await this.manager.createEmailDomain({
|
|
67
|
+
linkedDomainId: dataArg.linkedDomainId,
|
|
68
|
+
dkimSelector: dataArg.dkimSelector,
|
|
69
|
+
dkimKeySize: dataArg.dkimKeySize,
|
|
70
|
+
rotateKeys: dataArg.rotateKeys,
|
|
71
|
+
rotationIntervalDays: dataArg.rotationIntervalDays,
|
|
72
|
+
});
|
|
73
|
+
return { success: true, domain };
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
return { success: false, message: err.message };
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
// Update email domain
|
|
80
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('updateEmailDomain', async (dataArg) => {
|
|
81
|
+
await this.requireAuth(dataArg, 'email-domains:write');
|
|
82
|
+
if (!this.manager) {
|
|
83
|
+
return { success: false, message: 'EmailDomainManager not initialized' };
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await this.manager.updateEmailDomain(dataArg.id, {
|
|
87
|
+
rotateKeys: dataArg.rotateKeys,
|
|
88
|
+
rotationIntervalDays: dataArg.rotationIntervalDays,
|
|
89
|
+
rateLimits: dataArg.rateLimits,
|
|
90
|
+
});
|
|
91
|
+
return { success: true };
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return { success: false, message: err.message };
|
|
95
|
+
}
|
|
96
|
+
}));
|
|
97
|
+
// Delete email domain
|
|
98
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('deleteEmailDomain', async (dataArg) => {
|
|
99
|
+
await this.requireAuth(dataArg, 'email-domains:write');
|
|
100
|
+
if (!this.manager) {
|
|
101
|
+
return { success: false, message: 'EmailDomainManager not initialized' };
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
await this.manager.deleteEmailDomain(dataArg.id);
|
|
105
|
+
return { success: true };
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return { success: false, message: err.message };
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
// Validate DNS records
|
|
112
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('validateEmailDomain', async (dataArg) => {
|
|
113
|
+
await this.requireAuth(dataArg, 'email-domains:read');
|
|
114
|
+
if (!this.manager) {
|
|
115
|
+
return { success: false, message: 'EmailDomainManager not initialized' };
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const records = await this.manager.validateDns(dataArg.id);
|
|
119
|
+
const domain = await this.manager.getById(dataArg.id);
|
|
120
|
+
return { success: true, domain: domain ?? undefined, records };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return { success: false, message: err.message };
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
// Get required DNS records
|
|
127
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getEmailDomainDnsRecords', async (dataArg) => {
|
|
128
|
+
await this.requireAuth(dataArg, 'email-domains:read');
|
|
129
|
+
if (!this.manager)
|
|
130
|
+
return { records: [] };
|
|
131
|
+
return { records: await this.manager.getRequiredDnsRecords(dataArg.id) };
|
|
132
|
+
}));
|
|
133
|
+
// Auto-provision DNS records
|
|
134
|
+
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('provisionEmailDomainDns', async (dataArg) => {
|
|
135
|
+
await this.requireAuth(dataArg, 'email-domains:write');
|
|
136
|
+
if (!this.manager) {
|
|
137
|
+
return { success: false, message: 'EmailDomainManager not initialized' };
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const provisioned = await this.manager.provisionDnsRecords(dataArg.id);
|
|
141
|
+
return { success: true, provisioned };
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
return { success: false, message: err.message };
|
|
145
|
+
}
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1haWwtZG9tYWluLmhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9vcHNzZXJ2ZXIvaGFuZGxlcnMvZW1haWwtZG9tYWluLmhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUU1QyxPQUFPLEtBQUssVUFBVSxNQUFNLGlDQUFpQyxDQUFDO0FBRTlEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBR1Q7SUFGYixXQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRTVELFlBQW9CLFlBQXVCO1FBQXZCLGlCQUFZLEdBQVosWUFBWSxDQUFXO1FBQ3pDLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0QsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVPLEtBQUssQ0FBQyxXQUFXLENBQ3ZCLE9BQW9FLEVBQ3BFLGFBQThDO1FBRTlDLElBQUksT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUM7b0JBQzNFLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUTtpQkFDM0IsQ0FBQyxDQUFDO2dCQUNILElBQUksT0FBTztvQkFBRSxPQUFPLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQzlDLENBQUM7WUFBQyxNQUFNLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7UUFFRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNyQixNQUFNLFlBQVksR0FBRyxJQUFJLENB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
|
|
@@ -18,4 +18,5 @@ export * from './dns-provider.handler.js';
|
|
|
18
18
|
export * from './domain.handler.js';
|
|
19
19
|
export * from './dns-record.handler.js';
|
|
20
20
|
export * from './acme-config.handler.js';
|
|
21
|
-
|
|
21
|
+
export * from './email-domain.handler.js';
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9vcHNzZXJ2ZXIvaGFuZGxlcnMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsNEJBQTRCLENBQUM7QUFDM0MsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsMkJBQTJCLENBQUMifQ==
|