Files
deskhub/DeskHub-Webseite/tests/permissions.php
T
2026-11-05 21:21:59 +00:00

129 lines
9.9 KiB
PHP

<?php
declare(strict_types=1);
/**
* Prüft den Rechte-Katalog (includes/permissions.php) und has_permission(): vollständig und eindeutig, Standardwerte, Rückfall für Rechte, die in älteren
* Rollen fehlen, Rolle pro Abteilung, deaktivierte Rollen und die Rollen-Vorlagen.
*/
putenv('DESKHUB_TESTING=1');
putenv('DESKHUB_SQLITE_PATH=:memory:');
require_once dirname(__DIR__) . '/includes/bootstrap.php';
$failures = [];
$total = 0;
$check = function (bool $ok, string $what) use (&$failures, &$total): void {
$total++;
if (!$ok) $failures[] = $what;
};
// ── Katalog ────────────────────────────────────────────────────────────────────
$catalog = permission_catalog();
$all = [];
$dupes = [];
foreach ($catalog as $g) {
$check(!empty($g['title']) && !empty($g['items']), 'Gruppe hat Titel und Rechte');
foreach ($g['items'] as $k => $i) {
if (isset($all[$k])) $dupes[] = $k;
$all[$k] = $i;
$check(preg_match('/^[a-z_]+$/', $k) === 1 && $i['label'] !== '' && $i['hint'] !== '' && is_bool($i['agent']) && is_bool($i['area']), "Recht {$k}: Schlüssel, Beschriftung, Hinweis und Flags");
}
}
$check($dupes === [], 'Kein Recht kommt doppelt vor: ' . implode(',', $dupes));
$check(array_keys(permission_labels()) === array_keys($all), 'permission_labels() entspricht dem Katalog');
// Alle bisherigen Rechte gibt es weiterhin (gespeicherte Rollen bleiben gültig)
$old = ['reply_ticket', 'close_ticket', 'delete_ticket', 'transfer_ticket', 'post_note', 'assign_ticket', 'manage_canned', 'view_reports', 'manage_kb', 'create_ticket',
'manage_departments', 'manage_priorities', 'manage_help_topics', 'manage_email_addresses', 'manage_email_templates', 'manage_organizations', 'manage_teams', 'manage_roles',
'manage_staff', 'view_audit_log', 'manage_escalations', 'view_time_entries', 'manage_business_hours', 'manage_assistant'];
$check(array_diff($old, array_keys($all)) === [], 'Alle bisherigen Rechte sind im Katalog');
$check(count($all) >= 40, 'Der Katalog hat die neuen Rechte (' . count($all) . ')');
// Neue Rechte, die es bisher gar nicht gab
foreach (['merge_split_ticket', 'link_tickets', 'manage_banlist', 'export_tickets', 'fetch_mail', 'share_views', 'schedule_reports', 'view_customers', 'manage_customers', 'manage_custom_fields',
'manage_ticket_templates', 'manage_automation', 'manage_site_pages', 'manage_languages', 'manage_status_page', 'view_mail_queue', 'view_login_guard', 'manage_problems', 'manage_availability', 'view_help'] as $k) {
$check(isset($all[$k]), "Neues Recht {$k} vorhanden");
}
// Adminportal-Bereiche
$areas = admin_section_permissions();
$check(isset($areas['manage_canned'], $areas['manage_kb'], $areas['view_help'], $areas['view_login_guard']) && !isset($areas['reply_ticket'], $areas['manage_banlist'], $areas['export_tickets']), 'admin_section_permissions(): Bereiche ja, Ticket-Rechte nein');
foreach (['settings', 'backup', 'update', 'plugins', 'api_keys', 'webhooks', 'import', 'security_check', 'passkeys'] as $needle) {
$hit = array_filter(array_keys($all), fn($k) => str_contains($k, $needle));
$check($hit === [], "Nicht delegierbar: kein Recht für {$needle}");
}
// ── Standardwerte ──────────────────────────────────────────────────────────────
$adm = default_permissions('admin');
$agt = default_permissions('agent');
$check(count(array_filter($adm)) === count($all), 'Administrator: alle Rechte');
foreach (['reply_ticket', 'close_ticket', 'transfer_ticket', 'post_note', 'assign_ticket', 'create_ticket', 'view_reports', 'merge_split_ticket', 'link_tickets', 'manage_banlist', 'fetch_mail', 'share_views', 'schedule_reports', 'view_customers'] as $k) {
$check($agt[$k] === true, "Standard-Mitarbeiter darf weiterhin: {$k}");
}
foreach (['delete_ticket', 'export_tickets'] as $k) $check($agt[$k] === false, "Standard-Mitarbeiter darf nicht: {$k}");
foreach ($areas as $k => $_l) $check($agt[$k] === false, "Adminportal-Bereich standardmäßig aus: {$k}");
// ── has_permission ─────────────────────────────────────────────────────────────
$pdo = get_db();
$now = date('Y-m-d H:i:s');
$dept = (int) $pdo->query('SELECT id FROM departments ORDER BY id LIMIT 1')->fetchColumn();
$pdo->prepare('INSERT INTO departments (name, email, is_active, created_at) VALUES (?,?,1,?)')->execute(['Zweite', 'zweite@test.de', $now]);
$dept2 = (int) $pdo->lastInsertId();
$pdo->exec('DELETE FROM staff');
$mkRole = function (string $name, array $perms, int $active = 1) use ($pdo, $now): int {
$pdo->prepare('INSERT INTO roles (name, permissions, is_active, created_at, updated_at) VALUES (?,?,?,?,?)')->execute([$name, json_encode($perms), $active, $now, $now]);
return (int) $pdo->lastInsertId();
};
$mkStaff = function (string $mail, string $role, ?int $roleId) use ($pdo, $dept, $now): array {
$pdo->prepare('INSERT INTO staff (name, email, password_hash, role, role_id, department_id, is_active, created_at) VALUES (?,?,?,?,?,?,1,?)')->execute([$mail, $mail . '@test.de', 'x', $role, $roleId, $dept, $now]);
return $pdo->query('SELECT * FROM staff WHERE id = ' . (int) $pdo->lastInsertId())->fetch();
};
$admin = $mkStaff('chef', 'admin', null);
$plain = $mkStaff('eva', 'agent', null);
$check(has_permission($admin, 'manage_staff') && has_permission($admin, 'gibt_es_nicht'), 'Administrator hat immer alles');
$check(has_permission($plain, 'reply_ticket') && has_permission($plain, 'merge_split_ticket') && !has_permission($plain, 'delete_ticket') && !has_permission($plain, 'manage_custom_fields'), 'Mitarbeiter ohne Rolle: Standardrechte');
$check(!has_permission($plain, 'gibt_es_nicht'), 'Unbekanntes Recht: nein');
// Alte Rolle (gespeichert vor den neuen Rechten): neue Rechte gelten mit dem Standardwert
$oldJson = array_fill_keys($old, false);
$oldJson['reply_ticket'] = true;
$oldJson['manage_departments'] = true;
$roleOld = $mkRole('Alt', $oldJson);
$s1 = $mkStaff('alt', 'agent', $roleOld);
$check(has_permission($s1, 'reply_ticket') && has_permission($s1, 'manage_departments') && !has_permission($s1, 'close_ticket'), 'Alte Rolle: gespeicherte Werte gelten (auch „aus“)');
$check(has_permission($s1, 'merge_split_ticket') && has_permission($s1, 'manage_banlist') && has_permission($s1, 'fetch_mail'), 'Alte Rolle: bisher offene Funktionen bleiben erlaubt (Standardwert)');
$check(!has_permission($s1, 'manage_custom_fields') && !has_permission($s1, 'view_help') && !has_permission($s1, 'export_tickets'), 'Alte Rolle: neue Adminbereiche bleiben aus');
// Altes Recht fehlt in einer gespeicherten Rolle: wie bisher „nein“
$roleGap = $mkRole('Lücke', ['reply_ticket' => true]);
$sg = $mkStaff('luecke', 'agent', $roleGap);
$check(has_permission($sg, 'reply_ticket') && !has_permission($sg, 'post_note') && !has_permission($sg, 'close_ticket'), 'Fehlendes altes Recht in einer Rolle: nein (wie bisher)');
$check(array_diff(permission_legacy_keys(), array_keys($all)) === [] && count(permission_legacy_keys()) === 24, 'Liste der alten Rechte ist vollständig');
$eff = permission_effective(['reply_ticket' => true]);
$check($eff['reply_ticket'] && !$eff['post_note'] && $eff['merge_split_ticket'] && !$eff['manage_custom_fields'] && count($eff) === count($all), 'permission_effective(): wie has_permission() für fehlende Rechte');
// Neue Rolle mit ausdrücklich „aus“
$roleNew = $mkRole('Neu', ['merge_split_ticket' => false, 'manage_custom_fields' => true]);
$s2 = $mkStaff('neu', 'agent', $roleNew);
$check(!has_permission($s2, 'merge_split_ticket') && has_permission($s2, 'manage_custom_fields'), 'Ausdrücklich gesetzte Werte schlagen den Standard');
// Deaktivierte Rolle
$roleOff = $mkRole('Aus', ['reply_ticket' => false, 'manage_custom_fields' => true], 0);
$s3 = $mkStaff('aus', 'agent', $roleOff);
$check(has_permission($s3, 'reply_ticket') && !has_permission($s3, 'manage_custom_fields'), 'Deaktivierte Rolle: Standardrechte');
// Rolle pro Abteilung
$pdo->prepare('INSERT INTO staff_department (staff_id, department_id, notify, role_id) VALUES (?,?,?,?)')->execute([$s1['id'], $dept2, 1, $roleNew]);
$check(has_permission($s1, 'manage_custom_fields', $dept2) && !has_permission($s1, 'manage_custom_fields', $dept), 'Rolle pro Abteilung gilt nur in dieser Abteilung');
// ── Vorlagen ───────────────────────────────────────────────────────────────────
$presets = permission_presets();
foreach ($presets as $key => [$name, $desc, $perms]) {
$check(array_keys($perms) === array_keys($all) || count(array_diff(array_keys($all), array_keys($perms))) === 0, "Vorlage {$key} nennt jedes Recht");
$check(array_diff(array_keys($perms), array_keys($all)) === [], "Vorlage {$key} nennt keine unbekannten Rechte");
}
$check($presets['mitarbeiter'][2] == $agt, 'Vorlage „Mitarbeiter“ entspricht den Standardrechten');
$check(!$presets['nur_lesen'][2]['reply_ticket'] && $presets['nur_lesen'][2]['view_customers'], 'Vorlage „Nur lesen“ darf nicht antworten');
$check($presets['teamleitung'][2]['delete_ticket'] && !$presets['teamleitung'][2]['manage_staff'], 'Vorlage „Teamleitung“: löschen ja, Mitarbeiter verwalten nein');
$check($presets['support_manager'][2]['manage_staff'] && !$presets['support_manager'][2]['manage_roles'], 'Vorlage „Support-Manager“: Mitarbeiter ja, Rollen nein');
echo $failures ? "FEHLGESCHLAGEN:\n - " . implode("\n - ", $failures) . "\n" : '';
echo "Rechte-Test: " . ($total - count($failures)) . " von {$total} Prüfungen in Ordnung.\n";
exit($failures ? 1 : 0);