Newer
Older
gnexus-auth-client-php / tests / Unit / Webhook / HmacWebhookVerifierTest.php
@Eugene Sukhodolskiy Eugene Sukhodolskiy 12 hours ago 2 KB Initial auth client package scaffold
<?php

declare(strict_types=1);

namespace GNexus\GAuth\Tests\Unit\Webhook;

use GNexus\GAuth\Config\GAuthConfig;
use GNexus\GAuth\Contract\ClockInterface;
use GNexus\GAuth\Exception\WebhookVerificationException;
use GNexus\GAuth\Webhook\HmacWebhookVerifier;
use PHPUnit\Framework\TestCase;

final class HmacWebhookVerifierTest extends TestCase
{
    public function testVerifiesValidSignature(): void
    {
        $clock = new class implements ClockInterface
        {
            public function now(): \DateTimeImmutable
            {
                return new \DateTimeImmutable('@1713900000');
            }
        };

        $verifier = new HmacWebhookVerifier(
            new GAuthConfig(
                baseUrl: 'https://auth.example.test',
                clientId: 'billing',
                clientSecret: 'secret',
                redirectUri: 'https://billing.example.test/callback',
                webhookToleranceSeconds: 10,
            ),
            $clock,
        );

        $body = '{"id":"evt_1","type":"webhook.test"}';
        $timestamp = '1713900000';
        $signature = hash_hmac('sha256', $timestamp . '.' . $body, 'whsec_test');

        $verified = $verifier->verify($body, [
            'X-GNexus-Event-Id' => 'evt_1',
            'X-GNexus-Event-Type' => 'webhook.test',
            'X-GNexus-Event-Timestamp' => $timestamp,
            'X-GNexus-Signature' => 't=' . $timestamp . ',v1=' . $signature,
        ], 'whsec_test');

        self::assertSame('evt_1', $verified->signatureId);
    }

    public function testRejectsTimestampOutsideTolerance(): void
    {
        $clock = new class implements ClockInterface
        {
            public function now(): \DateTimeImmutable
            {
                return new \DateTimeImmutable('@1713901000');
            }
        };

        $verifier = new HmacWebhookVerifier(
            new GAuthConfig(
                baseUrl: 'https://auth.example.test',
                clientId: 'billing',
                clientSecret: 'secret',
                redirectUri: 'https://billing.example.test/callback',
                webhookToleranceSeconds: 10,
            ),
            $clock,
        );

        $this->expectException(WebhookVerificationException::class);

        $body = '{"id":"evt_1","type":"webhook.test"}';
        $timestamp = '1713900000';
        $signature = hash_hmac('sha256', $timestamp . '.' . $body, 'whsec_test');

        $verifier->verify($body, [
            'X-GNexus-Event-Id' => 'evt_1',
            'X-GNexus-Event-Type' => 'webhook.test',
            'X-GNexus-Event-Timestamp' => $timestamp,
            'X-GNexus-Signature' => 't=' . $timestamp . ',v1=' . $signature,
        ], 'whsec_test');
    }
}