Save consent without reloading the page
consent.js posts the consent form in the background, the server answers 204 with the cookie, and the script swaps in the embeds and the legal line from a fresh copy of the page. Embed hosts are in frame-src from the start, the content address still only after consent. Without JavaScript the form keeps working with a reload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6390c00876
commit
6fa303f901
8 files changed
+198
-24
No files matched your search
+35
-5
@@ -4546,8 +4546,10 @@ Achern']);
|
||||
self::assertStringContainsString('value="all"', $html);
|
||||
self::assertStringContainsString('value="none"', $html);
|
||||
self::assertStringContainsString('/datenschutz', $html);
|
||||
// No script anywhere: the strict policy stays as it is.
|
||||
self::assertStringContainsString("script-src 'none'", (string) $response->headers->get('Content-Security-Policy'));
|
||||
// Seit ADR 115 kommt consent.js dazu, solange die Frage offen ist - als Datei von hier,
|
||||
// nie inline. Ohne Skript bleibt das Formular mit Weiterleitung.
|
||||
self::assertStringContainsString('<script src="/assets/consent.js?v=', $html);
|
||||
self::assertStringContainsString("script-src 'self'", (string) $response->headers->get('Content-Security-Policy'));
|
||||
|
||||
$saved = $this->request('/einwilligung', 'POST', ['choice' => 'all', 'back' => '/']);
|
||||
self::assertSame(302, $saved->getStatusCode());
|
||||
@@ -4561,6 +4563,9 @@ Achern']);
|
||||
// With a decision in hand the banner is gone, but the way back to it is not.
|
||||
$decided = $this->request('/', 'GET', [], [Consent::COOKIE => (string) $cookie->getValue()]);
|
||||
self::assertStringNotContainsString('consent-bar', $decided->getContent());
|
||||
// Nichts mehr offen: kein Skript, die Richtlinie wieder streng.
|
||||
self::assertStringNotContainsString('consent.js', $decided->getContent());
|
||||
self::assertStringContainsString("script-src 'none'", (string) $decided->headers->get('Content-Security-Policy'));
|
||||
self::assertStringContainsString('/einwilligung', $decided->getContent());
|
||||
self::assertSame(200, $this->request('/einwilligung', 'GET', [], [Consent::COOKIE => (string) $cookie->getValue()])->getStatusCode());
|
||||
}
|
||||
@@ -4601,10 +4606,35 @@ Achern']);
|
||||
self::assertStringNotContainsString('<iframe', $html);
|
||||
self::assertStringNotContainsString('karten.example/einbetten', $html);
|
||||
self::assertStringContainsString('OpenStreetMap', $html, 'The placeholder names the provider.');
|
||||
self::assertStringContainsString("frame-src 'none'", $policy);
|
||||
// Die Erlaubnis steht schon in der Richtlinie (ADR 115): consent.js setzt den Rahmen
|
||||
// nach der Einwilligung ohne Neuladen ein, und eine Richtlinie ändert sich danach nicht
|
||||
// mehr. Geladen wird dadurch nichts - es gibt keinen Rahmen und keine Adresse.
|
||||
self::assertStringContainsString('frame-src https://karten.example', $policy);
|
||||
self::assertStringContainsString('<script src="/assets/consent.js?v=', $html);
|
||||
}
|
||||
}
|
||||
|
||||
public function testTheConsentScriptSavesWithoutARedirect(): void
|
||||
{
|
||||
$this->askConsent();
|
||||
|
||||
// consent.js kennzeichnet seine Anfrage; dann gibt es das Cookie ohne Weiterleitung.
|
||||
$saved = $this->request('/einwilligung', 'POST', ['choice' => 'all', 'back' => '/'], [], ['HTTP_X_KANT_CONSENT' => '1']);
|
||||
self::assertSame(204, $saved->getStatusCode());
|
||||
self::assertNull($saved->headers->get('Location'));
|
||||
self::assertSame('', $saved->getContent());
|
||||
$cookie = $saved->headers->getCookies()[0];
|
||||
self::assertSame(Consent::COOKIE, $cookie->getName());
|
||||
self::assertStringContainsString('external', (string) $cookie->getValue());
|
||||
|
||||
// Von einer fremden Website bleibt es bei der Antwort ohne Cookie, wie beim Formular.
|
||||
$fremd = $this->request('/einwilligung', 'POST', ['choice' => 'all'], [], ['HTTP_X_KANT_CONSENT' => '1', 'HTTP_SEC_FETCH_SITE' => 'cross-site']);
|
||||
self::assertSame([], $fremd->headers->getCookies());
|
||||
|
||||
// Ohne die Kopfzeile bleibt alles beim Alten: Weiterleitung zurück.
|
||||
self::assertSame(302, $this->request('/einwilligung', 'POST', ['choice' => 'none', 'back' => '/'])->getStatusCode());
|
||||
}
|
||||
|
||||
public function testTheEmbedButtonGrantsOnlyItsOwnGroupAndKeepsWhatWasGrantedBefore(): void
|
||||
{
|
||||
$document = DemoContent::starter('Mit Karte');
|
||||
@@ -4713,7 +4743,7 @@ Achern']);
|
||||
}
|
||||
}
|
||||
|
||||
private function request(string $url, string $method = 'GET', array $body = [], array $cookies = []): Response
|
||||
private function request(string $url, string $method = 'GET', array $body = [], array $cookies = [], array $server = []): Response
|
||||
{
|
||||
$previous = [];
|
||||
foreach (['APP_SECRET' => 'test-only', 'DATABASE_URL' => 'sqlite:///'.str_replace('\\', '/', $this->path), 'SITE_ORIGIN' => 'https://cms.test', 'MEDIA_DIRECTORY' => $this->path.'-media', 'FONT_DIRECTORY' => $this->path.'-fonts', 'ASSET_DIRECTORY' => $this->path.'-assets'] as $key => $value) {
|
||||
@@ -4722,7 +4752,7 @@ Achern']);
|
||||
}
|
||||
$kernel = new Kernel('test', false);
|
||||
try {
|
||||
$request = Request::create($url, $method, $body, $cookies);
|
||||
$request = Request::create($url, $method, $body, $cookies, [], $server);
|
||||
$response = $kernel->handle($request);
|
||||
// Counting happens on kernel.terminate, so a test that does not terminate would
|
||||
// silently test a different application than the one that runs.
|
||||
|
||||
Reference in new issue
Block a user