import * as plugins from '../plugins.js'; import { DomainManager } from './classes.domainmanager.js'; @plugins.smartdata.managed() 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 ) { 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; } }