- 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.
203 lines
5.8 KiB
TypeScript
203 lines
5.8 KiB
TypeScript
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;
|
|
}
|
|
} |