melden($body, $kopf['X-KantSites-Signatur'] ?? '', '203.0.113.7'); return ['status' => $antwort['status'], 'body' => $antwort['body'], 'signatur' => (string) $antwort['signatur']]; }; $installation = static function (string $wurzel, string $adresse, \Closure $senden): CmsZentrale { $db = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true]); $updater = new Updater($wurzel, 'sqlite:///:memory:', new CommandRunner(), $db); return new CmsZentrale($wurzel, $updater, new ArchiveUpdate($wurzel, $updater, new Backup($wurzel, 'sqlite:///:memory:', $wurzel.'/var/media', $db, new CommandRunner()), new Download()), 'https://sites.example', $adresse, 'sqlite:///x', $senden); }; $site = $installation($tmp.'/site', 'https://kunde-eins.de', $ueberApi); $erste = $site->melden(); $pruefe(null === $erste['auftrag'], 'Erste Meldung wird angenommen, kein Auftrag'); $zeile = $pdo->query('SELECT * FROM installation')->fetch(); $pruefe('kunde-eins.de' === ($zeile['domain'] ?? null) && '1.35.1' === $zeile['fassung'], 'Domain und Fassung stehen in der Zentrale'); $ich = json_decode((string) file_get_contents($tmp.'/site/var/zentrale.json'), true); $pruefe(true === $ich['registriert'], 'Installation gilt danach als angemeldet'); $bestand = new Zentrale\Bestand($pdo); $pruefe(null === $bestand->beauftragen($zeile['id'], '1.36.0'), 'Update auf 1.36.0 lässt sich beauftragen'); $zweite = $site->melden(); $pruefe('1.36.0' === ($zweite['auftrag']['fassung'] ?? null) && 'update' === $zweite['auftrag']['aktion'], 'Folgemeldung holt den Auftrag ab'); $pruefe(null === $site->melden()['auftrag'], 'Ein abgeholter Auftrag kommt nicht zweimal'); $pruefe(null !== $bestand->beauftragen($zeile['id'], '1.36.0'), 'Während ein Auftrag läuft, gibt es keinen zweiten'); $site->auftragAngenommen($zweite['auftrag']['id'], '1.36.0'); file_put_contents($tmp.'/site/VERSION', "1.36.0\n"); $site->auftragErledigt(true, 'Fassung 1.36.0 läuft.'); $site->melden(); $auftrag = $pdo->query('SELECT * FROM auftrag')->fetch(); $pruefe(1 === (int) $auftrag['ok'] && null !== $auftrag['erledigt'], 'Ergebnis kommt in der Zentrale an'); $pruefe('1.36.0' === $pdo->query('SELECT fassung FROM installation')->fetchColumn(), 'Neue Fassung ist gemeldet'); $pruefe(null === $site->offenerAuftrag(), 'Die Installation vergisst den quittierten Auftrag'); // Eine fremde Antwort: anderer Schlüssel unterschreibt. $gefaelscht = $installation($tmp.'/site', 'https://kunde-eins.de', static function (string $url, string $body) use ($ueberApi): array { $echt = $ueberApi($url, $body, []); return [...$echt, 'signatur' => hash_hmac('sha256', $echt['body'], str_repeat('b', 64))]; }); try { $gefaelscht->melden(); $pruefe(false, 'Unsignierte Meldung wird abgewiesen'); } catch (\RuntimeException $e) { $pruefe(str_contains($e->getMessage(), '403'), 'Meldung ohne gültige Unterschrift weist die Zentrale mit 403 ab'); } // Jemand übernimmt die Kennung mit eigenem Schlüssel. $body = json_encode(['id' => $zeile['id'], 'adresse' => 'https://fremd.de', 'fassung' => '1.36.0', 'schluessel' => str_repeat('c', 64)]); $fremd = $api->melden($body, hash_hmac('sha256', $body, str_repeat('c', 64)), '198.51.100.1'); $pruefe(403 === $fremd['status'], 'Fremder Schlüssel für eine bekannte Kennung wird abgewiesen'); // Die Zentrale hat die Installation vergessen: Sie meldet sich mit Schlüssel neu an. $pdo->exec('DELETE FROM installation'); $site->melden(); $pruefe(1 === (int) $pdo->query('SELECT COUNT(*) FROM installation')->fetchColumn(), 'Nach Verlust in der Zentrale meldet sich die Installation neu an'); // Umzug: dieselbe Kennung, andere Domain. $umzug = $installation($tmp.'/site', 'https://www.kunde-zwei.de', $ueberApi); $umzug->melden(); $neu = $pdo->query('SELECT domain, domain_vorher FROM installation')->fetch(); $pruefe('www.kunde-zwei.de' === $neu['domain'] && 'kunde-eins.de' === $neu['domain_vorher'], 'Domainwechsel ist sichtbar'); echo $fehler > 0 ? "\n{$fehler} Prüfung(en) fehlgeschlagen.\n" : "\nAlle Prüfungen bestanden.\n"; exit($fehler > 0 ? 1 : 0);