67 lines
2.9 KiB
PHP
67 lines
2.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Test 75: Analyse-Skript für die Nextcloud-Verbindung (scripts/analyse-nextcloud.sh).
|
||
*
|
||
* Das Skript ist ein Diagnosewerkzeug für den Produktivbetrieb. Es muss
|
||
* ausführbar und syntaktisch gültig sein und darf ausschließlich lesen –
|
||
* ein versehentlich ergänzter MOVE/DELETE oder ein Aufruf des Importlaufs
|
||
* würde bei der Fehlersuche Belege verschieben oder löschen.
|
||
*/
|
||
class AnalyseNextcloudSkriptTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 75: Analyse-Skript Nextcloud-Verbindung';
|
||
|
||
public function run(): void
|
||
{
|
||
$path = dirname(__DIR__) . '/scripts/analyse-nextcloud.sh';
|
||
|
||
$this->assert(file_exists($path), 'scripts/analyse-nextcloud.sh existiert');
|
||
$this->assert(is_executable($path), 'scripts/analyse-nextcloud.sh ist ausführbar');
|
||
|
||
exec('bash -n ' . escapeshellarg($path) . ' 2>&1', $output, $exitCode);
|
||
$this->assertEquals(0, $exitCode, 'bash-Syntax ist gültig (' . implode(' ', $output) . ')');
|
||
|
||
$content = (string)file_get_contents($path);
|
||
|
||
// Rein lesend: keine schreibenden WebDAV-Methoden, kein Importlauf.
|
||
foreach (['MOVE', 'DELETE', 'PUT', 'MKCOL'] as $method) {
|
||
$this->assert(
|
||
!str_contains($content, "'" . $method . "'") && !str_contains($content, '"' . $method . '"'),
|
||
'Skript verwendet keine schreibende WebDAV-Methode ' . $method
|
||
);
|
||
}
|
||
|
||
// Verweise auf NextcloudImportService im Kommentar sind erwünscht (die cURL-Optionen
|
||
// müssen dort synchron gehalten werden) – ausgeführt werden darf der Import nicht.
|
||
$this->assert(
|
||
!str_contains($content, 'nextcloud-import.php') && !str_contains($content, 'new NextcloudImportService'),
|
||
'Skript startet keinen Importlauf'
|
||
);
|
||
|
||
// Das Passwort dient ausschließlich als cURL-Zugangsdatum. In Ausgaben darf
|
||
// es nur als Länge (strlen) auftauchen, nie im Klartext.
|
||
foreach (explode("\n", $content) as $index => $line) {
|
||
if (!str_contains($line, '$pass') || !preg_match('/\b(echo|print|printf|sprintf|print_r|var_export)\b/', $line)) {
|
||
continue;
|
||
}
|
||
$this->assert(
|
||
!str_contains(str_replace('strlen($pass)', '', $line), '$pass'),
|
||
'Passwort erscheint in Ausgabe-Zeile ' . ($index + 1) . ' höchstens als Länge'
|
||
);
|
||
}
|
||
|
||
// Die Analyse muss den echten SSRF-/Pinning-Pfad verwenden, sonst prüft sie
|
||
// etwas anderes als der Importlauf.
|
||
$this->assert(
|
||
str_contains($content, 'SsrfGuard::resolvePinned'),
|
||
'Skript prüft das IP-Pinning über SsrfGuard::resolvePinned()'
|
||
);
|
||
$this->assert(
|
||
str_contains($content, 'PROPFIND'),
|
||
'Skript unternimmt einen PROPFIND-Verbindungsversuch'
|
||
);
|
||
}
|
||
}
|