chore: complete update
This commit is contained in:
112
src/Framework/Http/RequestId.php
Normal file
112
src/Framework/Http/RequestId.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http;
|
||||
|
||||
/**
|
||||
* Repräsentiert eine kryptografisch sichere und signierte Request-ID.
|
||||
* Enthält sowohl die ID selbst als auch deren HMAC-Signatur zur Validierung.
|
||||
*/
|
||||
final readonly class RequestId
|
||||
{
|
||||
private string $id;
|
||||
private string $signature;
|
||||
private string $combined;
|
||||
|
||||
/**
|
||||
* Erstellt eine neue Request-ID oder parsed eine bestehende
|
||||
*
|
||||
* @param string|null $combined Wenn nicht null, wird diese ID validiert und verwendet
|
||||
* @param string $secret Das Secret für die HMAC-Signatur
|
||||
*/
|
||||
public function __construct(?string $combined = null, string $secret = '')
|
||||
{
|
||||
// Secret über eine Umgebungsvariable beziehen, falls nicht angegeben
|
||||
$secret = $secret ?: ($_ENV['APP_SECRET'] ?? 'default-secret-change-me');
|
||||
|
||||
if ($combined !== null && self::isValidFormat($combined)) {
|
||||
// Bestehende ID parsen
|
||||
[$rawId, $signature] = explode('.', $combined, 2);
|
||||
|
||||
// Signatur validieren
|
||||
$expectedSignature = $this->generateSignature($rawId, $secret);
|
||||
|
||||
if (!hash_equals($expectedSignature, $signature)) {
|
||||
// Bei ungültiger Signatur, neue ID erstellen
|
||||
$this->generateNew($secret);
|
||||
} else {
|
||||
// Bei gültiger Signatur, diese ID verwenden
|
||||
$this->id = $rawId;
|
||||
$this->signature = $signature;
|
||||
$this->combined = $combined;
|
||||
}
|
||||
} else {
|
||||
// Neue ID erstellen
|
||||
$this->generateNew($secret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert eine neue Request-ID mit Signatur
|
||||
*/
|
||||
private function generateNew(string $secret): void
|
||||
{
|
||||
// Zufällige ID generieren (16 Byte = 32 Hex-Zeichen)
|
||||
$this->id = bin2hex(random_bytes(16));
|
||||
|
||||
// Signatur erstellen
|
||||
$this->signature = $this->generateSignature($this->id, $secret);
|
||||
|
||||
// Kombinierte Darstellung erstellen
|
||||
$this->combined = $this->id . '.' . $this->signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert eine HMAC-Signatur für die ID
|
||||
*/
|
||||
private function generateSignature(string $id, string $secret): string
|
||||
{
|
||||
return hash_hmac('sha256', $id, $secret, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob eine kombinierte ID das korrekte Format hat
|
||||
*/
|
||||
private static function isValidFormat(string $combined): bool
|
||||
{
|
||||
// Format: 32 Hex-Zeichen + Punkt + 64 Hex-Zeichen (SHA-256 HMAC)
|
||||
return preg_match('/^[a-f0-9]{32}\.[a-f0-9]{64}$/i', $combined) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die kombinierte ID (ID + Signatur) zurück
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->combined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt nur die eigentliche ID ohne Signatur zurück
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Signatur zurück
|
||||
*/
|
||||
public function getSignature(): string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* String-Repräsentation für Debugging
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user