strtolower(trim($group, '/')), array_values(array_map('strval', (array) ($currentUser['groups'] ?? []))) ); $isPartial = !empty($_GET['partial']); if (!in_array('administrators', $currentGroups, true)) { http_response_code(403); $forbidden = '

Kein Zugriff auf Admin Apps.

'; if ($isPartial) { echo $forbidden; return; } ?> Admin Apps '', 'required_groups' => [], 'available_without_login' => false, ]; $section = trim((string) ($_GET['section'] ?? $_POST['active_section'] ?? 'overview')); $allowedSections = ['overview', 'installation', 'widgets', 'integrations']; if (!in_array($section, $allowedSections, true)) { $section = 'overview'; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $installForm = [ 'target_directory_name' => trim((string) ($_POST['target_directory_name'] ?? '')), 'required_groups' => array_values(array_map('strval', (array) ($_POST['required_groups'] ?? []))), 'available_without_login' => !empty($_POST['available_without_login']), ]; $postedToken = (string) ($_POST['csrf_token'] ?? ''); if ($postedToken === '' || !hash_equals($csrfToken, $postedToken)) { $errors[] = 'Die Formularpruefung ist fehlgeschlagen.'; } else { $action = (string) ($_POST['action'] ?? ''); try { if ($action === 'save-gitea') { $service->saveGiteaConfig([ 'base_url' => (string) ($_POST['base_url'] ?? ''), 'token' => (string) ($_POST['token'] ?? ''), 'owner' => (string) ($_POST['owner'] ?? ''), 'repositories' => (string) ($_POST['repositories'] ?? ''), 'poll_idle_seconds' => (string) ($_POST['poll_idle_seconds'] ?? ''), 'poll_running_seconds' => (string) ($_POST['poll_running_seconds'] ?? ''), 'visibility' => (string) ($_POST['visibility'] ?? ''), ]); $messages[] = 'Gitea-Deploy-Status-Konfiguration gespeichert.'; $section = 'integrations'; } elseif ($action === 'save-app-access') { $service->saveAppAccess( (string) ($_POST['app_id'] ?? ''), array_values(array_map('strval', (array) ($_POST['required_groups'] ?? []))), !empty($_POST['available_without_login']) ); $messages[] = 'LDAP-Gruppen fuer die App wurden gespeichert.'; $section = 'overview'; } elseif ($action === 'install-app') { $result = $service->installUploadedApp( is_array($_FILES['module_zip'] ?? null) ? $_FILES['module_zip'] : [], $installForm['target_directory_name'], $installForm['required_groups'], $installForm['available_without_login'] ); $messages[] = 'App installiert: ' . (string) ($result['manifest']['title'] ?? $result['module_directory']); $messages[] = 'Zielverzeichnis: custom/apps/' . (string) $result['module_directory']; $messages[] = 'App-ID fuer Berechtigungen: ' . (string) $result['app_id']; $installForm = [ 'target_directory_name' => '', 'required_groups' => [], 'available_without_login' => false, ]; $section = 'installation'; } } catch (\Throwable $exception) { $errors[] = $exception->getMessage(); if ($action === 'install-app') { $section = 'installation'; } } } } $bootstrap = $service->bootstrap(true); $apps = is_array($bootstrap['apps'] ?? null) ? $bootstrap['apps'] : []; $widgets = is_array($bootstrap['widgets'] ?? null) ? $bootstrap['widgets'] : []; $stats = is_array($bootstrap['stats'] ?? null) ? $bootstrap['stats'] : []; $meta = is_array($bootstrap['meta'] ?? null) ? $bootstrap['meta'] : []; $availableGroups = is_array($meta['available_groups'] ?? null) ? $meta['available_groups'] : []; $gitea = is_array($bootstrap['gitea'] ?? null) ? $bootstrap['gitea'] : []; $giteaConfig = is_array($gitea['config'] ?? null) ? $gitea['config'] : []; $giteaDiagnostics = is_array($gitea['diagnostics'] ?? null) ? $gitea['diagnostics'] : []; $h = static fn (?string $value): string => htmlspecialchars($value ?? '', ENT_QUOTES); $sectionUrl = static fn (string $targetSection): string => '/admin/apps/?section=' . rawurlencode($targetSection); $sectionMeta = [ 'overview' => [ 'label' => 'Apps', 'title' => 'Apps und Bereitstellung', 'description' => 'Apps sind allgemeine Anwendungen. Sie koennen als Menue-App, Tray-App, Widget-Quelle oder mit optionalem Desktop-Icon auftreten.', 'nav' => 'Bestand und Installationsweg pruefen.', ], 'installation' => [ 'label' => 'Installation', 'title' => 'ZIP-Upload und Installation', 'description' => 'Installierbare Fach-Apps liegen unter custom/apps/. ZIP-Dateien koennen hier geprueft, entpackt und mit LDAP-Gruppen verknuepft werden.', 'nav' => 'ZIP hochladen und nach /custom/apps/ installieren.', ], 'widgets' => [ 'label' => 'Widgets', 'title' => 'Widget-Quellen', 'description' => 'Hier sieht man nur, welche Widgets aktuell im System registriert sind, aus welcher App sie kommen und welche Start-App oder Status-API dahinterliegt.', 'nav' => 'Registrierte Widgets und Herkunft pruefen.', ], 'integrations' => [ 'label' => 'Integrationen', 'title' => 'Gitea-Deploy-Status', 'description' => 'Erste echte Admin-Einstellung fuer das Deploy-Status-Addon inklusive Environment-Datei und Tray-Sichtbarkeit.', 'nav' => 'Addon-Konfiguration bearbeiten.', ], ]; ob_start(); ?>

Admin Registry

Administrators only Desktop Auth Section:
Ergebnis
Bitte pruefen
Installierbare Apps
Systemtools
Core-Apps

Registry

Desktop-Apps

Titel Scope Typ LDAP-Gruppen Route Flags

Berechtigungen

LDAP-Gruppen und Freigabe fuer den Logoff-Desktop zentral festlegen.

Aktuell:

Keine LDAP-Gruppen gefunden.

Desktop Widget Tray Default Logoff Desktop Admin only

Installation

Aktueller Installationsweg

Neue Apps koennen als Modul-Verzeichnis unter custom/apps/ liegen. Fuer ZIP-Dateien steht der eigentliche Installer im Bereich Installation zur Verfuegung.

Flags

Bedeutung der Flags

Default bedeutet: Die App wird fuer neue Benutzer oder fuer Benutzer ohne explizite Auswahl initial vorausgewaehlt. Logoff Desktop bedeutet: Die App darf bereits ohne Login auf der offenen Desktop-Oberflaeche erscheinen, sofern sie als Desktop-App darstellbar ist.

Gespeichert wird in . Dort liegen sowohl LDAP-Gruppen als auch die Freigabe fuer den offenen Desktop.

Installierbare Apps
Systemtools

ZIP-Installer

App als ZIP hochladen

Das ZIP muss genau ein Modulverzeichnis enthalten. Geprueft werden oberstes Verzeichnis, Pflichtdateien wie module.json und desktop.php, Name-Konflikte sowie einfache Hochrisiko-Muster im Code.

LDAP-Gruppen nach der Installation

Leere Auswahl bedeutet: alle sichtbaren Benutzer. Die Werte werden sofort in hinterlegt.

Keine LDAP-Gruppen aus der Registration-Konfiguration gefunden.

Checks

Was geprueft wird

Der Installer erwartet ein einzelnes Modulverzeichnis im ZIP, prueft auf module.json und desktop.php, blockiert Pfad-Traversal, Symlinks und typische Hochrisiko-Funktionen wie exec() oder shell_exec(). Das ist ein Plausibilitaetscheck, keine vollstaendige Sicherheitsgarantie.

Widget Registry

Registrierte Widgets

Dieser Bereich ist rein technisch gemeint: Er zeigt, welche Widgets derzeit registriert sind, aus welcher Quelle sie kommen und welche App oder API damit verbunden ist. Er ist keine separate Benutzerverwaltung.

Widget Zone Quelle Launch-App Status-API
Modul:

Addon

Gitea-Deploy-Status

Die Werte werden in der aktuellen Environment-Datei gespeichert und beim Deploy in das gemischte `config/`-Verzeichnis uebernommen.

Aktuelle Datei

Der Tray ist fuer den aktuellen Benutzer .

Konfiguriert
Token vorhanden
Repos konfiguriert
Visibility
Admin Apps