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
124 lines
4.5 KiB
PHP
124 lines
4.5 KiB
PHP
<?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'));
|
|
}
|
|
}
|