107 lines
5.9 KiB
PHP
107 lines
5.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/** Prüft die Theme-Installation aus dem Katalog (includes/theme_catalog.php): Prüfsumme, Signatur, Format, Sicherheit. */
|
|
|
|
$themesDir = sys_get_temp_dir() . '/deskhub-tc-' . bin2hex(random_bytes(4));
|
|
mkdir($themesDir, 0755, true);
|
|
putenv('DESKHUB_THEMES_DIR=' . $themesDir);
|
|
putenv('DESKHUB_TESTING=1');
|
|
putenv('DESKHUB_CATALOG_DEFAULTS=' . __DIR__ . '/fixtures/no-catalog.php');
|
|
putenv('DESKHUB_SQLITE_PATH=:memory:');
|
|
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
|
|
|
if (!class_exists('ZipArchive')) { echo "Theme-Katalog-Tests übersprungen: PHP-ZIP fehlt.\n"; exit(0); }
|
|
|
|
$failures = [];
|
|
$check = function (bool $ok, string $what) use (&$failures): void {
|
|
if (!$ok) $failures[] = $what;
|
|
};
|
|
|
|
$cnf = tempnam(sys_get_temp_dir(), 'cnf');
|
|
file_put_contents($cnf, "[req]\ndistinguished_name=req_dn\n[req_dn]\n");
|
|
$k = openssl_pkey_new(['config' => $cnf, 'private_key_bits' => 2048, 'private_key_type' => OPENSSL_KEYTYPE_RSA]);
|
|
openssl_pkey_export($k, $priv, null, ['config' => $cnf]);
|
|
$pub = openssl_pkey_get_details($k)['key'];
|
|
|
|
$zipPath = tempnam(sys_get_temp_dir(), 'th') . '.zip';
|
|
$z = new ZipArchive();
|
|
$z->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
|
$z->addFromString('theme.css', "/*\n * Author: Studio\n * Version: 1.2.0\n */\n:root { --primary: #0a5; }");
|
|
$z->close();
|
|
$sha = hash_file('sha256', $zipPath);
|
|
openssl_sign(plugin_signature_message('theme-nordlicht', '1.2.0', $sha), $sigRaw, $priv, OPENSSL_ALGO_SHA256);
|
|
$sig = base64_encode($sigRaw);
|
|
|
|
$entry = ['slug' => 'nordlicht', 'name' => 'Nordlicht', 'version' => '1.2.0', 'description' => 'Hell und ruhig', 'author' => 'Studio',
|
|
'downloadUrl' => 'https://plugins.example.de/dl/nordlicht-1.2.0.zip', 'sha256' => $sha, 'signature' => $sig];
|
|
$served = ['themes' => [$entry, ['slug' => 'kaputt', 'version' => 'x', 'sha256' => 'y'], array_merge($entry, ['slug' => 'httpdl', 'downloadUrl' => 'http://x.de/a.zip'])]];
|
|
$body = file_get_contents($zipPath);
|
|
$GLOBALS['deskhub_http_get'] = function (string $url, int $max) use (&$served, &$body): array {
|
|
if (str_contains($url, 'catalog.php')) return [200, json_encode($served), null];
|
|
return [200, $body, null];
|
|
};
|
|
|
|
$check(!theme_catalog_fetch()['ok'], 'ohne Katalog-Adresse gibt es einen Hinweis');
|
|
set_setting('theme_catalog_url', 'https://plugins.example.de/catalog.php?type=themes');
|
|
$cat = theme_catalog_fetch();
|
|
$check($cat['ok'] && count($cat['themes']) === 1 && $cat['themes'][0]['slug'] === 'nordlicht', 'Katalog wird gelesen, ungültige Einträge werden verworfen');
|
|
|
|
$r = theme_catalog_install('nordlicht');
|
|
$check(!$r['ok'] && str_contains($r['error'], 'kein Herausgeber-Schlüssel'), 'Signatur ohne hinterlegten Schlüssel kann nicht geprüft werden');
|
|
$check(!theme_catalog_install('gibtesnicht')['ok'], 'Theme außerhalb des Katalogs kann nicht installiert werden');
|
|
|
|
set_setting('plugin_publisher_key', $pub);
|
|
$r = theme_catalog_install('nordlicht');
|
|
$check($r['ok'] && $r['signed'] === true, 'mit Herausgeber-Schlüssel wird die Signatur geprüft');
|
|
$again = theme_catalog_install('nordlicht');
|
|
$check(!$again['ok'] && str_contains($again['error'], 'bereits'), 'ein bereits installiertes Theme lässt sich nicht noch einmal installieren');
|
|
$state = theme_catalog_state($served['themes'][0]);
|
|
$check($state['installed'] && !$state['update'] && $state['version'] === '1.2.0', 'Katalog erkennt das Theme als installiert (gleicher Name, gleiche Version)');
|
|
$check(!theme_catalog_state(['name' => 'Anderes Theme', 'version' => '1.0.0'])['installed'], 'ein nicht installiertes Theme wird nicht als installiert gezeigt');
|
|
$check(theme_catalog_state(['name' => 'Nordlicht', 'version' => '1.3.0'])['update'] === true, 'eine neuere Katalogversion wird als Update erkannt');
|
|
$themes = list_custom_themes();
|
|
$check(count($themes) === 1 && $themes[0]['name'] === 'Nordlicht' && is_file($themesDir . '/' . $themes[0]['id'] . '/theme.css'), 'Theme liegt im Theme-Ordner und wird aufgelistet');
|
|
$check($themes && $themes[0]['theme_version'] === '1.2.0' && $themes[0]['author'] === 'Studio', 'Version und Autor stammen aus theme.css');
|
|
$check(get_setting('active_custom_theme', '') === '', 'das Theme wird nicht automatisch aktiviert');
|
|
|
|
foreach (list_custom_themes() as $__t) delete_custom_theme($__t['id']);
|
|
$served['themes'][0]['signature'] = base64_encode(random_bytes(256));
|
|
$r = theme_catalog_install('nordlicht');
|
|
$check(!$r['ok'] && str_contains($r['error'], 'Signatur ist ungültig'), 'ungültige Signatur wird abgelehnt');
|
|
|
|
// Plugin-Signatur darf nicht als Theme-Signatur durchgehen
|
|
openssl_sign(plugin_signature_message('nordlicht', '1.2.0', $sha), $pluginSig, $priv, OPENSSL_ALGO_SHA256);
|
|
$served['themes'][0]['signature'] = base64_encode($pluginSig);
|
|
$check(!theme_catalog_install('nordlicht')['ok'], 'eine Plugin-Signatur gilt nicht für ein Theme');
|
|
|
|
$served['themes'][0]['signature'] = $sig;
|
|
$body = file_get_contents($zipPath) . 'x'; // Download wurde verändert
|
|
$r = theme_catalog_install('nordlicht');
|
|
$check(!$r['ok'] && str_contains($r['error'], 'Prüfsumme'), 'veränderter Download wird abgelehnt');
|
|
$body = file_get_contents($zipPath);
|
|
|
|
$served['themes'][0]['signature'] = '';
|
|
set_setting('plugin_require_signature', '1');
|
|
$r = theme_catalog_install('nordlicht');
|
|
$check(!$r['ok'] && str_contains($r['error'], 'müssen signiert sein'), '„Signatur erforderlich“ lehnt unsignierte Themes ab');
|
|
set_setting('plugin_require_signature', '0');
|
|
|
|
$served['themes'][0]['downloadUrl'] = 'https://192.168.1.5/x.zip';
|
|
$check(!theme_catalog_install('nordlicht')['ok'], 'Download von interner Adresse wird abgelehnt');
|
|
|
|
unset($GLOBALS['deskhub_http_get']);
|
|
$rm = function (string $d) use (&$rm) {
|
|
foreach (scandir($d) ?: [] as $e) { if ($e === '.' || $e === '..') continue; is_dir("$d/$e") ? $rm("$d/$e") : @unlink("$d/$e"); }
|
|
@rmdir($d);
|
|
};
|
|
$rm($themesDir);
|
|
@unlink($zipPath);
|
|
@unlink($cnf);
|
|
|
|
if ($failures) {
|
|
fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n");
|
|
exit(1);
|
|
}
|
|
echo "Theme catalog checks passed.\n";
|