Files
kaffeekasse-saas/scripts/check-analytics-relay.php

132 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../app/analytics-relay.php';
$failures = 0;
$assert = static function (string $label, bool $condition) use (&$failures): void {
if ($condition) {
echo "OK: {$label}\n";
return;
}
$failures++;
echo "FEHLER: {$label}\n";
};
$environmentNames = [
'APP_ENV',
'APP_HOST',
'APP_MARKETING_URL',
'MATOMO_URL',
'MATOMO_SITE_ID',
'MATOMO_CONSENT_COOKIE_DOMAIN',
'MATOMO_PRIVACY_CONFIRMED',
];
$previousEnvironment = [];
foreach ($environmentNames as $name) {
$previousEnvironment[$name] = getenv($name);
}
putenv('APP_ENV=dev');
putenv('APP_HOST=app.example.test');
putenv('APP_MARKETING_URL=http://example.test:8765');
putenv('MATOMO_URL=http://analytics.example.test/');
putenv('MATOMO_SITE_ID=7');
putenv('MATOMO_CONSENT_COOKIE_DOMAIN=.example.test');
putenv('MATOMO_PRIVACY_CONFIRMED=1');
$visitorId = '0123456789abcdef';
$cookies = [
APP_ANALYTICS_CONSENT_COOKIE => APP_ANALYTICS_CONSENT_VERSION . ':granted',
APP_ANALYTICS_VISITOR_COOKIE => $visitorId,
];
$server = [
'HTTP_HOST' => 'example.test:8765',
'HTTP_ORIGIN' => 'http://example.test:8765',
'HTTP_SEC_FETCH_SITE' => 'same-origin',
'SERVER_PORT' => '8765',
'HTTP_USER_AGENT' => 'Relay-Testbrowser/1.0',
'REMOTE_ADDR' => '203.0.113.42',
];
$payload = [
'visitorId' => $visitorId,
'pageUrl' => 'http://example.test:8765/passwort-zuruecksetzen.php?token=GEHEIM#formular',
'pageTitle' => 'Kaffeeliste Passwort zurücksetzen',
'referrerUrl' => 'http://app.example.test/login.php?source=GEHEIM',
'resolution' => '1440x900',
'language' => 'de-DE',
'h' => 12,
'm' => 34,
's' => 56,
];
$parameters = app_matomo_page_view_parameters($payload, $server, $cookies);
$assert('Seiten-URL verliert Query und Fragment',
($parameters['url'] ?? '') === 'http://example.test:8765/passwort-zuruecksetzen.php');
$assert('Interner Referrer verliert Query und Fragment',
($parameters['urlref'] ?? '') === 'http://app.example.test/login.php');
$assert('Zufällige Besucherkennung wird unverändert genutzt', ($parameters['_id'] ?? '') === $visitorId);
$assert('Browserdaten werden auf erlaubte Angaben begrenzt',
($parameters['res'] ?? '') === '1440x900'
&& ($parameters['lang'] ?? '') === 'de-DE'
&& ($parameters['ua'] ?? '') === 'Relay-Testbrowser/1.0');
$assert('Client-IP wird nicht an Matomo übergeben',
!array_key_exists('cip', $parameters)
&& !in_array('203.0.113.42', $parameters, true));
$capturedUrl = '';
$capturedParameters = [];
$forwardResult = app_matomo_forward_page_view(
$parameters,
static function (string $url, array $values) use (&$capturedUrl, &$capturedParameters): array {
$capturedUrl = $url;
$capturedParameters = $values;
return ['ok' => true, 'status' => 204, 'error' => null];
}
);
$assert('Relay verwendet den fest konfigurierten Matomo-Endpunkt',
$forwardResult['ok']
&& $capturedUrl === 'http://analytics.example.test/matomo.php'
&& ($capturedParameters['idsite'] ?? '') === '7');
$mustReject = static function (array $changedPayload, array $changedServer, array $changedCookies): bool {
try {
app_matomo_page_view_parameters($changedPayload, $changedServer, $changedCookies);
return false;
} catch (Throwable) {
return true;
}
};
$deniedCookies = $cookies;
$deniedCookies[APP_ANALYTICS_CONSENT_COOKIE] = APP_ANALYTICS_CONSENT_VERSION . ':denied';
$assert('Ohne Einwilligung wird der Aufruf verworfen', $mustReject($payload, $server, $deniedCookies));
$foreignServer = $server;
$foreignServer['HTTP_ORIGIN'] = 'https://evil.example';
$foreignServer['HTTP_SEC_FETCH_SITE'] = 'cross-site';
$assert('Fremder Ursprung wird verworfen', $mustReject($payload, $foreignServer, $cookies));
$foreignPage = $payload;
$foreignPage['pageUrl'] = 'https://evil.example/gestohlen?token=1';
$assert('Fremde Seiten-URL wird verworfen', $mustReject($foreignPage, $server, $cookies));
$wrongVisitor = $payload;
$wrongVisitor['visitorId'] = 'fedcba9876543210';
$assert('Nicht zum Cookie passende Besucherkennung wird verworfen', $mustReject($wrongVisitor, $server, $cookies));
$relaySource = file_get_contents(APP_ROOT . '/app/analytics-relay.php') ?: '';
$assert('Relay-Code liest die Client-IP nicht', !str_contains($relaySource, "['REMOTE_ADDR']"));
foreach ($previousEnvironment as $name => $value) {
$value === false ? putenv($name) : putenv($name . '=' . $value);
}
if ($failures > 0) {
echo "\n{$failures} Relay-Prüfung(en) fehlgeschlagen.\n";
exit(1);
}
echo "\nFirst-Party-Matomo-Relay: alle Prüfungen bestanden.\n";