feat(dns): Implement DNS management functionality
- Added DnsManager and DnsEntry classes to handle DNS entries. - Introduced new interfaces for DNS entry requests and data structures. - Updated Cloudly class to include DnsManager instance. - Enhanced app state to manage DNS entries and actions for creating, updating, and deleting DNS records. - Created UI components for DNS management, including forms for adding and editing DNS entries. - Updated overview and services views to reflect DNS entries. - Added validation and formatting methods for DNS entries.
This commit is contained in:
@@ -25,6 +25,8 @@ import { ExternalRegistryManager } from './manager.externalregistry/index.js';
|
||||
import { ImageManager } from './manager.image/classes.imagemanager.js';
|
||||
import { ServiceManager } from './manager.service/classes.servicemanager.js';
|
||||
import { DeploymentManager } from './manager.deployment/classes.deploymentmanager.js';
|
||||
import { DnsManager } from './manager.dns/classes.dnsmanager.js';
|
||||
import { DomainManager } from './manager.domain/classes.domainmanager.js';
|
||||
import { logger } from './logger.js';
|
||||
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';
|
||||
import { CloudlySettingsManager } from './manager.settings/classes.settingsmanager.js';
|
||||
@@ -64,6 +66,8 @@ export class Cloudly {
|
||||
public imageManager: ImageManager;
|
||||
public serviceManager: ServiceManager;
|
||||
public deploymentManager: DeploymentManager;
|
||||
public dnsManager: DnsManager;
|
||||
public domainManager: DomainManager;
|
||||
public taskManager: CloudlyTaskmanager;
|
||||
public nodeManager: CloudlyNodeManager;
|
||||
public baremetalManager: CloudlyBaremetalManager;
|
||||
@@ -95,6 +99,8 @@ export class Cloudly {
|
||||
this.imageManager = new ImageManager(this);
|
||||
this.serviceManager = new ServiceManager(this);
|
||||
this.deploymentManager = new DeploymentManager(this);
|
||||
this.dnsManager = new DnsManager(this);
|
||||
this.domainManager = new DomainManager(this);
|
||||
this.taskManager = new CloudlyTaskmanager(this);
|
||||
this.secretManager = new CloudlySecretManager(this);
|
||||
this.nodeManager = new CloudlyNodeManager(this);
|
||||
|
148
ts/manager.dns/classes.dnsentry.ts
Normal file
148
ts/manager.dns/classes.dnsentry.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { DnsManager } from './classes.dnsmanager.js';
|
||||
|
||||
export class DnsEntry extends plugins.smartdata.SmartDataDbDoc<
|
||||
DnsEntry,
|
||||
plugins.servezoneInterfaces.data.IDnsEntry,
|
||||
DnsManager
|
||||
> {
|
||||
// STATIC
|
||||
public static async getDnsEntryById(dnsEntryIdArg: string) {
|
||||
const dnsEntry = await this.getInstance({
|
||||
id: dnsEntryIdArg,
|
||||
});
|
||||
return dnsEntry;
|
||||
}
|
||||
|
||||
public static async getDnsEntries(filterArg?: { zone?: string }) {
|
||||
const filter: any = {};
|
||||
if (filterArg?.zone) {
|
||||
filter['data.zone'] = filterArg.zone;
|
||||
}
|
||||
const dnsEntries = await this.getInstances(filter);
|
||||
return dnsEntries;
|
||||
}
|
||||
|
||||
public static async getDnsZones() {
|
||||
const dnsEntries = await this.getInstances({});
|
||||
const zones = new Set<string>();
|
||||
for (const entry of dnsEntries) {
|
||||
if (entry.data.zone) {
|
||||
zones.add(entry.data.zone);
|
||||
}
|
||||
}
|
||||
return Array.from(zones).sort();
|
||||
}
|
||||
|
||||
public static async createDnsEntry(dnsEntryDataArg: plugins.servezoneInterfaces.data.IDnsEntry['data']) {
|
||||
const dnsEntry = new DnsEntry();
|
||||
dnsEntry.id = await DnsEntry.getNewId();
|
||||
dnsEntry.data = {
|
||||
...dnsEntryDataArg,
|
||||
ttl: dnsEntryDataArg.ttl || 3600, // Default TTL: 1 hour
|
||||
active: dnsEntryDataArg.active !== false, // Default to active
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
await dnsEntry.save();
|
||||
return dnsEntry;
|
||||
}
|
||||
|
||||
public static async updateDnsEntry(
|
||||
dnsEntryIdArg: string,
|
||||
dnsEntryDataArg: Partial<plugins.servezoneInterfaces.data.IDnsEntry['data']>
|
||||
) {
|
||||
const dnsEntry = await this.getInstance({
|
||||
id: dnsEntryIdArg,
|
||||
});
|
||||
if (!dnsEntry) {
|
||||
throw new Error(`DNS entry with id ${dnsEntryIdArg} not found`);
|
||||
}
|
||||
Object.assign(dnsEntry.data, dnsEntryDataArg, {
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
await dnsEntry.save();
|
||||
return dnsEntry;
|
||||
}
|
||||
|
||||
public static async deleteDnsEntry(dnsEntryIdArg: string) {
|
||||
const dnsEntry = await this.getInstance({
|
||||
id: dnsEntryIdArg,
|
||||
});
|
||||
if (!dnsEntry) {
|
||||
throw new Error(`DNS entry with id ${dnsEntryIdArg} not found`);
|
||||
}
|
||||
await dnsEntry.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
@plugins.smartdata.svDb()
|
||||
public id: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public data: plugins.servezoneInterfaces.data.IDnsEntry['data'];
|
||||
|
||||
/**
|
||||
* Validates the DNS entry data
|
||||
*/
|
||||
public validateData(): boolean {
|
||||
const { type, name, value, zone } = this.data;
|
||||
|
||||
// Basic validation
|
||||
if (!type || !name || !value || !zone) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Type-specific validation
|
||||
switch (type) {
|
||||
case 'A':
|
||||
// Validate IPv4 address
|
||||
return /^(\d{1,3}\.){3}\d{1,3}$/.test(value);
|
||||
case 'AAAA':
|
||||
// Validate IPv6 address (simplified)
|
||||
return /^([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}$/.test(value);
|
||||
case 'MX':
|
||||
// MX records must have priority
|
||||
return this.data.priority !== undefined && this.data.priority >= 0;
|
||||
case 'SRV':
|
||||
// SRV records must have priority, weight, and port
|
||||
return (
|
||||
this.data.priority !== undefined &&
|
||||
this.data.weight !== undefined &&
|
||||
this.data.port !== undefined
|
||||
);
|
||||
case 'CNAME':
|
||||
case 'NS':
|
||||
case 'PTR':
|
||||
// These should point to valid domain names
|
||||
return /^[a-zA-Z0-9.-]+$/.test(value);
|
||||
case 'TXT':
|
||||
case 'CAA':
|
||||
case 'SOA':
|
||||
// These can contain any text
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a formatted string representation of the DNS entry
|
||||
*/
|
||||
public toFormattedString(): string {
|
||||
const { type, name, value, ttl, priority } = this.data;
|
||||
let result = `${name} ${ttl} IN ${type}`;
|
||||
|
||||
if (priority !== undefined) {
|
||||
result += ` ${priority}`;
|
||||
}
|
||||
|
||||
if (type === 'SRV' && this.data.weight !== undefined && this.data.port !== undefined) {
|
||||
result += ` ${this.data.weight} ${this.data.port}`;
|
||||
}
|
||||
|
||||
result += ` ${value}`;
|
||||
return result;
|
||||
}
|
||||
}
|
152
ts/manager.dns/classes.dnsmanager.ts
Normal file
152
ts/manager.dns/classes.dnsmanager.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import type { Cloudly } from '../classes.cloudly.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
import { DnsEntry } from './classes.dnsentry.js';
|
||||
|
||||
export class DnsManager {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
public cloudlyRef: Cloudly;
|
||||
|
||||
get db() {
|
||||
return this.cloudlyRef.mongodbConnector.smartdataDb;
|
||||
}
|
||||
|
||||
public CDnsEntry = plugins.smartdata.setDefaultManagerForDoc(this, DnsEntry);
|
||||
|
||||
constructor(cloudlyRef: Cloudly) {
|
||||
this.cloudlyRef = cloudlyRef;
|
||||
|
||||
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
|
||||
|
||||
// Get all DNS entries
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsEntries>(
|
||||
'getDnsEntries',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const dnsEntries = await this.CDnsEntry.getDnsEntries(
|
||||
reqArg.zone ? { zone: reqArg.zone } : undefined
|
||||
);
|
||||
|
||||
return {
|
||||
dnsEntries: await Promise.all(
|
||||
dnsEntries.map((entry) => entry.createSavableObject())
|
||||
),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Get DNS entry by ID
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsEntryById>(
|
||||
'getDnsEntryById',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const dnsEntry = await this.CDnsEntry.getDnsEntryById(reqArg.dnsEntryId);
|
||||
if (!dnsEntry) {
|
||||
throw new Error(`DNS entry with id ${reqArg.dnsEntryId} not found`);
|
||||
}
|
||||
|
||||
return {
|
||||
dnsEntry: await dnsEntry.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Create DNS entry
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_CreateDnsEntry>(
|
||||
'createDnsEntry',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const dnsEntry = await this.CDnsEntry.createDnsEntry(reqArg.dnsEntryData);
|
||||
|
||||
return {
|
||||
dnsEntry: await dnsEntry.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Update DNS entry
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_UpdateDnsEntry>(
|
||||
'updateDnsEntry',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const dnsEntry = await this.CDnsEntry.updateDnsEntry(
|
||||
reqArg.dnsEntryId,
|
||||
reqArg.dnsEntryData
|
||||
);
|
||||
|
||||
return {
|
||||
dnsEntry: await dnsEntry.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Delete DNS entry
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_DeleteDnsEntry>(
|
||||
'deleteDnsEntry',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const success = await this.CDnsEntry.deleteDnsEntry(reqArg.dnsEntryId);
|
||||
|
||||
return {
|
||||
success,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Get DNS zones
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsZones>(
|
||||
'getDnsZones',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const zones = await this.CDnsEntry.getDnsZones();
|
||||
|
||||
return {
|
||||
zones,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the DNS manager
|
||||
*/
|
||||
public async init() {
|
||||
console.log('DNS Manager initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the DNS manager
|
||||
*/
|
||||
public async stop() {
|
||||
console.log('DNS Manager stopped');
|
||||
}
|
||||
}
|
203
ts/manager.domain/classes.domain.ts
Normal file
203
ts/manager.domain/classes.domain.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { DomainManager } from './classes.domainmanager.js';
|
||||
|
||||
export class Domain extends plugins.smartdata.SmartDataDbDoc<
|
||||
Domain,
|
||||
plugins.servezoneInterfaces.data.IDomain,
|
||||
DomainManager
|
||||
> {
|
||||
// STATIC
|
||||
public static async getDomainById(domainIdArg: string) {
|
||||
const domain = await this.getInstance({
|
||||
id: domainIdArg,
|
||||
});
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static async getDomainByName(domainNameArg: string) {
|
||||
const domain = await this.getInstance({
|
||||
'data.name': domainNameArg,
|
||||
});
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static async getDomains() {
|
||||
const domains = await this.getInstances({});
|
||||
return domains;
|
||||
}
|
||||
|
||||
public static async createDomain(domainDataArg: plugins.servezoneInterfaces.data.IDomain['data']) {
|
||||
const domain = new Domain();
|
||||
domain.id = await Domain.getNewId();
|
||||
domain.data = {
|
||||
...domainDataArg,
|
||||
status: domainDataArg.status || 'pending',
|
||||
verificationStatus: domainDataArg.verificationStatus || 'pending',
|
||||
nameservers: domainDataArg.nameservers || [],
|
||||
autoRenew: domainDataArg.autoRenew !== false,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
await domain.save();
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static async updateDomain(
|
||||
domainIdArg: string,
|
||||
domainDataArg: Partial<plugins.servezoneInterfaces.data.IDomain['data']>
|
||||
) {
|
||||
const domain = await this.getInstance({
|
||||
id: domainIdArg,
|
||||
});
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${domainIdArg} not found`);
|
||||
}
|
||||
Object.assign(domain.data, domainDataArg, {
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
await domain.save();
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static async deleteDomain(domainIdArg: string) {
|
||||
const domain = await this.getInstance({
|
||||
id: domainIdArg,
|
||||
});
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${domainIdArg} not found`);
|
||||
}
|
||||
|
||||
// Check if there are DNS entries for this domain
|
||||
const dnsManager = domain.manager.cloudlyRef.dnsManager;
|
||||
const dnsEntries = await dnsManager.CDnsEntry.getInstances({
|
||||
'data.zone': domain.data.name,
|
||||
});
|
||||
|
||||
if (dnsEntries.length > 0) {
|
||||
console.log(`Warning: Deleting domain ${domain.data.name} with ${dnsEntries.length} DNS entries`);
|
||||
// Optionally delete associated DNS entries
|
||||
for (const dnsEntry of dnsEntries) {
|
||||
await dnsEntry.delete();
|
||||
}
|
||||
}
|
||||
|
||||
await domain.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
@plugins.smartdata.svDb()
|
||||
public id: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public data: plugins.servezoneInterfaces.data.IDomain['data'];
|
||||
|
||||
/**
|
||||
* Verify domain ownership
|
||||
*/
|
||||
public async verifyDomain(methodArg?: 'dns' | 'http' | 'email' | 'manual') {
|
||||
const method = methodArg || this.data.verificationMethod || 'dns';
|
||||
|
||||
// Generate verification token if not exists
|
||||
if (!this.data.verificationToken) {
|
||||
this.data.verificationToken = plugins.smartunique.shortId();
|
||||
await this.save();
|
||||
}
|
||||
|
||||
let verificationResult = {
|
||||
success: false,
|
||||
message: '',
|
||||
details: {} as any,
|
||||
};
|
||||
|
||||
switch (method) {
|
||||
case 'dns':
|
||||
// Check for TXT record with verification token
|
||||
verificationResult = await this.verifyViaDns();
|
||||
break;
|
||||
case 'http':
|
||||
// Check for file at well-known URL
|
||||
verificationResult = await this.verifyViaHttp();
|
||||
break;
|
||||
case 'email':
|
||||
// Send verification email
|
||||
verificationResult = await this.verifyViaEmail();
|
||||
break;
|
||||
case 'manual':
|
||||
// Manual verification
|
||||
verificationResult.success = true;
|
||||
verificationResult.message = 'Manually verified';
|
||||
break;
|
||||
}
|
||||
|
||||
// Update verification status
|
||||
if (verificationResult.success) {
|
||||
this.data.verificationStatus = 'verified';
|
||||
this.data.lastVerificationAt = Date.now();
|
||||
this.data.verificationMethod = method;
|
||||
} else {
|
||||
this.data.verificationStatus = 'failed';
|
||||
this.data.lastVerificationAt = Date.now();
|
||||
}
|
||||
|
||||
await this.save();
|
||||
return verificationResult;
|
||||
}
|
||||
|
||||
private async verifyViaDns(): Promise<{ success: boolean; message: string; details: any }> {
|
||||
// TODO: Implement DNS verification
|
||||
// Look for TXT record _cloudly-verify.{domain} with value {verificationToken}
|
||||
return {
|
||||
success: false,
|
||||
message: 'DNS verification not yet implemented',
|
||||
details: {
|
||||
expectedRecord: `_cloudly-verify.${this.data.name}`,
|
||||
expectedValue: this.data.verificationToken,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private async verifyViaHttp(): Promise<{ success: boolean; message: string; details: any }> {
|
||||
// TODO: Implement HTTP verification
|
||||
// Check for file at http://{domain}/.well-known/cloudly-verify.txt
|
||||
return {
|
||||
success: false,
|
||||
message: 'HTTP verification not yet implemented',
|
||||
details: {
|
||||
expectedUrl: `http://${this.data.name}/.well-known/cloudly-verify.txt`,
|
||||
expectedContent: this.data.verificationToken,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private async verifyViaEmail(): Promise<{ success: boolean; message: string; details: any }> {
|
||||
// TODO: Implement email verification
|
||||
return {
|
||||
success: false,
|
||||
message: 'Email verification not yet implemented',
|
||||
details: {},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if domain is expiring soon
|
||||
*/
|
||||
public isExpiringSoon(daysThreshold: number = 30): boolean {
|
||||
if (!this.data.expiresAt) {
|
||||
return false;
|
||||
}
|
||||
const daysUntilExpiry = (this.data.expiresAt - Date.now()) / (1000 * 60 * 60 * 24);
|
||||
return daysUntilExpiry <= daysThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all DNS entries for this domain
|
||||
*/
|
||||
public async getDnsEntries() {
|
||||
const dnsManager = this.manager.cloudlyRef.dnsManager;
|
||||
const dnsEntries = await dnsManager.CDnsEntry.getInstances({
|
||||
'data.zone': this.data.name,
|
||||
});
|
||||
return dnsEntries;
|
||||
}
|
||||
}
|
188
ts/manager.domain/classes.domainmanager.ts
Normal file
188
ts/manager.domain/classes.domainmanager.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
import type { Cloudly } from '../classes.cloudly.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
import { Domain } from './classes.domain.js';
|
||||
|
||||
export class DomainManager {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
public cloudlyRef: Cloudly;
|
||||
|
||||
get db() {
|
||||
return this.cloudlyRef.mongodbConnector.smartdataDb;
|
||||
}
|
||||
|
||||
public CDomain = plugins.smartdata.setDefaultManagerForDoc(this, Domain);
|
||||
|
||||
constructor(cloudlyRef: Cloudly) {
|
||||
this.cloudlyRef = cloudlyRef;
|
||||
|
||||
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
|
||||
|
||||
// Get all domains
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_GetDomains>(
|
||||
'getDomains',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const domains = await this.CDomain.getDomains();
|
||||
|
||||
return {
|
||||
domains: await Promise.all(
|
||||
domains.map((domain) => domain.createSavableObject())
|
||||
),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Get domain by ID
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_GetDomainById>(
|
||||
'getDomainById',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const domain = await this.CDomain.getDomainById(reqArg.domainId);
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${reqArg.domainId} not found`);
|
||||
}
|
||||
|
||||
return {
|
||||
domain: await domain.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Create domain
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_CreateDomain>(
|
||||
'createDomain',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
// Check if domain already exists
|
||||
const existingDomain = await this.CDomain.getDomainByName(reqArg.domainData.name);
|
||||
if (existingDomain) {
|
||||
throw new Error(`Domain ${reqArg.domainData.name} already exists`);
|
||||
}
|
||||
|
||||
const domain = await this.CDomain.createDomain(reqArg.domainData);
|
||||
|
||||
return {
|
||||
domain: await domain.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Update domain
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_UpdateDomain>(
|
||||
'updateDomain',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const domain = await this.CDomain.updateDomain(
|
||||
reqArg.domainId,
|
||||
reqArg.domainData
|
||||
);
|
||||
|
||||
return {
|
||||
domain: await domain.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Delete domain
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_DeleteDomain>(
|
||||
'deleteDomain',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const success = await this.CDomain.deleteDomain(reqArg.domainId);
|
||||
|
||||
return {
|
||||
success,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Verify domain
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.domain.IRequest_Any_Cloudly_VerifyDomain>(
|
||||
'verifyDomain',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const domain = await this.CDomain.getDomainById(reqArg.domainId);
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${reqArg.domainId} not found`);
|
||||
}
|
||||
|
||||
const verificationResult = await domain.verifyDomain(reqArg.verificationMethod);
|
||||
|
||||
return {
|
||||
domain: await domain.createSavableObject(),
|
||||
verificationResult,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the domain manager
|
||||
*/
|
||||
public async init() {
|
||||
console.log('Domain Manager initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the domain manager
|
||||
*/
|
||||
public async stop() {
|
||||
console.log('Domain Manager stopped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all active domains
|
||||
*/
|
||||
public async getActiveDomains() {
|
||||
const domains = await this.CDomain.getInstances({
|
||||
'data.status': 'active',
|
||||
});
|
||||
return domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get domains that are expiring soon
|
||||
*/
|
||||
public async getExpiringDomains(daysThreshold: number = 30) {
|
||||
const domains = await this.CDomain.getDomains();
|
||||
return domains.filter(domain => domain.isExpiringSoon(daysThreshold));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a domain name is available (not in our system)
|
||||
*/
|
||||
public async isDomainAvailable(domainName: string): Promise<boolean> {
|
||||
const existingDomain = await this.CDomain.getDomainByName(domainName);
|
||||
return !existingDomain;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user