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:
@@ -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'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user