Files
cloudly/ts/manager.domain/classes.domain.ts

204 lines
5.8 KiB
TypeScript
Raw Normal View History

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<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;
}
}