diff --git a/DeskHub-Webseite/.htaccess b/DeskHub-Webseite/.htaccess index ed301e59..fb7d8dcf 100644 --- a/DeskHub-Webseite/.htaccess +++ b/DeskHub-Webseite/.htaccess @@ -13,7 +13,7 @@ RewriteRule ^ - [F,L] # RewriteRule ^ - [F,L] # Clickjacking-Schutz -Header always set X-Frame-Options "SAMEORIGIN" +Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" # Schützt interne Verzeichnisse vor direktem Web-Zugriff. diff --git a/DeskHub-Webseite/live_chat.php b/DeskHub-Webseite/live_chat.php index 3e90be1b..2788c0c6 100644 --- a/DeskHub-Webseite/live_chat.php +++ b/DeskHub-Webseite/live_chat.php @@ -248,7 +248,7 @@ if ($action !== 'typing') { if ($action === 'typing') { if ($activeTicket && $activeTicket['status'] !== 'closed') { - $pdo->prepare('UPDATE tickets SET typing_customer_until = ? WHERE id = ?') + $pdo->prepare('UPDATE tickets SET typing_customer_until = ?, updated_at = updated_at WHERE id = ?') ->execute([date('Y-m-d H:i:s', time() + 6), $activeTicket['id']]); } chat_json(['ok' => true]); diff --git a/DeskHub-Webseite/tests/status_plugin_site.php b/DeskHub-Webseite/tests/status_plugin_site.php new file mode 100644 index 00000000..701522d1 --- /dev/null +++ b/DeskHub-Webseite/tests/status_plugin_site.php @@ -0,0 +1,75 @@ + $pdo->query("SELECT * FROM status_components WHERE name = " . $pdo->quote($name))->fetch(PDO::FETCH_ASSOC); + +// Ohne offiziellen Katalog gibt es nichts zu prüfen +$check(status_plugin_site_url() === '', 'ohne Katalog keine Prüfadresse'); +status_restore_core_components($pdo); +$check(!$byName('Plugin-Webseite'), 'ohne Katalog wird kein Dienst "Plugin-Webseite" angelegt'); + +// Mit offiziellem Katalog +$GLOBALS['deskhub_catalog_defaults'] = ['plugins_url' => 'https://plugins.example.test/seite/catalog.php?type=plugins', 'themes_url' => '', 'publisher_key' => 'x']; +$check(status_plugin_site_url() === 'https://plugins.example.test/seite/health.php', 'Prüfadresse liegt neben dem Katalog: ' . status_plugin_site_url()); +$check(status_restore_core_components($pdo) >= 1, 'Standarddienste ergänzen den fehlenden Dienst'); +$c = $byName('Plugin-Webseite'); +$check((bool) $c && $c['monitor_type'] === 'plugin_site' && (int) ($c['is_enabled'] ?? 1) === 1, 'Dienst "Plugin-Webseite" ist angelegt und aktiv'); +$t = status_component_monitor_target($pdo, $c); +$check($t && $t['type'] === 'plugin_site' && $t['target'] === 'https://plugins.example.test/seite/health.php', 'Prüfziel ist das health.php der Plugin-Webseite'); +$check(status_restore_core_components($pdo) === 0, 'ein zweiter Durchlauf legt nichts doppelt an'); +$check(isset(status_monitor_types()['plugin_site']) && status_set_component_monitor($pdo, (int) $c['id'], 'plugin_site', ''), 'Prüfart "Plugin-Webseite" lässt sich wählen'); + +// Automatische Erkennung am Namen (Dienst mit anderem Namen, Prüfart "auto") +$id = status_save_component($pdo, null, 'Pluginseite von DeskHub', '', 900, null); +$row = $pdo->query('SELECT * FROM status_components WHERE id = ' . (int) $id)->fetch(PDO::FETCH_ASSOC); +$t = status_component_monitor_target($pdo, $row); +$check($t && $t['type'] === 'plugin_site', 'Name mit "Plugin" und "seite" wird automatisch erkannt'); +$id2 = status_save_component($pdo, null, 'Plugin-Hersteller', '', 910, null); +$row2 = $pdo->query('SELECT * FROM status_components WHERE id = ' . (int) $id2)->fetch(PDO::FETCH_ASSOC); +$check(status_component_monitor_target($pdo, $row2) === null, 'ein anderer Name mit "Plugin" wird nicht fälschlich geprüft'); + +// Intern: wird geprüft, steht aber nicht öffentlich +$check(status_has_internal($pdo), 'Spalte is_internal ist vorhanden'); +$check((int) $byName('Plugin-Webseite')['is_internal'] === 1, 'Plugin-Webseite ist standardmäßig intern'); +$cat = $pdo->query('SELECT name FROM status_categories WHERE id = ' . (int) $byName('Plugin-Webseite')['category_id'])->fetchColumn(); +$check($cat === 'Server & Datenbank', 'Kategorie ist "Server & Datenbank", nicht "Webseite": ' . var_export($cat, true)); +$pub = array_column(status_components($pdo, false, true), 'name'); +$all = array_column(status_components($pdo), 'name'); +$check(!in_array('Plugin-Webseite', $pub, true) && in_array('Plugin-Webseite', $all, true), 'öffentliche Liste ohne den internen Dienst, Mitarbeiterliste mit ihm'); +$check(in_array('plugin_site', array_map(fn($c) => (status_component_monitor_target($pdo, $c)['type'] ?? ''), status_components($pdo)), true), 'interner Dienst wird weiter geprüft'); +// Ausfall eines internen Dienstes ändert den öffentlichen Gesamtzustand nicht +status_set_component($pdo, (int) $byName('Plugin-Webseite')['id'], 'outage'); +$check(status_overall($pdo)['key'] === 'operational', 'Ausfall eines internen Dienstes ändert den öffentlichen Gesamtzustand nicht: ' . status_overall($pdo)['key']); +$check(status_set_component_internal($pdo, (int) $byName('Plugin-Webseite')['id'], false) && in_array('Plugin-Webseite', array_column(status_components($pdo, false, true), 'name'), true), 'als öffentlich markiert erscheint er wieder'); +$check(status_overall($pdo)['key'] === 'outage', 'öffentlich: der Ausfall zählt'); +status_set_component_internal($pdo, (int) $byName('Plugin-Webseite')['id'], true); +status_set_component($pdo, (int) $byName('Plugin-Webseite')['id'], 'operational'); +// Störung an einem internen Dienst erscheint nicht öffentlich +$inc = status_create_incident($pdo, 'Plugin-Webseite langsam', 'x', 'investigating', (int) $byName('Plugin-Webseite')['id'], null, null); +$check(!empty($inc['ok']) && count(status_incidents($pdo, 14)) === 0 && count(status_incidents($pdo, 14, false, true)) === 1, 'Störung an einem internen Dienst steht nicht öffentlich, Mitarbeiter sehen sie'); + +// Eine http-Adresse (ohne https) wird nicht als Prüfadresse verwendet +$GLOBALS['deskhub_catalog_defaults'] = ['plugins_url' => 'http://plugins.example.test/catalog.php', 'themes_url' => '', 'publisher_key' => 'x']; +$check(status_plugin_site_url() === '', 'nur https wird verwendet'); +unset($GLOBALS['deskhub_catalog_defaults']); + +if ($failures) { + fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n"); + exit(1); +} +echo "Status plugin site checks passed.\n"; diff --git a/DeskHub-Webseite/tests/ticket_lock_admin.php b/DeskHub-Webseite/tests/ticket_lock_admin.php index 7d35cd4c..be6d4782 100644 --- a/DeskHub-Webseite/tests/ticket_lock_admin.php +++ b/DeskHub-Webseite/tests/ticket_lock_admin.php @@ -216,10 +216,10 @@ try { [$s] = $call('GET', '/staff/ticket_view.php?n=T-OPEN-5', null, null, [], $jarChef, ['Sec-Fetch-Mode: navigate']); $check($s === 200 && (int) $assignee('T-OPEN-5') === $ids['Chef'], 'Auch im Browser: Öffnen weist das Ticket zu (HTTP ' . $s . ')'); - // Ticketliste: Spalte mit dem Eingangsdatum + // Ticketliste: Spalte mit der letzten Aktivität (Eingang im Tooltip) [$s, $list] = $call('GET', '/staff/tickets.php', null, null, [], $jarChef, ['Sec-Fetch-Mode: navigate']); $list = is_string($list) ? $list : ''; - $check($s === 200 && str_contains($list, '