Files
deskhub/DeskHub-Webseite/includes/web_handoff.php
T
2026-10-24 20:14:54 +00:00

87 lines
5.3 KiB
PHP

<?php
/**
* includes/web_handoff.php
*
* Übergabe von der App an die Webseite: Für alles, was nur am Bildschirm sinnvoll zu bedienen ist (Einstellungen, Assistent,
* Backup, Plugins, Webhooks …), öffnen Android- und Windows-App die passende Seite der Weboberfläche. Die App holt dafür eine
* einmalige Anmelde-Adresse (60 Sekunden gültig, nur einmal benutzbar); die Webseite prüft dann wie immer selbst die Rechte.
* Die App zeigt nur die Seiten, die der Mitarbeiter laut dieser Liste überhaupt öffnen darf.
*/
/**
* Seiten der Weboberfläche, die die Apps nicht selbst nachbauen.
*
* @return array<int,array{key:string,label:string,path:string,group:string}>
*/
function web_handoff_pages(array $staff): array
{
$isAdmin = ($staff['role'] ?? '') === 'admin';
$perm = fn(string $p): bool => $isAdmin || has_permission($staff, $p);
$all = [
// Alle Mitarbeiter
['mentions', 'Erwähnungen', '/staff/mentions.php', 'Allgemein', true],
['agent_directory', 'Mitarbeiterverzeichnis', '/staff/agent_directory.php', 'Allgemein', true],
// Mit Recht
['assistant', 'Digitaler Assistent (Antworten, Fragen-Log)', '/staff/assistant.php', 'Verwaltung', $perm('manage_assistant')],
['imap_accounts', 'Postfächer (E-Mail-Abruf)', '/staff/imap_accounts.php', 'Verwaltung', $perm('manage_email_addresses')],
// Nur Administratoren
['settings', 'Einstellungen', '/staff/settings.php', 'Verwaltung', $isAdmin],
['recurring_tickets', 'Wiederkehrende Tickets', '/staff/recurring_tickets.php', 'Verwaltung', $isAdmin],
['canned_responses', 'Textbausteine', '/staff/canned_responses.php', 'Verwaltung', $isAdmin],
['custom_fields', 'Ticket-Felder', '/staff/custom_fields.php', 'Verwaltung', $isAdmin],
['custom_lists', 'Benutzerdefinierte Listen', '/staff/custom_lists.php', 'Verwaltung', $isAdmin],
['site_pages', 'Seiten (Impressum, Datenschutz …)', '/staff/site_pages.php', 'Verwaltung', $isAdmin],
['ticket_templates', 'Ticket-Vorlagen', '/staff/ticket_templates.php', 'Verwaltung', $isAdmin],
['status_page', 'Statusseite (Dienste, Meldungen)', '/staff/status_page.php', 'Verwaltung', $isAdmin],
['webhooks', 'Webhooks', '/staff/webhooks.php', 'Verwaltung', $isAdmin],
['api_keys', 'API-Schlüssel', '/staff/api_keys.php', 'Verwaltung', $isAdmin],
['plugins', 'Plugins und Themes', '/staff/plugins.php', 'System', $isAdmin],
['backup', 'Backup', '/staff/backup.php', 'System', $isAdmin],
['update', 'System-Update', '/staff/update.php', 'System', $isAdmin],
['security_check', 'Sicherheitsprüfung', '/staff/security_check.php', 'System', $isAdmin],
['import_osticket', 'Import aus osTicket', '/staff/import_osticket.php', 'System', $isAdmin],
];
$out = [];
foreach ($all as [$key, $label, $path, $group, $allowed]) {
if ($allowed) $out[] = ['key' => $key, 'label' => $label, 'path' => $path, 'group' => $group];
}
return $out;
}
/** Darf diese Adresse aus der App geöffnet werden? (eine Seite der Liste oder ein einzelnes Ticket) */
function web_handoff_path_allowed(array $staff, string $path): bool
{
if (preg_match('#^/staff/(ticket_view|ticket_print|ticket_split)\.php\?n=[A-Za-z0-9._-]{1,40}$#', $path)) return true;
foreach (web_handoff_pages($staff) as $p) if ($p['path'] === $path) return true;
return false;
}
/** Erzeugt die einmalige Anmelde-Adresse für die Seite $path. */
function web_handoff_create(PDO $pdo, array $staff, string $path): ?string
{
if (!web_handoff_path_allowed($staff, $path)) return null;
$token = bin2hex(random_bytes(32));
$now = db_now();
$pdo->prepare('DELETE FROM web_login_tokens WHERE expires_at < ?')->execute([date('Y-m-d H:i:s', time() - 3600)]);
$pdo->prepare('INSERT INTO web_login_tokens (staff_id, token_hash, path, created_at, expires_at) VALUES (?,?,?,?,?)')
->execute([(int) $staff['id'], hash('sha256', $token), $path, $now, date('Y-m-d H:i:s', time() + 60)]);
return rtrim(base_url(), '/') . '/staff/app_login.php?t=' . $token;
}
/** Löst die Anmelde-Adresse ein (einmalig). @return array{staff:array,path:string}|null */
function web_handoff_consume(PDO $pdo, string $token): ?array
{
if (!preg_match('/^[a-f0-9]{64}$/', $token)) return null;
$hash = hash('sha256', $token);
$upd = $pdo->prepare('UPDATE web_login_tokens SET used_at = ? WHERE token_hash = ? AND used_at IS NULL AND expires_at >= ?');
$upd->execute([db_now(), $hash, db_now()]);
if ($upd->rowCount() !== 1) return null; // schon benutzt, abgelaufen oder unbekannt
$row = $pdo->prepare('SELECT t.path AS handoff_path, s.* FROM web_login_tokens t JOIN staff s ON s.id = t.staff_id WHERE t.token_hash = ? AND s.is_active = 1');
$row->execute([$hash]);
$r = $row->fetch();
if (!$r) return null;
$path = (string) $r['handoff_path'];
unset($r['handoff_path']);
return ['staff' => $r, 'path' => $path];
}