Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,150 @@
<?php
declare(strict_types=1);
namespace App\Framework\Security\RequestSigning;
use App\Framework\Http\Request;
/**
* Verifies HTTP request signatures
*/
final readonly class RequestVerifier
{
public function __construct(
private SigningKeyRepository $keyRepository,
) {
}
/**
* Verify a request signature
*/
public function verify(Request $request): VerificationResult
{
try {
// Extract signature from header
$signatureHeader = $request->headers->getFirst('Signature');
if ($signatureHeader === null) {
return VerificationResult::failure('Missing Signature header');
}
$signature = RequestSignature::fromHttpSignatureHeader($signatureHeader);
// Check if signature is expired
if ($signature->isExpired()) {
return VerificationResult::failure('Signature has expired');
}
// Get signing key
$key = $this->keyRepository->findByKeyId($signature->keyId);
if ($key === null) {
return VerificationResult::failure('Unknown key ID: ' . $signature->keyId);
}
if (! $key->isValid()) {
return VerificationResult::failure('Signing key is not valid');
}
// Verify algorithm matches
if ($key->algorithm !== $signature->algorithm) {
return VerificationResult::failure('Algorithm mismatch');
}
// Build signing string
$signingString = new SigningString($request);
$stringToSign = $signingString->build($signature->headers);
// Verify signature
$isValid = $this->verifySignature($stringToSign, $signature->signature, $key);
if ($isValid) {
return VerificationResult::success($signature, $key);
} else {
return VerificationResult::failure('Invalid signature');
}
} catch (\Exception $e) {
return VerificationResult::failure('Signature verification error: ' . $e->getMessage());
}
}
/**
* Verify signature using the appropriate algorithm
*/
private function verifySignature(string $data, string $signature, SigningKey $key): bool
{
return match ($key->algorithm) {
SigningAlgorithm::HMAC_SHA256 => $this->verifyHmacSignature($data, $signature, $key, 'sha256'),
SigningAlgorithm::HMAC_SHA512 => $this->verifyHmacSignature($data, $signature, $key, 'sha512'),
SigningAlgorithm::RSA_SHA256 => $this->verifyRsaSignature($data, $signature, $key),
SigningAlgorithm::ED25519 => throw new \InvalidArgumentException('ED25519 not yet implemented'),
};
}
/**
* Verify HMAC signature
*/
private function verifyHmacSignature(string $data, string $signature, SigningKey $key, string $algorithm): bool
{
$expectedSignature = hash_hmac($algorithm, $data, $key->keyMaterial, true);
$expectedSignatureBase64 = base64_encode($expectedSignature);
return hash_equals($expectedSignatureBase64, $signature);
}
/**
* Verify RSA signature
*/
private function verifyRsaSignature(string $data, string $signature, SigningKey $key): bool
{
// Extract public key from private key
$privateKey = openssl_pkey_get_private($key->keyMaterial);
if ($privateKey === false) {
return false;
}
$keyDetails = openssl_pkey_get_details($privateKey);
if ($keyDetails === false || ! isset($keyDetails['key'])) {
return false;
}
$publicKey = openssl_pkey_get_public($keyDetails['key']);
if ($publicKey === false) {
return false;
}
$signatureBinary = base64_decode($signature);
if ($signatureBinary === false) {
return false;
}
$result = openssl_verify($data, $signatureBinary, $publicKey, $key->algorithm->getOpenSSLSignatureAlgorithm());
return $result === 1;
}
/**
* Verify digest header if present
*/
public function verifyDigest(Request $request): bool
{
$digestHeader = $request->headers->getFirst('Digest');
if ($digestHeader === null) {
return true; // No digest to verify
}
$body = $request->body;
// Parse digest header: "SHA256=base64hash"
if (! preg_match('/^([A-Z0-9]+)=(.+)$/', $digestHeader, $matches)) {
return false;
}
$algorithm = strtolower($matches[1]);
$expectedHash = $matches[2];
$actualHash = base64_encode(hash($algorithm, $body, true));
return hash_equals($expectedHash, $actualHash);
}
}