317 lines
11 KiB
TypeScript
317 lines
11 KiB
TypeScript
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<string, string[]>, permissionDeps?: Record<string, string[]> }
|
|
*/
|
|
async setDependencyConfig(req: Request, res: Response): Promise<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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();
|