Files
urlshort-qr-gen/tests/CheckTokenTest.php
T
florian.wilde 8a7939bee2 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
2026-08-03 18:11:40 +02:00

90 lines
2.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests;
use App\Support\CheckToken;
use PHPUnit\Framework\TestCase;
final class CheckTokenTest extends TestCase
{
private const SECRET = 'a4f1c0d2e3b4a5968778695a4b3c2d1e0f1a2b3c4d5e6f708192a3b4c5d6e7f8';
public function testFreshTokenIsAccepted(): void
{
$token = CheckToken::create(self::SECRET);
self::assertTrue(CheckToken::isValid($token, self::SECRET));
}
public function testTokenOfAnotherInstallationIsRejected(): void
{
// Genau das beweist die Pruefung: nur wer das Geheimnis kennt,
// kann ein gueltiges Token erzeugen.
$token = CheckToken::create('ein-anderes-geheimnis');
self::assertFalse(CheckToken::isValid($token, self::SECRET));
}
public function testExpiredTokenIsRejected(): void
{
$now = 1_800_000_000;
$token = CheckToken::create(self::SECRET, $now);
self::assertTrue(CheckToken::isValid($token, self::SECRET, $now + CheckToken::LIFETIME - 1));
self::assertFalse(CheckToken::isValid($token, self::SECRET, $now + CheckToken::LIFETIME + 1));
}
public function testTokenFromTheFutureIsRejected(): void
{
$now = 1_800_000_000;
$token = CheckToken::create(self::SECRET, $now + 3600);
self::assertFalse(CheckToken::isValid($token, self::SECRET, $now));
}
/**
* @return array<string,array{0:string}>
*/
public static function malformedProvider(): array
{
return [
'leer' => [''],
'ohne Punkt' => ['1800000000'],
'ohne Signatur' => ['1800000000.'],
'Text statt Zeitstempel' => ['abc.def'],
'nur Signatur' => ['.abcdef'],
'negativer Zeitstempel' => ['-100.abcdef'],
'zu viele Teile' => ['1800000000.abc.def'],
];
}
/**
* @dataProvider malformedProvider
*/
public function testMalformedTokensAreRejected(string $token): void
{
self::assertFalse(CheckToken::isValid($token, self::SECRET));
}
public function testSignatureIsNotGuessable(): void
{
$now = 1_800_000_000;
$valid = CheckToken::create(self::SECRET, $now);
// Signatur um ein Zeichen veraendert.
$tampered = substr($valid, 0, -1) . (str_ends_with($valid, 'a') ? 'b' : 'a');
self::assertNotSame($valid, $tampered);
self::assertFalse(CheckToken::isValid($tampered, self::SECRET, $now));
}
public function testTokenContainsNoSecret(): void
{
$token = CheckToken::create(self::SECRET);
self::assertStringNotContainsString(self::SECRET, $token);
}
}