import { Request, Response } from 'express'; import { permissionService } from '../services/permission.service'; import pool from '../config/database'; import logger from '../utils/logger'; class PermissionController { /** * GET /api/permissions/me * Returns the current user's effective permissions. */ async getMyPermissions(req: Request, res: Response): Promise { try { const groups: string[] = req.user?.groups ?? []; const isAdmin = groups.includes('dashboard_admin'); let permissions: string[]; if (isAdmin) { // Admin gets all permissions const matrix = await permissionService.getMatrix(); permissions = matrix.permissions.map(p => p.id); } else { permissions = permissionService.getEffectivePermissions(groups); } const maintenance = permissionService.getMaintenanceFlags(); logger.debug('GET /api/permissions/me', { email: req.user?.email, groups, isAdmin, permissionsCount: permissions.length, maintenanceWissen: maintenance['wissen'] ?? false, maintenanceAusruestungsanfrage: maintenance['ausruestungsanfrage'] ?? false, }); res.json({ success: true, data: { permissions, maintenance, isAdmin, }, }); } catch (error) { logger.error('Failed to get user permissions', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Berechtigungen' }); } } /** * GET /api/admin/permissions/matrix * Returns the full permission matrix for the admin UI. */ async getMatrix(_req: Request, res: Response): Promise { try { const matrix = await permissionService.getMatrix(); res.json({ success: true, data: matrix }); } catch (error) { logger.error('Failed to get permission matrix', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Berechtigungsmatrix' }); } } /** * PUT /api/admin/permissions/group/:groupName * Sets all permissions for a given Authentik group. */ async setGroupPermissions(req: Request, res: Response): Promise { try { const groupName = req.params.groupName as string; const { permissions } = req.body; if (!Array.isArray(permissions)) { res.status(400).json({ success: false, message: 'permissions must be an array' }); return; } await permissionService.setGroupPermissions( groupName, permissions, req.user!.id ); res.json({ success: true, message: 'Berechtigungen aktualisiert' }); } catch (error) { logger.error('Failed to set group permissions', { error }); res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' }); } } /** * DELETE /api/admin/permissions/group/:groupName * Removes a group and all its permissions from the matrix. */ async deleteGroup(req: Request, res: Response): Promise { try { const groupName = req.params.groupName as string; await permissionService.deleteGroup(groupName); res.json({ success: true, message: 'Gruppe entfernt' }); } catch (error) { logger.error('Failed to delete group', { error }); res.status(500).json({ success: false, message: 'Fehler beim Entfernen der Gruppe' }); } } /** * PUT /api/admin/permissions/bulk * Bulk-update permissions for multiple groups in one request. * Body: { updates: [{ group: string, permissions: string[] }] } */ async setBulkPermissions(req: Request, res: Response): Promise { try { const { updates } = req.body; if (!Array.isArray(updates)) { res.status(400).json({ success: false, message: 'updates must be an array' }); return; } for (const u of updates) { if (typeof u.group !== 'string' || !Array.isArray(u.permissions)) { res.status(400).json({ success: false, message: 'Each update must have group (string) and permissions (array)' }); return; } } const result = await permissionService.setMultipleGroupPermissions(updates, req.user!.id); if (result.droppedPermissions.length > 0) { res.json({ success: true, message: `Berechtigungen aktualisiert. Warnung: ${result.droppedPermissions.length} Berechtigung(en) existieren nicht in der Datenbank und wurden ignoriert: ${result.droppedPermissions.join(', ')}`, droppedPermissions: result.droppedPermissions, }); } else { res.json({ success: true, message: 'Berechtigungen aktualisiert' }); } } catch (error) { logger.error('Failed to set bulk permissions', { error }); res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' }); } } /** * GET /api/admin/permissions/groups * Returns all known Authentik groups from the permission table. */ async getGroups(_req: Request, res: Response): Promise { try { const groups = await permissionService.getKnownGroups(); res.json({ success: true, data: groups }); } catch (error) { logger.error('Failed to get groups', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Gruppen' }); } } /** * GET /api/admin/permissions/unknown-groups * Returns Authentik groups found in users table but not in the permission matrix. */ async getUnknownGroups(_req: Request, res: Response): Promise { try { const groups = await permissionService.getUnknownGroups(); res.json({ success: true, data: groups }); } catch (error) { logger.error('Failed to get unknown groups', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der unbekannten Gruppen' }); } } /** * PUT /api/admin/permissions/maintenance/:featureGroupId * Toggles maintenance mode for a feature group. */ async setMaintenanceFlag(req: Request, res: Response): Promise { try { const featureGroupId = req.params.featureGroupId as string; const { active } = req.body; if (typeof active !== 'boolean') { res.status(400).json({ success: false, message: 'active must be a boolean' }); return; } await permissionService.setMaintenanceFlag(featureGroupId, active); res.json({ success: true, message: 'Wartungsmodus aktualisiert' }); } catch (error) { logger.error('Failed to set maintenance flag', { error }); res.status(500).json({ success: false, message: 'Fehler beim Setzen des Wartungsmodus' }); } } /** * GET /api/admin/permissions/config * Returns the dependency configuration (group hierarchy + permission deps). */ async getDependencyConfig(_req: Request, res: Response): Promise { try { const config = await permissionService.getDependencyConfig(); res.json({ success: true, data: config }); } catch (error) { logger.error('Failed to get dependency config', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Konfiguration' }); } } /** * PUT /api/admin/permissions/config * Updates the dependency configuration. * Body: { groupHierarchy?: Record, permissionDeps?: Record } */ async setDependencyConfig(req: Request, res: Response): Promise { try { const { groupHierarchy, permissionDeps } = req.body; if (groupHierarchy !== undefined) { if (typeof groupHierarchy !== 'object' || groupHierarchy === null) { res.status(400).json({ success: false, message: 'groupHierarchy must be an object' }); return; } await permissionService.setGroupHierarchy(groupHierarchy, req.user!.id); } if (permissionDeps !== undefined) { if (typeof permissionDeps !== 'object' || permissionDeps === null) { res.status(400).json({ success: false, message: 'permissionDeps must be an object' }); return; } await permissionService.setPermissionDeps(permissionDeps, req.user!.id); } res.json({ success: true, message: 'Konfiguration aktualisiert' }); } catch (error) { logger.error('Failed to set dependency config', { error }); res.status(500).json({ success: false, message: 'Fehler beim Speichern der Konfiguration' }); } } /** * GET /api/permissions/users-with?permission=bestellungen:create * Returns users who have a specific permission. */ async getUsersWithPermission(req: Request, res: Response): Promise { try { const permission = req.query.permission as string; if (!permission) { res.status(400).json({ success: false, message: 'permission query parameter required' }); return; } const users = await permissionService.getUsersWithPermission(permission); res.json({ success: true, data: users }); } catch (error) { logger.error('Failed to get users with permission', { error }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Benutzer' }); } } /** * GET /api/permissions/debug/:userId * Returns debug info for a specific user: their groups, resolved permissions, * and maintenance flags. Admin only. */ async debugUser(req: Request, res: Response): Promise { try { const userId = req.params.userId as string; // Fetch user's Authentik groups from DB const userResult = await pool.query( 'SELECT authentik_groups, email, name FROM users WHERE id = $1', [userId] ); if (userResult.rows.length === 0) { res.status(404).json({ success: false, message: 'Benutzer nicht gefunden' }); return; } const user = userResult.rows[0]; const groups: string[] = user.authentik_groups ?? []; const isAdmin = groups.includes('dashboard_admin'); // Resolve permissions for those groups let permissions: string[]; if (isAdmin) { const matrix = await permissionService.getMatrix(); permissions = matrix.permissions.map(p => p.id); } else { permissions = permissionService.getEffectivePermissions(groups); } // Maintenance flags const maintenance = permissionService.getMaintenanceFlags(); const maintenanceActive = Object.entries(maintenance) .filter(([, active]) => active) .map(([featureGroup]) => featureGroup); res.json({ success: true, data: { userId, email: user.email, name: user.name, authentikGroups: groups, isAdmin, permissions, maintenance, maintenanceActiveFeatureGroups: maintenanceActive, }, }); } catch (error) { logger.error('Failed to debug user permissions', { error, userId: req.params.userId }); res.status(500).json({ success: false, message: 'Fehler beim Laden der Debug-Informationen' }); } } } export default new PermissionController();