Set the site address in the administration, checked against the installation itself
- System > This installation > Address has a field and a link to the other spelling (with or without www), like the WordPress address. It writes SITE_ORIGIN to .env through Environment::write and takes effect on the next request. With SITE_ORIGIN from the server environment there is no field, and a POST is refused. - Before saving, OriginCheck requests /.well-known/kantsites-origin under the new address; it has to return an HMAC of APP_SECRET that only this installation knows. Switching to www without DNS or certificate would otherwise send every page, the administration included, nowhere. "Save anyway" appears only after a refusal. The probe also answers during maintenance. - The message says when the administration changes host and needs a new sign-in, since the session cookie belongs to one spelling. Tests: 584 PHPUnit on PHP 8.2 and 8.4, 35 node, test:editor and test:browser green (test:browser reports only the known editor colour contrast on /grundlagen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e21e800f2c
commit
3b1dfc0948
10 files changed
+238
-7
No files matched your search
@@ -14,6 +14,7 @@ use App\Ops\ArchiveUpdate;
|
||||
use App\Ops\Backup;
|
||||
use App\Ops\CommandRunner;
|
||||
use App\Ops\Download;
|
||||
use App\Ops\OriginCheck;
|
||||
use App\Ops\Updater;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
@@ -133,7 +134,7 @@ final class SystemScreenTest extends WebTestCase
|
||||
$html = (string) $client->getResponse()->getContent();
|
||||
self::assertStringContainsString('https://cms.test', $html);
|
||||
self::assertStringContainsString('läuft gerade unter <code>localhost</code>', $html);
|
||||
self::assertStringContainsString('cms:site:origin', $html, 'Der Weg, es zu aendern, steht dabei.');
|
||||
self::assertStringContainsString('Stimmt die nicht mehr, unten ändern.', $html);
|
||||
|
||||
// Unter der eingetragenen Adresse selbst: kein Hinweis, dafuer die Richtung der Umleitung.
|
||||
$client->request('GET', 'https://cms.test/admin/login');
|
||||
@@ -149,6 +150,85 @@ final class SystemScreenTest extends WebTestCase
|
||||
self::assertSame('https://cms.test/admin/system', $client->getResponse()->headers->get('Location'));
|
||||
}
|
||||
|
||||
public function testTheAddressIsSetInTheAdministrationButOnlyWhereItReallyArrives(): void
|
||||
{
|
||||
// Umut: „bau die Einstellung in der Verwaltung ein sodass es in die env eingetragen wird“ -
|
||||
// wie die WordPress-Adresse. Im Test kommt SITE_ORIGIN aus der Server-Umgebung; dort hat
|
||||
// sie Vorrang, also gibt es kein Feld, und auch ein POST ändert nichts.
|
||||
$client = $this->login();
|
||||
$client->request('GET', '/admin/system');
|
||||
$html = (string) $client->getResponse()->getContent();
|
||||
self::assertStringContainsString('lässt sich nur beim Hoster ändern', $html);
|
||||
self::assertStringNotContainsString('name="origin"', $html);
|
||||
$token = (string) $client->getCrawler()->filter('form[action$="/system/wartung"] input[name=_csrf_token]')->attr('value');
|
||||
$client->request('POST', '/admin/system/adresse', ['_csrf_token' => $token, 'origin' => 'https://www.cms.test']);
|
||||
$client->followRedirect();
|
||||
self::assertStringContainsString('in der Server-Umgebung gesetzt', (string) $client->getResponse()->getContent());
|
||||
|
||||
// Steht sie in .env, gibt es das Feld samt Umschalter auf die andere Schreibweise.
|
||||
$geladen = $_SERVER['SYMFONY_DOTENV_VARS'] ?? null;
|
||||
$_SERVER['SYMFONY_DOTENV_VARS'] = 'SITE_ORIGIN';
|
||||
try {
|
||||
$client->request('GET', '/admin/system');
|
||||
$html = (string) $client->getResponse()->getContent();
|
||||
self::assertStringContainsString('name="origin" type="url"', $html);
|
||||
self::assertStringContainsString('value="https://www.cms.test" formnovalidate>www.cms.test</button>', $html);
|
||||
|
||||
// Eine Adresse, unter der diese Website nicht antwortet, wird nicht gespeichert - sonst
|
||||
// leitete die andere Schreibweise ins Leere. Das Feld behält sie, und erst jetzt
|
||||
// erscheint „Trotzdem übernehmen“.
|
||||
$client->request('POST', '/admin/system/adresse', ['_csrf_token' => $token, 'origin' => 'https://kein-server.invalid/']);
|
||||
$client->followRedirect();
|
||||
$html = (string) $client->getResponse()->getContent();
|
||||
self::assertStringContainsString('Unter https://kein-server.invalid antwortet diese Website nicht', $html);
|
||||
self::assertStringContainsString('Nichts geändert.', $html);
|
||||
self::assertStringContainsString('value="https://kein-server.invalid"', $html);
|
||||
self::assertStringContainsString('name="force"', $html);
|
||||
foreach (['https://cms.test/start' => 'ohne Pfad', 'ftp://cms.test' => 'beginnt mit https://'] as $falsch => $meldung) {
|
||||
$client->request('POST', '/admin/system/adresse', ['_csrf_token' => $token, 'origin' => $falsch]);
|
||||
$client->followRedirect();
|
||||
self::assertStringContainsString($meldung, (string) $client->getResponse()->getContent());
|
||||
}
|
||||
} finally {
|
||||
if (null === $geladen) {
|
||||
unset($_SERVER['SYMFONY_DOTENV_VARS']);
|
||||
} else {
|
||||
$_SERVER['SYMFONY_DOTENV_VARS'] = $geladen;
|
||||
}
|
||||
}
|
||||
self::assertStringContainsString('SITE_ORIGIN', (string) file_get_contents(dirname(__DIR__).'/.env'));
|
||||
self::assertStringNotContainsString('kein-server', (string) file_get_contents(dirname(__DIR__).'/.env'));
|
||||
|
||||
// Die Gegenstelle der Prüfung: öffentlich, ohne Anmeldung, und nur die Kennung.
|
||||
$client->request('GET', '/.well-known/kantsites-origin');
|
||||
self::assertSame(200, $client->getResponse()->getStatusCode());
|
||||
self::assertSame(hash_hmac('sha256', 'site-origin', 'isolated-test-secret'), $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testTheAddressCheckWantsThisInstallationsOwnAnswer(): void
|
||||
{
|
||||
$antwort = null;
|
||||
$download = new class($antwort) extends Download {
|
||||
public function __construct(private ?string &$antwort)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function get(string $url): ?string
|
||||
{
|
||||
return $this->antwort;
|
||||
}
|
||||
};
|
||||
$check = new OriginCheck('geheim', $download);
|
||||
self::assertStringContainsString('antwortet diese Website nicht', (string) $check->problem('https://www.example.de'));
|
||||
$antwort = hash_hmac('sha256', 'site-origin', 'anderes-geheimnis');
|
||||
self::assertStringContainsString('antwortet eine andere Website', (string) $check->problem('https://www.example.de'));
|
||||
$antwort = $check->token().'
|
||||
';
|
||||
self::assertNull($check->problem('https://www.example.de'));
|
||||
self::assertStringContainsString('nur HTTPS', (string) $check->problem('http://www.example.de'));
|
||||
}
|
||||
|
||||
public function testTheScreenShowsWhatTheArchiveUpdaterDidInsteadOfDyingOnIt(): void
|
||||
{
|
||||
// Der Fehler, den Umut auf seinem Hosting gesehen hat: Das Update lief, legte seine
|
||||
|
||||
Reference in new issue
Block a user