test: Testsuite fuer Kernlogik, QR-Codes, Domains und Sicherheit

232 Tests, unter anderem:
- Slug-Erzeugung, Kollisionsbehandlung und Validierung
- URL-Validierung inklusive IDN, Prozentkodierung und abgelehnter
  Protokolle; Punycode gegengeprueft gegen idn_to_ascii
- QR-Erzeugung in allen Groessen, mit Logo und Level-H-Automatik
- Weiterleitung gegen eine echte SQLite-Datenbank samt Domain-
  Aufloesung ueber den Host-Header
- Update einer bestehenden Installation auf mehrere Domains
- Angriffsseitig: gefaelschte Proxy-Header, Host-Header-Injektion,
  SVG mit Skripten, XXE und externen Referenzen
This commit is contained in:
2026-08-03 18:11:40 +02:00
parent 73a9bb09b1
commit 8a7939bee2
14 changed files with 2228 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace App\Tests;
use App\Support\ShortDomain;
use PHPUnit\Framework\TestCase;
final class ShortDomainTest extends TestCase
{
/**
* @return array<string,array{0:string,1:string}>
*/
public static function baseUrlProvider(): array
{
return [
'nur Host' => ['qr.example.de', 'https://qr.example.de'],
'mit https' => ['https://qr.example.de', 'https://qr.example.de'],
'mit http' => ['http://qr.example.de', 'http://qr.example.de'],
'Schraegstrich am Ende' => ['https://qr.example.de/', 'https://qr.example.de'],
'Leerraum' => [' qr.example.de ', 'https://qr.example.de'],
'Grossbuchstaben' => ['QR.Example.DE', 'https://qr.example.de'],
'mit Port' => ['localhost:8088', 'https://localhost:8088'],
'Unterverzeichnis' => ['https://example.de/kurz/', 'https://example.de/kurz'],
'Umlaut-Domain' => ['kürzer.de', 'https://kürzer.de'],
];
}
/**
* @dataProvider baseUrlProvider
*/
public function testNormalizeBaseUrl(string $input, string $expected): void
{
self::assertSame($expected, ShortDomain::normalizeBaseUrl($input));
}
/**
* @return array<string,array{0:string,1:string}>
*/
public static function hostProvider(): array
{
return [
'einfach' => ['https://qr.example.de', 'qr.example.de'],
'mit Port' => ['http://localhost:8088', 'localhost:8088'],
'mit Pfad' => ['https://example.de/kurz', 'example.de'],
'mit Benutzerinfo' => ['https://user@example.de/x', 'example.de'],
'ohne Schema' => ['example.de', ''],
];
}
/**
* @dataProvider hostProvider
*/
public function testHostOf(string $baseUrl, string $expected): void
{
self::assertSame($expected, ShortDomain::hostOf($baseUrl));
}
public function testNormalizeRequestHost(): void
{
self::assertSame('qr.example.de', ShortDomain::normalizeRequestHost('QR.Example.DE'));
self::assertSame('qr.example.de', ShortDomain::normalizeRequestHost('qr.example.de:443'));
self::assertSame('qr.example.de', ShortDomain::normalizeRequestHost('qr.example.de:80'));
self::assertSame('localhost:8088', ShortDomain::normalizeRequestHost('localhost:8088'));
self::assertSame('', ShortDomain::normalizeRequestHost(' '));
}
/**
* Host aus der Basis-URL und Host aus dem Request-Header muessen
* direkt vergleichbar sein - sonst greift die Zuordnung nicht.
*/
public function testHostOfAndRequestHostMatch(): void
{
foreach ([
'https://qr.example.de' => 'qr.example.de',
'http://localhost:8088' => 'localhost:8088',
'https://example.de/kurz' => 'example.de',
] as $baseUrl => $requestHost) {
self::assertSame(
ShortDomain::hostOf(ShortDomain::normalizeBaseUrl($baseUrl)),
ShortDomain::normalizeRequestHost($requestHost),
$baseUrl,
);
}
}
/**
* @return array<string,array{0:string,1:bool}>
*/
public static function validationProvider(): array
{
return [
'gueltig' => ['https://qr.example.de', true],
'mit Port' => ['http://localhost:8088', true],
'Unterverzeichnis' => ['https://example.de/kurz', true],
'interner Host' => ['http://intranet', true],
'leer' => ['', false],
'nur Schema' => ['https://', false],
'fremdes Schema' => ['ftp://example.de', false],
'javascript' => ['javascript:alert(1)', false],
'mit Query' => ['https://example.de?x=1', false],
'mit Fragment' => ['https://example.de#x', false],
'zu lang' => ['https://example.de/' . str_repeat('a', 300), false],
];
}
/**
* @dataProvider validationProvider
*/
public function testValidation(string $baseUrl, bool $expected): void
{
self::assertSame($expected, ShortDomain::validationError($baseUrl) === null, $baseUrl);
}
public function testDisplayNameHidesHttps(): void
{
self::assertSame('qr.example.de', ShortDomain::displayName('https://qr.example.de'));
self::assertSame('example.de/kurz', ShortDomain::displayName('https://example.de/kurz'));
// http wird bewusst angezeigt, damit man es bemerkt.
self::assertSame('http://localhost:8088', ShortDomain::displayName('http://localhost:8088'));
}
}