63 lines
2.0 KiB
PHP
63 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\PayPal;
|
|
|
|
use App\Services\PayPal\Exceptions\PayPalException;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class PayPalWebhookVerifier
|
|
{
|
|
public function __construct(private readonly PayPalClient $client) {}
|
|
|
|
/**
|
|
* @param array<string, mixed> $payload
|
|
*/
|
|
public function verify(Request $request, array $payload): bool
|
|
{
|
|
$webhookId = config('services.paypal.webhook_id');
|
|
|
|
if (! is_string($webhookId) || $webhookId === '') {
|
|
if (app()->environment('production')) {
|
|
Log::warning('PayPal webhook verification skipped: webhook id missing.');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
$signature = (string) $request->headers->get('PAYPAL-TRANSMISSION-SIG', '');
|
|
|
|
if ($signature === '') {
|
|
Log::warning('PayPal webhook missing signature header.', [
|
|
'header' => 'PAYPAL-TRANSMISSION-SIG',
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
|
|
$payload = array_filter([
|
|
'auth_algo' => $request->headers->get('PAYPAL-AUTH-ALGO'),
|
|
'cert_url' => $request->headers->get('PAYPAL-CERT-URL'),
|
|
'transmission_id' => $request->headers->get('PAYPAL-TRANSMISSION-ID'),
|
|
'transmission_sig' => $signature,
|
|
'transmission_time' => $request->headers->get('PAYPAL-TRANSMISSION-TIME'),
|
|
'webhook_id' => $webhookId,
|
|
'webhook_event' => $payload,
|
|
], static fn ($value) => $value !== null && $value !== '');
|
|
|
|
try {
|
|
$response = $this->client->post('/v1/notifications/verify-webhook-signature', $payload);
|
|
} catch (PayPalException $exception) {
|
|
Log::warning('PayPal webhook verification failed', [
|
|
'message' => $exception->getMessage(),
|
|
'status' => $exception->status(),
|
|
'context' => $exception->context(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
|
|
return strtoupper((string) ($response['verification_status'] ?? '')) === 'SUCCESS';
|
|
}
|
|
}
|