import * as plugins from '../../plugins.js'; import type { OpsServer } from '../classes.opsserver.js'; import * as interfaces from '../../../ts_interfaces/index.js'; import { requireOpsAuth } from '../helpers/auth.js'; export class RouteManagementHandler { public typedrouter = new plugins.typedrequest.TypedRouter(); constructor(private opsServerRef: OpsServer) { this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter); this.registerHandlers(); } /** * Validate auth: JWT identity OR API token with required scope. * Returns a userId string on success, throws on failure. */ private async requireAuth( request: { identity?: interfaces.data.IIdentity; apiToken?: string }, requiredScope?: interfaces.data.TApiTokenScope, ): Promise { const auth = await requireOpsAuth(this.opsServerRef, request, { scope: requiredScope, requireAdminIdentity: requiredScope?.endsWith(':write'), }); return auth.userId; } private registerHandlers(): void { // Get merged routes this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getMergedRoutes', async (dataArg) => { await this.requireAuth(dataArg, 'routes:read'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { routes: [], warnings: [] }; } return manager.getMergedRoutes(); }, ), ); // Get generated HTTP redirects this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getHttpRedirects', async (dataArg) => { await this.requireAuth(dataArg, 'routes:read'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { redirects: [] }; } return { redirects: manager.getHttpRedirects() }; }, ), ); // Create route this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'createRoute', async (dataArg) => { const userId = await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } const id = await manager.createRoute(dataArg.route, userId, dataArg.enabled ?? true, dataArg.metadata); this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [id], reason: 'route-created', }); return { success: true, routeId: id }; }, ), ); // Update route this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updateRoute', async (dataArg) => { await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } const result = await manager.updateRoute(dataArg.id, { route: dataArg.route as any, enabled: dataArg.enabled, metadata: dataArg.metadata, }); if (result.success) { this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [dataArg.id], reason: 'route-updated', }); } return result; }, ), ); // Delete route this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'deleteRoute', async (dataArg) => { await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } const result = await manager.deleteRoute(dataArg.id); if (result.success) { this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [dataArg.id], reason: 'route-deleted', }); } return result; }, ), ); // Toggle route this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'toggleRoute', async (dataArg) => { await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } const result = await manager.toggleRoute(dataArg.id, dataArg.enabled); if (result.success) { this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [dataArg.id], reason: 'route-toggled', }); } return result; }, ), ); this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'createLetsEncryptHttp01Forward', async (dataArg) => { const userId = await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } try { const routeId = await manager.createLetsEncryptHttp01Forward( dataArg.config, userId, dataArg.enabled ?? true, ); this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [routeId], reason: 'lets-encrypt-forward-created', }); return { success: true, routeId }; } catch (error) { return { success: false, message: (error as Error).message }; } }, ), ); this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updateLetsEncryptHttp01Forward', async (dataArg) => { await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } try { const result = await manager.updateLetsEncryptHttp01Forward( dataArg.id, dataArg.config, dataArg.enabled, ); if (result.success) { this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [dataArg.id], reason: 'lets-encrypt-forward-updated', }); } return result; } catch (error) { return { success: false, message: (error as Error).message }; } }, ), ); this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'deleteLetsEncryptHttp01Forward', async (dataArg) => { await this.requireAuth(dataArg, 'routes:write'); const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!manager) { return { success: false, message: 'Route management not initialized' }; } const result = await manager.deleteLetsEncryptHttp01Forward(dataArg.id); if (result.success) { this.opsServerRef.invalidateRealtime?.('routes', { changedIds: [dataArg.id], reason: 'lets-encrypt-forward-deleted', }); } return result; }, ), ); } }