Markus Michalski FAQ

Markdown Support: Technische Details

Technik von Markdown Support: Plugin-Metadaten, Core-Patch und Backup, Signal-Handler, E-Mail-Vorverarbeitung, Preview-Endpoint, Sicherheitsmaßnahmen und Dateistruktur.

English Version

Zurück zur Übersicht

Markdown Support: Technische Details

Plugin-Metadaten

Eigenschaft Wert
Plugin-ID com.osticket:markdown-support
Name Markdown Support
Plugin-Klasse MarkdownPlugin in class.MarkdownPlugin.php
Konfigurationsklasse MarkdownConfig in config.php
Instanzen Singleton: genau eine Instanz, enable() legt sie bei Bedarf an
PHP 8.0 oder neuer: composer.json deklariert >=7.4, aber ConfigCache verwendet den PHP-8.0-Typ mixed. Unter PHP 7.4 lösen get() und set() einen TypeError aus
Abhängigkeit erusev/parsedown ^1.7 (gesperrt auf 1.7.4)

Ablauf beim Start

graph TD
    A["bootstrap()"] --> B["Konfiguration in ConfigCache laden"]
    B --> C["Version prüfen und Preview-Endpoint kopieren"]
    C --> D{"Enable Markdown Support an?"}
    D -->|"Nein"| E["Ende"]
    D -->|"Ja"| F["ThreadEntryBody::types um markdown erweitern"]
    F --> G["MarkdownThreadEntryBody laden, class.thread.php patchen"]
    G --> H["POST für E-Mail vorverarbeiten"]
    H --> I["Signale object.view und threadentry.created verbinden"]
    I --> J["Output-Buffer für Editor-Seiten"]

Core-Eingriff

Das Plugin braucht zwei Eingriffe in osTicket:

Enthält die Datei bereits einen case 'markdown':, tut das Plugin nichts. Vor dem Patch kopiert es die Datei nach include/class.thread.php.markdown-backup, sofern noch keine Sicherung existiert. Beim Deaktivieren stellt es die Datei aus dieser Sicherung wieder her und löscht sie. Fehlt die Sicherung, stellt es nichts wieder her. Eine bereits vorhandene Sicherung wird nicht überschrieben (siehe Installation, Abschnitt osTicket aktualisieren).

Rendering

MarkdownThreadEntryBody erweitert ThreadEntryBody mit dem Typ markdown und rendert in display():

  1. Parsedown mit setSafeMode(true) wandelt Markdown zu HTML.
  2. Format::sanitize() von osTicket bereinigt das Ergebnis.
  3. Im Modus pdf ersetzt das Plugin img-Tags mit http(s)-Quelle durch den Text [Image]. Im Modus email bleibt das HTML unverändert.

Die Suchindizierung (getSearchable()) wandelt das gerenderte HTML mit Format::html2text() in Text um.

E-Mail-Verarbeitung

osTicket verwendet für E-Mails den rohen POST-Text. Der Markdown-Editor sendet Klartext, deshalb würden E-Mails sonst Markdown-Syntax zeigen. Das Plugin geht so vor:

  1. Bei einem POST mit format=markdown sichert es die Felder response, note und message, rendert sie mit MarkdownThreadEntryBody zu HTML und setzt format für osTicket auf html.
  2. osTicket legt den Eintrag als HTML an und versendet die E-Mail mit dem gerenderten Text.
  3. Der Handler für threadentry.created merkt sich die ID des Eintrags.
  4. Eine Shutdown-Funktion schreibt am Ende der Anfrage das ursprüngliche Markdown und format = 'markdown' per SQL in THREAD_ENTRY_TABLE zurück.

Zusätzlich korrigiert der Handler das Format über threadentry.created, wenn die Anfrage ein gültiges format mitbringt (siehe API-Integration).

Editor-Assets

Preview-Endpoint

markdown-preview.php wird beim Aktivieren (und bei jedem Start, wenn die Datei abweicht) nach api/markdown-preview.php kopiert, weil include/ per .htaccess gesperrt ist. Der Endpoint:

Der Endpoint existiert unter zwei Pfaden: als api/markdown-preview.php (vom Plugin dorthin kopiert) und als Original im Plugin-Ordner include/plugins/markdown-support/markdown-preview.php, das die .htaccess des Plugins freigibt. Beide Pfade sind ohne Anmeldung erreichbar, prüfen kein CSRF-Token, begrenzen die Größe der Eingabe nicht und laden osTicket nicht. Die Live-Vorschau im Editor nutzt nur die Kopie in api/.

Die Vorschau läuft nicht durch Format::sanitize(), sondern nur durch den eigenen Filter. Sie zeigt deshalb nicht in jedem Fall exakt das HTML, das später in der Ticket-Ansicht erscheint.

Sicherheit

Maßnahme Wo
Parsedown SafeMode (HTML im Text wird maskiert, unsichere URL-Schemata werden entschärft) Rendering und Vorschau
Format::sanitize() (osTicket) Rendering von Thread-Einträgen
Regex-Filter für javascript:/data:-URLs, on*, expression(), script Preview-Endpoint
Bild-Upload: MIME-Whitelist (JPEG, PNG, GIF, WebP, BMP), URL-Prüfung, Alt-Text ohne [](/), Abbruch ohne CSRF-Token Editor im Browser
Eigene .htaccess im Plugin-Ordner: gibt markdown-preview.php frei, sperrt *.log Plugin-Ordner
SQL-Werte über db_input() Format- und Body-Updates

Die Klasse MarkdownSanitizer ist mit Tests enthalten, wird im Plugin-Ablauf aber nicht aufgerufen.

Änderungen an include/.htaccess

Beim Aktivieren fügt das Plugin zwei Blöcke ein: einen FilesMatch-Block, der js, css, map, json, Bilder und Fonts freigibt, und einen Block für PHP-Dateien unter plugins/. Beim Deaktivieren entfernt es beide Blöcke wieder. Für NGINX gibt es keine automatische Anpassung.

Die Regel für PHP-Dateien (<FilesMatch "^plugins/.+\.php$">) wird von Apache nur gegen Dateinamen ohne Pfad geprüft und greift deshalb vermutlich nie. Geöffnet wird markdown-preview.php durch die Files-Direktive in der .htaccess des Plugin-Ordners.

Dateistruktur

markdown-support/
├── plugin.php                 # Plugin-Metadaten
├── class.MarkdownPlugin.php   # Plugin-Klasse, Signale, enable/disable
├── config.php                 # MarkdownConfig mit den Optionen
├── markdown-body.php          # MarkdownThreadEntryBody
├── markdown-preview.php       # Preview-Endpoint (Kopie landet in api/)
├── MarkdownDetector.php       # Erkennung von Markdown-Syntax
├── .htaccess                  # Freigabe des Endpoints, Sperre für Logs
├── src/
│   ├── Config/ConfigCache.php
│   ├── Core/CorePatcher.php
│   ├── Asset/AssetInjector.php
│   ├── Asset/AssetDeployer.php
│   ├── Http/MarkdownPostProcessor.php
│   ├── Signal/ThreadEntryHandler.php
│   └── Format/                # Sanitizer und Interfaces
├── css/markdown-editor.css
├── js/markdown-editor.js      # gebündelt aus js/src/
├── i18n/de_DE/                # Deutsche Übersetzung der Konfiguration
└── vendor/                    # Parsedown (Composer)

Das Repository enthält zusätzlich Tests (PHPUnit), Build-Quellen für das JavaScript und Dokumentation. Die CI führt eine Syntaxprüfung (php -l) mit PHP 7.4 bis 8.3 aus.