import { assert, assertEquals } from '@std/assert'; import { ExternalGatewayManager } from '../ts/classes/external-gateway.ts'; import type { IDomain, IService, ISslCertificate } from '../ts/types.ts'; class FakeDatabase { public settings = new Map(); public secretSettings = new Map(); public domains: IDomain[] = []; public certificates = new Map(); private nextDomainId = 1; getSetting(key: string): string | null { return this.settings.get(key) ?? null; } setSetting(key: string, value: string): void { this.settings.set(key, value); } async getSecretSetting(key: string): Promise { return this.secretSettings.get(key) ?? null; } getDomainByName(domain: string): IDomain | null { return this.domains.find((entry) => entry.domain === domain) ?? null; } createDomain(domain: Omit): IDomain { const createdDomain = { ...domain, id: this.nextDomainId++ }; this.domains.push(createdDomain); return createdDomain; } updateDomain(id: number, updates: Partial): void { const index = this.domains.findIndex((entry) => entry.id === id); if (index === -1) return; this.domains[index] = { ...this.domains[index], ...updates }; } getDomainsByProvider(provider: NonNullable): IDomain[] { return this.domains.filter((entry) => entry.dnsProvider === provider); } getSSLCertificate(domain: string): ISslCertificate | null { return this.certificates.get(domain) ?? null; } updateSSLCertificate(domain: string, updates: Partial): void { const existing = this.certificates.get(domain); if (!existing) return; this.certificates.set(domain, { ...existing, ...updates }); } async createSSLCertificate(cert: Omit): Promise { const storedCert = { ...cert, id: this.certificates.size + 1 }; this.certificates.set(cert.domain, storedCert); return storedCert; } } const makeOneboxRef = () => { const database = new FakeDatabase(); database.settings.set('dcrouterGatewayUrl', 'https://edge.example.com'); database.settings.set('dcrouterWorkHosterId', 'onebox-1'); database.secretSettings.set('dcrouterGatewayApiToken', 'dcr-token'); let reloadCount = 0; return { database, reverseProxy: { reloadCertificates: async () => { reloadCount++; }, get reloadCount() { return reloadCount; }, }, }; }; Deno.test('ExternalGatewayManager syncs dcrouter domains into Onebox domains', async () => { const oneboxRef = makeOneboxRef(); oneboxRef.database.domains.push({ id: 99, domain: 'old.example.com', dnsProvider: 'dcrouter', isObsolete: false, defaultWildcard: true, createdAt: 1, updatedAt: 1, }); const manager = new ExternalGatewayManager(oneboxRef as any); (manager as any).fireDcRouterRequest = async (method: string) => { assertEquals(method, 'getWorkHosterDomains'); return { domains: [ { name: 'example.com', capabilities: { canCreateSubdomains: true, canManageDnsRecords: true, canIssueCertificates: true, canHostEmail: true, }, }, ], }; }; const domains = await manager.syncDomains(); assertEquals(domains.length, 2); assertEquals(oneboxRef.database.getDomainByName('example.com')?.dnsProvider, 'dcrouter'); assertEquals(oneboxRef.database.getDomainByName('example.com')?.defaultWildcard, true); assertEquals(oneboxRef.database.getDomainByName('old.example.com')?.isObsolete, true); }); Deno.test('ExternalGatewayManager syncs service routes to dcrouter WorkHoster API', async () => { const oneboxRef = makeOneboxRef(); oneboxRef.database.settings.set('serverIP', '203.0.113.10'); oneboxRef.database.settings.set('httpPort', '8080'); const service: IService = { id: 1, name: 'hello', image: 'nginx:latest', envVars: {}, port: 3000, domain: 'hello.example.com', status: 'running', createdAt: 1, updatedAt: 1, }; const requests: Array<{ method: string; requestData: Record }> = []; const manager = new ExternalGatewayManager(oneboxRef as any); (manager as any).fireDcRouterRequest = async (method: string, requestData: Record) => { requests.push({ method, requestData }); if (method === 'exportCertificate') { return { success: false }; } return { success: true, action: 'created', routeId: 'route-1' }; }; await manager.syncServiceRoute(service); const syncRequest = requests.find((request) => request.method === 'syncWorkAppRoute')!; const route = syncRequest.requestData.route as any; const ownership = syncRequest.requestData.ownership as any; assertEquals(ownership, { workHosterType: 'onebox', workHosterId: 'onebox-1', workAppId: 'hello', hostname: 'hello.example.com', }); assertEquals(route.match, { ports: [443], domains: ['hello.example.com'] }); assertEquals(route.action.targets, [{ host: '203.0.113.10', port: 8080 }]); assertEquals(route.action.tls, { mode: 'terminate', certificate: 'auto' }); assertEquals(syncRequest.requestData.enabled, true); }); Deno.test('ExternalGatewayManager deletes service routes through dcrouter WorkHoster API', async () => { const oneboxRef = makeOneboxRef(); const manager = new ExternalGatewayManager(oneboxRef as any); let deleteRequest: Record | null = null; (manager as any).fireDcRouterRequest = async (method: string, requestData: Record) => { assertEquals(method, 'syncWorkAppRoute'); deleteRequest = requestData; return { success: true, action: 'deleted', routeId: 'route-1' }; }; await manager.deleteServiceRoute({ id: 1, name: 'hello', domain: 'hello.example.com', }); assert(deleteRequest); const capturedDeleteRequest = deleteRequest as Record; assertEquals(capturedDeleteRequest.delete, true); assertEquals((capturedDeleteRequest.ownership as any).hostname, 'hello.example.com'); }); Deno.test('ExternalGatewayManager imports exported dcrouter certificates into Onebox', async () => { const oneboxRef = makeOneboxRef(); const manager = new ExternalGatewayManager(oneboxRef as any); (manager as any).fireDcRouterRequest = async (method: string, requestData: Record) => { assertEquals(method, 'exportCertificate'); assertEquals(requestData.domain, 'hello.example.com'); return { success: true, cert: { id: 'cert-1', domainName: 'hello.example.com', created: 1, validUntil: 2, privateKey: '-----BEGIN PRIVATE KEY-----\nfake\n-----END PRIVATE KEY-----', publicKey: '-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----', csr: '', }, }; }; const imported = await manager.importCertificateForDomain('hello.example.com'); assert(imported); assertEquals(oneboxRef.database.getSSLCertificate('hello.example.com')?.issuer, 'dcrouter'); assertEquals(oneboxRef.reverseProxy.reloadCount, 1); });