import * as plugins from '../../plugins.ts'; import type { OpsServer } from '../classes.opsserver.ts'; import * as interfaces from '../../../ts_interfaces/index.ts'; import { requireValidIdentity } from '../helpers/guards.ts'; export class DomainsHandler { public typedrouter = new plugins.typedrequest.TypedRouter(); constructor(private opsServerRef: OpsServer) { this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter); this.registerHandlers(); } private buildDomainViews(): interfaces.data.IDomainDetail[] { const domains = this.opsServerRef.oneboxRef.database.getAllDomains(); const allServices = this.opsServerRef.oneboxRef.database.getAllServices(); return domains.map((domain: any) => { const certificates = this.opsServerRef.oneboxRef.database.getCertificatesByDomain(domain.id!); const requirements = this.opsServerRef.oneboxRef.database.getCertRequirementsByDomain(domain.id!); const serviceCount = allServices.filter((service: any) => { if (!service.domain) return false; const baseDomain = service.domain.split('.').slice(-2).join('.'); return baseDomain === domain.domain; }).length; let certificateStatus: 'valid' | 'expiring-soon' | 'expired' | 'pending' | 'none' = 'none'; let daysRemaining: number | null = null; const validCerts = certificates.filter((cert: any) => cert.isValid && cert.expiryDate > Date.now()); if (validCerts.length > 0) { const latestCert = validCerts.reduce((latest: any, cert: any) => cert.expiryDate > latest.expiryDate ? cert : latest ); daysRemaining = Math.floor((latestCert.expiryDate - Date.now()) / (24 * 60 * 60 * 1000)); certificateStatus = daysRemaining <= 30 ? 'expiring-soon' : 'valid'; } else if (certificates.some((cert: any) => !cert.isValid)) { certificateStatus = 'expired'; } else if (requirements.some((req: any) => req.status === 'pending')) { certificateStatus = 'pending'; } return { domain, certificates, requirements, serviceCount, certificateStatus, daysRemaining, }; }); } private registerHandlers(): void { this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getDomains', async (dataArg) => { await requireValidIdentity(this.opsServerRef.adminHandler, dataArg); const domains = this.buildDomainViews(); return { domains }; }, ), ); this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getDomain', async (dataArg) => { await requireValidIdentity(this.opsServerRef.adminHandler, dataArg); const domain = this.opsServerRef.oneboxRef.database.getDomainByName(dataArg.domainName); if (!domain) { throw new plugins.typedrequest.TypedResponseError('Domain not found'); } const views = this.buildDomainViews(); const domainView = views.find((v) => v.domain.domain === dataArg.domainName); if (!domainView) { throw new plugins.typedrequest.TypedResponseError('Domain not found'); } return { domain: domainView }; }, ), ); this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'syncDomains', async (dataArg) => { await requireValidIdentity(this.opsServerRef.adminHandler, dataArg); if (!this.opsServerRef.oneboxRef.cloudflareDomainSync) { throw new plugins.typedrequest.TypedResponseError('Cloudflare domain sync not configured'); } await this.opsServerRef.oneboxRef.cloudflareDomainSync.syncZones(); const domains = this.buildDomainViews(); return { domains }; }, ), ); } }