diff --git a/DeskHub-Webseite/staff/availability.php b/DeskHub-Webseite/staff/availability.php index cfc15605..73838ea2 100644 --- a/DeskHub-Webseite/staff/availability.php +++ b/DeskHub-Webseite/staff/availability.php @@ -125,17 +125,36 @@ $activePage = 'availability'; require __DIR__ . '/_header.php'; $statusLabels = [ - 'available' => ['Verfügbar', '#22c55e', '🟢'], - 'busy' => ['Beschäftigt', '#f59e0b', '🟡'], - 'break' => ['Pause', '#6366f1', '🟣'], - 'offline' => ['Offline', '#94a3b8', '⚫'], + 'available' => ['Verfügbar', '#22c55e'], + 'busy' => ['Beschäftigt', '#f59e0b'], + 'break' => ['Pause', '#6366f1'], + 'offline' => ['Offline', '#94a3b8'], ]; $weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']; ?> + -
-

Verfügbarkeit & Schichten

-
+

Verfügbarkeit & Schichten

@@ -147,53 +166,38 @@ foreach ($agents as $a) { if ($a['id'] === $staff['id']) { $myAvail = $a; break; $myStatus = $myAvail['avail_status'] ?? 'available'; ?>
-
Mein Status
-
- [$sl, $sc, $se]): ?> - -
- -
+
-
Team-Übersicht
-
+

Team-Übersicht

+
-
-
- - -
+
+
-
- - 🌴 -
-
-
+
+
+
+
automatisch offline
+
aktiv
- - ⚙️ - - -
offline' : '' ?>
+ Schichtplan
@@ -202,34 +206,38 @@ $myStatus = $myAvail['avail_status'] ?? 'available';
-
Status der Mitarbeiter ändern (Admin)
-

Ein von dir gesetzter Status bleibt, bis der Mitarbeiter ihn selbst ändert oder du ihn erneut änderst.

- +

Status der Mitarbeiter ändern (Admin)

+

Ein von dir gesetzter Status bleibt, bis der Mitarbeiter ihn selbst ändert oder du ihn erneut änderst.

+
+ + - - - + + -
MitarbeiterStatus und Notiz
-
+
+ - [$sl]): ?> - +
-
+ +
+ - - Minuten ohne Aktivität + + + Minuten ohne Aktivität - 0 = aus. Bei neuer Aktivität kommt der vorherige Status zurück. + 0 = aus. Bei neuer Aktivität kommt der vorherige Status zurück.
@@ -309,18 +317,7 @@ var statusUpdateTimer; function setMyStatus(s) { currentStatus = s; document.querySelectorAll('.status-btn').forEach(function(btn) { - var active = btn.dataset.status === s; - var colors = { - available: ['#22c55e','#22c55e18'], - busy: ['#f59e0b','#f59e0b18'], - break: ['#6366f1','#6366f118'], - offline: ['#94a3b8','#94a3b818'], - }; - var c = colors[btn.dataset.status] || ['var(--border)','transparent']; - btn.style.borderColor = active ? c[0] : 'var(--border)'; - btn.style.background = active ? c[1] : 'transparent'; - btn.style.color = active ? c[0] : 'var(--ink-soft)'; - btn.style.fontWeight = active ? '600' : '400'; + btn.classList.toggle('active', btn.dataset.status === s); }); sendStatusUpdate(); } @@ -360,7 +357,7 @@ function refreshTeamStatus() { var colors = { available:'#22c55e', busy:'#f59e0b', break:'#6366f1', offline:'#94a3b8' }; var labels = { available:'Verfügbar', busy:'Beschäftigt', break:'Pause', offline:'Offline' }; var s = ag.is_on_vacation ? 'offline' : (ag.status || 'offline'); - var label = ag.is_on_vacation ? '🌴 Urlaub' : labels[s]; + var label = ag.is_on_vacation ? 'Urlaub' : labels[s]; var color = colors[s] || '#94a3b8'; el.querySelector('.status-dot').style.background = color; el.querySelector('.status-label').textContent = label; diff --git a/DeskHub-Webseite/staff/login.php b/DeskHub-Webseite/staff/login.php index 0525fc89..f8e1b280 100644 --- a/DeskHub-Webseite/staff/login.php +++ b/DeskHub-Webseite/staff/login.php @@ -24,21 +24,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !csrf_valid()) { $stmt = get_db()->prepare('SELECT * FROM staff WHERE id = ? AND is_active = 1'); $stmt->execute([$pendingId]); $staff = $stmt->fetch(); - if ($staff && totp_verify($staff['totp_secret'], $code)) { + if ($staff && !rate_limit_check('staff_totp_attempt', (string) $pendingId, login_guard_max_attempts(), login_guard_lock_minutes())) { + // Code-Raten bremsen: nach zu vielen Fehlversuchen muss das Passwort neu eingegeben werden unset($_SESSION['totp_pending_staff_id']); + login_guard_locked((string) $staff['email'], 'web'); + $errors[] = 'Zu viele falsche Codes. Bitte warten Sie einige Minuten und melden Sie sich neu an.'; + } elseif ($staff && totp_verify($staff['totp_secret'], $code)) { + unset($_SESSION['totp_pending_staff_id']); + rate_limit_reset('staff_totp_attempt', (string) $pendingId); staff_login($staff); redirect('/staff/reports.php'); + } else { + if ($staff) login_guard_failed($staff, (string) $staff['email'], 'web', 'Falscher 2FA-Code'); + $errors[] = 'Ungültiger Code. Bitte erneut versuchen.'; + $need2fa = true; } - $errors[] = 'Ungültiger Code. Bitte erneut versuchen.'; - $need2fa = true; } } else { $email = trim($_POST['email'] ?? ''); $pass = $_POST['password'] ?? ''; if (!rate_limit_check('staff_login_attempt', client_ip(), 10, 15)) { $errors[] = 'Zu viele Anmeldeversuche. Bitte versuchen Sie es in einigen Minuten erneut.'; - } elseif ($email && !rate_limit_check('staff_login_email', strtolower($email), 5, 15)) { + } elseif ($email && !rate_limit_check('staff_login_email', strtolower($email), login_guard_max_attempts(), login_guard_lock_minutes())) { // Konto-basierte Sperre – verhindert Brute-Force über wechselnde IPs + login_guard_locked($email, 'web'); $errors[] = 'Zu viele Anmeldeversuche für dieses Konto. Bitte warten Sie einige Minuten.'; } else { $stmt = get_db()->prepare('SELECT * FROM staff WHERE LOWER(email) = LOWER(?) AND is_active = 1'); @@ -55,6 +64,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !csrf_valid()) { redirect('/staff/reports.php'); } } else { + login_guard_failed($staff ?: null, $email, 'web', $staff ? 'Falsches Passwort' : 'Unbekannte E-Mail-Adresse'); $errors[] = 'E-Mail-Adresse oder Passwort ist falsch.'; } } @@ -141,6 +151,12 @@ $displayName = get_setting('display_name', config()['site']['name']);
+ + + +
+ +
diff --git a/DeskHub-Webseite/staff/login_alert.php b/DeskHub-Webseite/staff/login_alert.php new file mode 100644 index 00000000..001712f5 --- /dev/null +++ b/DeskHub-Webseite/staff/login_alert.php @@ -0,0 +1,68 @@ + + + + + + + +Konto sichern – Mitarbeiterbereich +"> + + + + +
+
+ +

Konto sichern

+
+ +
Ihr Konto ist gesichert. Das Passwort ist ungültig, alle App-Anmeldungen wurden beendet und die Administratoren wurden informiert.
+

Setzen Sie jetzt über „Passwort vergessen?“ ein neues Passwort.

+ + +
Dieser Link ist ungültig, abgelaufen oder wurde schon verwendet.
+

← Zur Anmeldung

+ +
Diese Anmeldung wurde von Ihrem Konto gemeldet:
+ + + + + +
Zeit
Gerät
Ort
IP-Adresse
+

Waren Sie das nicht? Dann sichern Sie Ihr Konto: Das Passwort wird ungültig, alle App-Anmeldungen und gemerkten Geräte werden beendet und die Administratoren erfahren davon. Danach legen Sie ein neues Passwort fest.

+
+ + +
+
+

Waren Sie es doch? Dann schließen Sie diese Seite einfach.

+ +
+
+ + diff --git a/DeskHub-Webseite/staff/login_log.php b/DeskHub-Webseite/staff/login_log.php new file mode 100644 index 00000000..bb46d00b --- /dev/null +++ b/DeskHub-Webseite/staff/login_log.php @@ -0,0 +1,118 @@ +exec('DELETE FROM login_events'); + audit_log($admin['id'], 'Anmelde-Wächter: Protokoll geleert (' . (int) $n . ' Einträge)'); + flash('success', 'Protokoll geleert.'); + } elseif ($action === 'forget_devices') { + $sid = (int) ($_POST['staff_id'] ?? 0); + if ($sid > 0) { + $pdo->prepare('DELETE FROM login_devices WHERE staff_id = ?')->execute([$sid]); + $pdo->prepare('DELETE FROM login_places WHERE staff_id = ?')->execute([$sid]); + audit_log($admin['id'], 'Anmelde-Wächter: gemerkte Geräte und Orte vergessen (Mitarbeiter ' . $sid . ')'); + flash('success', 'Geräte und Orte vergessen. Die nächste Anmeldung zählt wieder als erste.'); + } + } + redirect('/staff/login_log.php'); +} + +$labels = login_guard_event_labels(); +$filter = (string) ($_GET['event'] ?? ''); +if (!isset($labels[$filter])) $filter = ''; +$q = trim((string) ($_GET['q'] ?? '')); +$where = ['1=1']; +$params = []; +if ($filter !== '') { $where[] = 'e.event = ?'; $params[] = $filter; } +if ($q !== '') { $where[] = '(e.email LIKE ? OR e.ip LIKE ? OR e.device LIKE ? OR e.place LIKE ?)'; $like = '%' . $q . '%'; array_push($params, $like, $like, $like, $like); } +$st = $pdo->prepare('SELECT e.*, s.name AS staff_name FROM login_events e LEFT JOIN staff s ON s.id = e.staff_id WHERE ' . implode(' AND ', $where) . ' ORDER BY e.id DESC LIMIT 300'); +$st->execute($params); +$rows = $st->fetchAll(); + +$since = date('Y-m-d H:i:s', time() - 86400); +$cnt = $pdo->prepare('SELECT event, COUNT(*) AS n FROM login_events WHERE created_at >= ? GROUP BY event'); +$cnt->execute([$since]); +$counts = array_fill_keys(array_keys($labels), 0); +foreach ($cnt->fetchAll() as $r) $counts[$r['event']] = (int) $r['n']; + +$pageTitle = 'Anmelde-Wächter'; +$activePage = 'login_log'; +$colors = ['success' => '#15803d', 'new_device' => '#b45309', 'new_place' => '#b45309', 'failed' => '#b91c1c', 'locked' => '#b91c1c', 'revoked' => '#7c3aed']; +require __DIR__ . '/_header.php'; +?> +

Anmelde-Wächter

+

Der Wächter merkt sich die Geräte und Orte, von denen sich Mitarbeiter anmelden (Web und App). Meldet sich jemand von einem neuen Gerät oder neuen Ort an, bekommt er eine Mail mit dem Link „Das war ich nicht“. Der Link macht das Passwort ungültig, beendet App-Anmeldungen und Browser-Sitzungen und informiert die Administratoren. Nach zu vielen Fehlversuchen wird die Anmeldung gesperrt; auch das steht im Protokoll und geht per Mail an Kontoinhaber und Administratoren. Als Ort gilt das Land (wenn Cloudflare es mitschickt), sonst das Netz der IP-Adresse; die erste Anmeldung eines Kontos wird still gemerkt.

+ +
+ +
(24 Std.)
+ +
+ +
+

Einstellungen

+ + + +
+
+
+
+
+
+
+ +
+
+

Protokoll

+
+ + + +
+
+
+ +

Keine Einträge.

+ +
+ + + + + + + + + + + + + + +
ZeitEreignisKontoGerätOrt / IPHinweis
' . e($r['email']) . '' : e($r['email']) ?>
+ +
+ +
+

Zeigt die letzten 300 Einträge. Einträge werden nach Tagen automatisch gelöscht.

+ +
+ diff --git a/DeskHub-Webseite/staff/plugin_login.php b/DeskHub-Webseite/staff/plugin_login.php new file mode 100644 index 00000000..815c8ad4 --- /dev/null +++ b/DeskHub-Webseite/staff/plugin_login.php @@ -0,0 +1,91 @@ +&e=. + * Das Plugin muss die Berechtigung "auth.login" haben und die Adresse mit plugin_register_login() anmelden. Hier steht nur, was für alle gleich ist: + * Ablauf der Antwort (Weiterleitung, Anmeldung, Fehler), Begrenzung der Aufrufe und der Eintrag im Admin-Protokoll. Wer sich anmelden darf, + * prüft das Plugin; DeskHub meldet nur aktive Mitarbeiterkonten an. + * + * Schon angemeldete Mitarbeiter kommen nur zu Adressen, die das Plugin ausdrücklich dafür angemeldet hat (zum Beispiel „Konto verknüpfen“); + * dabei kann nie ein anderer Mitarbeiter angemeldet werden. + */ +require_once __DIR__ . '/../includes/bootstrap.php'; + +header('Cache-Control: no-store'); +header('Referrer-Policy: no-referrer'); + +/** Nur Ziele im Mitarbeiterbereich: beginnt mit /staff/, keine Doppel-Schrägstriche, keine Zeilenumbrüche. */ +function plugin_login_local_ok(string $path): bool +{ + return $path !== '' && strlen($path) <= 300 && str_starts_with($path, '/staff/') && !str_contains($path, '//') && !preg_match('/[\x00-\x20\\\\]/', $path); +} + +/** Zurück mit Fehlermeldung: angemeldet in den Mitarbeiterbereich, sonst zur Anmeldeseite. */ +function plugin_login_back(string $message, ?string $back = null): never +{ + flash('error', $message); + if (current_staff()) redirect($back !== null && plugin_login_local_ok($back) ? $back : '/staff/reports.php'); + redirect('/staff/login.php'); +} + +$staffNow = current_staff(); +$slug = (string) ($_GET['p'] ?? ''); +$endpoint = (string) ($_GET['e'] ?? ''); +$handler = plugin_state()['logins'][$slug][$endpoint] ?? null; +if (!is_callable($handler)) { + if ($staffNow) redirect('/staff/reports.php'); + http_response_code(404); + echo 'Unbekannte Anmelde-Adresse.'; + exit; +} +$allowedLoggedIn = !empty(plugin_state()['login_loggedin'][$slug][$endpoint]); +if ($staffNow && !$allowedLoggedIn) redirect('/staff/reports.php'); +if (!rate_limit_check('plugin_login', client_ip(), 40, 15)) plugin_login_back('Zu viele Anmeldeversuche. Bitte versuchen Sie es in einigen Minuten erneut.'); + +$request = ['query' => $_GET, 'ip' => client_ip()]; +if ($staffNow) $request['staff'] = $staffNow; +$result = plugin_guard($slug, fn() => $handler($request), null); +$back = is_array($result) && isset($result['back']) ? (string) $result['back'] : null; +if (!is_array($result)) plugin_login_back('Die Anmeldung ist gerade nicht möglich. Bitte versuchen Sie es später noch einmal oder melden Sie sich mit E-Mail und Passwort an.'); + +// Weiter zum Anmeldedienst: nur https (oder http zu localhost zum Testen), keine Zeilenumbrüche +if (!empty($result['redirect'])) { + $url = (string) $result['redirect']; + if (!plugin_login_external_url_ok($url)) plugin_login_back('Die Adresse des Anmeldedienstes ist ungültig.', $back); + header('Location: ' . $url, true, 302); + exit; +} + +// Kunden: Die gemeinsame Rückkehr-Adresse darf auch eine Kunden-Anmeldung beenden (Berechtigung auth.customer, prüft plugin_customer_login_finish) +if (!$staffNow && (isset($result['customer']) || ($result['audience'] ?? '') === 'customer')) { + if (!empty($result['customer']) && is_array($result['customer'])) plugin_customer_login_finish($slug, $result['customer']); + flash('error', mb_substr((string) ($result['error'] ?? 'Die Anmeldung wurde abgelehnt.'), 0, 300)); + redirect('/login.php'); +} + +// Angemeldete Mitarbeiter: zurück in den Mitarbeiterbereich (mit Hinweis), nie ein anderer Mitarbeiter +if ($staffNow) { + if (!empty($result['staff_id'])) plugin_login_back('Dieser Schritt darf keinen anderen Mitarbeiter anmelden.', $back); + if (!empty($result['local'])) { + $local = (string) $result['local']; + if (!plugin_login_local_ok($local)) $local = '/staff/reports.php'; + if (!empty($result['notice'])) flash('success', mb_substr((string) $result['notice'], 0, 300)); + redirect($local); + } + plugin_login_back(mb_substr((string) ($result['error'] ?? 'Der Vorgang wurde abgelehnt.'), 0, 300), $back); +} + +// Geprüfter Mitarbeiter: anmelden +if (!empty($result['staff_id'])) { + $stmt = get_db()->prepare('SELECT * FROM staff WHERE id = ? AND is_active = 1'); + $stmt->execute([(int) $result['staff_id']]); + $staff = $stmt->fetch(); + if (!$staff) plugin_login_back('Dieses Konto ist in DeskHub nicht aktiv.'); + $via = mb_substr((string) ($result['via'] ?? $slug), 0, 60); + staff_login($staff); + audit_log((int) $staff['id'], 'Anmeldung über ' . $via . ' (Plugin ' . $slug . ')'); + redirect('/staff/reports.php'); +} + +plugin_login_back(mb_substr((string) ($result['error'] ?? 'Die Anmeldung wurde abgelehnt.'), 0, 300)); diff --git a/DeskHub-Webseite/staff/plugins.php b/DeskHub-Webseite/staff/plugins.php index 287ecf7b..f2edbb89 100644 --- a/DeskHub-Webseite/staff/plugins.php +++ b/DeskHub-Webseite/staff/plugins.php @@ -1,249 +1,516 @@ - $row) $manifests[$slug] = plugin_read_manifest(plugins_dir() . '/' . $slug)[0]; -$disabled = plugins_globally_disabled(); -$strict = plugin_strict_mode(); -$official = plugin_official_configured(); -$catalog = plugin_catalog_url() !== '' ? plugin_catalog_cached(isset($_GET['refresh']), 60) : null; -// Katalogeinträge je Plugin (für die Vorschaubilder der installierten Plugins) -$catBySlug = []; -if ($catalog && !empty($catalog['ok'])) foreach ($catalog['plugins'] as $__c) $catBySlug[$__c['slug']] = $__c; -$hasKey = plugin_publisher_key() !== ''; -$catalogHost = (string) (parse_url(plugin_catalog_url(), PHP_URL_HOST) ?: ''); - -$pageTitle = 'Plugins'; -$activePage = 'plugins'; -require __DIR__ . '/_header.php'; -?> -

Plugins

-
- - -
Updates verfügbar: $u['name'] . ' ' . $u['installed'] . ' → ' . $u['available'], $updates))) ?>. Unten im Katalog mit „Aktualisieren“ installieren.
- - -
Alle Plugins sind abgeschaltet (Datei plugins/.disabled oder Einstellung plugins.enabled = false). Bereits aktive Plugins werden nicht geladen.
- - -
- - - - $p): $m = $manifests[$slug]; $perms = $m['permissions'] ?? []; ?> - - - - - - - - - - -
PluginVersionStatusHerkunft
-
$slug, 'name' => $p['name']]) ?>
- -
-
von
- -
Berechtigungen () -
  • ()
-
-
Fordert keine Berechtigungen an.
-
plugin.json fehlt oder ist ungültig – das Plugin kann nicht geladen werden.
-
-
- Aktiv - = PLUGIN_FAIL_LIMIT): ?>Wegen Fehlern deaktiviert - Inaktiv -
-
- ✓ Signiert - Eigenes Plugin
- -
- -
- -
- - - -
- -
- - - -
-
Noch keine Plugins installiert.
-
- -
-
-

- Katalog aktualisieren -
- -

Es ist noch keine Katalog-Adresse hinterlegt. Trage unten die Adresse der Plugin-Webseite ein, dann könnt ihr Plugins direkt von dort installieren.

- -
- -
Stand:
- - - - '); ?> - - - - - - - - - -
PluginVersionSignatur
- 🌐 Sprache: ★ Empfohlen -
-
von
-
Fordert an: $permLabels[$p] ?? $p, $c['permissions']))) ?>
-
installiert: ' . e($have['version']) . '' : '' ?>✓ Signiert' : 'Signatur vorhanden, Schlüssel fehlt') : 'Nicht signiert' ?> - aktuell - nicht signiert,
nicht installierbar
- -
-
- -
Der Katalog enthält keine Plugins.
- -
- -
-

Eigenes Plugin hochladen

-

Hier könnt ihr eigene Plugins als ZIP installieren oder aktualisieren, auch ohne Signatur. Diese Plugins sind nicht vom Herausgeber geprüft und laufen mit allen Rechten des Systems, auch mit Zugriff auf die gesamte Datenbank. Installiert nur Code, den ihr selbst geschrieben oder geprüft habt.

-
- - - - - - - - -
-
-

Das Plugin wird nach der Installation nicht automatisch aktiviert. Vor dem Aktivieren bestätigt ihr die Berechtigungen, die es anfordert.

-
- - -
-

Katalog und Herausgeber-Schlüssel

-
- - - - - - -

Den Schlüssel bekommst du von der Plugin-Webseite. Ist er hinterlegt, prüft DeskHub bei jeder Installation, ob das Paket wirklich vom Herausgeber stammt und unverändert ist.

-
-
-
- - - + $row) $manifests[$slug] = plugin_read_manifest(plugins_dir() . '/' . $slug)[0]; +$disabled = plugins_globally_disabled(); +$strict = plugin_strict_mode(); +$official = plugin_official_configured(); +$catalog = plugin_catalog_url() !== '' ? plugin_catalog_cached(isset($_GET['refresh']), 60) : null; +// Katalogeinträge je Plugin (für die Vorschaubilder der installierten Plugins) +$catBySlug = []; +if ($catalog && !empty($catalog['ok'])) foreach ($catalog['plugins'] as $__c) $catBySlug[$__c['slug']] = $__c; +$hasKey = plugin_publisher_key() !== ''; +$catalogHost = (string) (parse_url(plugin_catalog_url(), PHP_URL_HOST) ?: ''); + +$updates = plugin_updates_available($pdo); +$updBySlug = []; +foreach ($updates as $u) $updBySlug[$u['slug']] = $u; +// Zustand je Plugin: active | inactive | error; dazu Update-Kennzeichen +$stateOf = []; +$counts = ['all' => 0, 'active' => 0, 'inactive' => 0, 'error' => 0, 'update' => 0]; +foreach ($installed as $slug => $p) { + $bad = !$manifests[$slug] || (!$p['is_active'] && (int) $p['fail_count'] >= PLUGIN_FAIL_LIMIT); + $st = $bad ? 'error' : ($p['is_active'] ? 'active' : 'inactive'); + $stateOf[$slug] = $st; + $counts['all']++; + $counts[$st]++; + if (isset($updBySlug[$slug])) $counts['update']++; +} +// Erste Menüseite eines geladenen Plugins für den Link „Öffnen“ +$openUrl = []; +foreach (plugin_state()['menus'] as $__m) { + if (!isset($openUrl[$__m['plugin']])) $openUrl[$__m['plugin']] = '/staff/plugin.php?p=' . rawurlencode($__m['plugin']) . '&page=' . rawurlencode($__m['page']); +} +$tab = in_array($_GET['tab'] ?? '', ['add', 'settings'], true) ? $_GET['tab'] : 'installed'; +if ($errors) { + $failedAction = $_POST['action'] ?? ''; + if (in_array($failedAction, ['install', 'catalog_install'], true)) $tab = 'add'; + if ($failedAction === 'save_settings') $tab = 'settings'; +} + +$banner = function (array $c, string $name): string { + $inner = !empty($c['preview']) + ? '' + : '' . e(mb_strtoupper(mb_substr($name, 0, 1))) . ''; + return '
' . $inner . '
'; +}; +$pageTitle = 'Plugins'; +$activePage = 'plugins'; +require __DIR__ . '/_header.php'; +?> + + +
+

Plugins

+ +
+
+ +
Updates verfügbar: $u['name'] . ' ' . $u['installed'] . ' → ' . $u['available'], $updates))) ?>. Anzeigen oder unter „Plugin hinzufügen“ mit „Aktualisieren“ installieren.
+ + +
Alle Plugins sind abgeschaltet (Datei plugins/.disabled oder Einstellung plugins.enabled = false). Bereits aktive Plugins werden nicht geladen.
+ + +
+ + + +
+ + +
> +
+
+ + + + + +
+ +
+ +
+ $p): $m = $manifests[$slug]; $perms = $m['permissions'] ?? []; $st = $stateOf[$slug]; $upd = $updBySlug[$slug] ?? null; + $trusted = ($p['source'] ?? '') === 'catalog' && !empty($p['signature_ok']); ?> +
+
+
$slug, 'name' => $p['name']]) ?>
+
+

+

plugin.json fehlt oder ist ungültig – das Plugin kann nicht geladen werden.' : '') ?>

+

Von

+
+ Aktiv + + Inaktiv + Update +
+
+
+ +
+ Öffnen + +
+ + + +
+ + Jetzt aktualisieren + Weitere Details +
+
+ +
+
+
Version
+
+
+
+
✓ Signiert vom Herausgeber' : 'Eigenes Plugin' ?>
+
+
+
+
+ +
+
>
+
+ + +
> +
+
+

+
+ + Katalog aktualisieren +
+
+ +

Es ist noch keine Katalog-Adresse hinterlegt. Trage unter „Katalog & Schlüssel“ die Adresse der Plugin-Webseite ein, dann könnt ihr Plugins direkt von dort installieren.

+ +
+ +
Stand:
+
+ '); ?> +
+
+
+
+

+

+

Von

+
+ 🌐 Sprache: + ★ Empfohlen +
+
+
+ ✓ Installiert + nicht signiert,
nicht installierbar
+ +
+
+ + Weitere Details +
+
+ +
+
+
Version
+
' . e($have['version']) . '' : 'Nicht installiert' ?>
+
+
+
✓ Signiert vom Herausgeber' : 'Signatur vorhanden, Schlüssel fehlt') : 'Nicht signiert' ?>
+
+
+
+
+ +
+
Der Katalog enthält keine Plugins.
+ +
+ +
+

Eigenes Plugin hochladen

+

Hier könnt ihr eigene Plugins als ZIP installieren oder aktualisieren, auch ohne Signatur. Diese Plugins sind nicht vom Herausgeber geprüft und laufen mit allen Rechten des Systems, auch mit Zugriff auf die gesamte Datenbank. Installiert nur Code, den ihr selbst geschrieben oder geprüft habt.

+
+ + + +
Signatur und Prüfsumme (optional) + + + + +
+ +
+
+

Das Plugin wird nach der Installation nicht automatisch aktiviert. Vor dem Aktivieren bestätigt ihr die Berechtigungen, die es anfordert.

+
+
+ + + +
> +
+

Katalog und Herausgeber-Schlüssel

+
+ + + + + + +

Den Schlüssel bekommst du von der Plugin-Webseite. Ist er hinterlegt, prüft DeskHub bei jeder Installation, ob das Paket wirklich vom Herausgeber stammt und unverändert ist.

+
+
+
+
+ + +
+ + +