import * as plugins from '../../plugins.js'; import type { OpsServer } from '../classes.opsserver.js'; import * as interfaces from '../../../ts_interfaces/index.js'; export class SecurityProfileHandler { public typedrouter = new plugins.typedrequest.TypedRouter(); constructor(private opsServerRef: OpsServer) { this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter); this.registerHandlers(); } private async requireAuth( request: { identity?: interfaces.data.IIdentity; apiToken?: string }, requiredScope?: interfaces.data.TApiTokenScope, ): Promise { if (request.identity?.jwt) { try { const isAdmin = await this.opsServerRef.adminHandler.adminIdentityGuard.exec({ identity: request.identity, }); if (isAdmin) return request.identity.userId; } catch { /* fall through */ } } if (request.apiToken) { const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager; if (tokenManager) { const token = await tokenManager.validateToken(request.apiToken); if (token) { if (!requiredScope || tokenManager.hasScope(token, requiredScope)) { return token.createdBy; } throw new plugins.typedrequest.TypedResponseError('insufficient scope'); } } } throw new plugins.typedrequest.TypedResponseError('unauthorized'); } private registerHandlers(): void { // Get all security profiles this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getSecurityProfiles', async (dataArg) => { await this.requireAuth(dataArg, 'profiles:read'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; if (!resolver) { return { profiles: [] }; } return { profiles: resolver.listProfiles() }; }, ), ); // Get a single security profile this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getSecurityProfile', async (dataArg) => { await this.requireAuth(dataArg, 'profiles:read'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; if (!resolver) { return { profile: null }; } return { profile: resolver.getProfile(dataArg.id) || null }; }, ), ); // Create a security profile this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'createSecurityProfile', async (dataArg) => { const userId = await this.requireAuth(dataArg, 'profiles:write'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; if (!resolver) { return { success: false, message: 'Reference resolver not initialized' }; } const id = await resolver.createProfile({ name: dataArg.name, description: dataArg.description, security: dataArg.security, extendsProfiles: dataArg.extendsProfiles, createdBy: userId, }); return { success: true, id }; }, ), ); // Update a security profile this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updateSecurityProfile', async (dataArg) => { await this.requireAuth(dataArg, 'profiles:write'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!resolver || !manager) { return { success: false, message: 'Not initialized' }; } const { affectedRouteIds } = await resolver.updateProfile(dataArg.id, { name: dataArg.name, description: dataArg.description, security: dataArg.security, extendsProfiles: dataArg.extendsProfiles, }); // Propagate to affected routes if (affectedRouteIds.length > 0) { await manager.reResolveRoutes(affectedRouteIds); } return { success: true, affectedRouteCount: affectedRouteIds.length }; }, ), ); // Delete a security profile this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'deleteSecurityProfile', async (dataArg) => { await this.requireAuth(dataArg, 'profiles:write'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!resolver || !manager) { return { success: false, message: 'Not initialized' }; } const result = await resolver.deleteProfile( dataArg.id, dataArg.force ?? false, manager.getStoredRoutes(), ); // If force-deleted with affected routes, re-apply if (result.success && dataArg.force) { await manager.applyRoutes(); } return result; }, ), ); // Get routes using a security profile this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getSecurityProfileUsage', async (dataArg) => { await this.requireAuth(dataArg, 'profiles:read'); const resolver = this.opsServerRef.dcRouterRef.referenceResolver; const manager = this.opsServerRef.dcRouterRef.routeConfigManager; if (!resolver || !manager) { return { routes: [] }; } const usage = resolver.getProfileUsageForId(dataArg.id, manager.getStoredRoutes()); return { routes: usage.map((u) => ({ id: u.id, name: u.routeName })) }; }, ), ); } }