169 lines
3.6 KiB
PHP
169 lines
3.6 KiB
PHP
<?php
|
|
/**
|
|
* Webhook Validator
|
|
*
|
|
* @link https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature_post
|
|
*
|
|
* @package easy-digital-downloads
|
|
* @subpackage Gateways\PayPal\Webhooks
|
|
* @copyright Copyright (c) 2021, Sandhills Development, LLC
|
|
* @license GPL2+
|
|
* @since 2.11
|
|
*/
|
|
|
|
namespace EDD\Gateways\PayPal\Webhooks;
|
|
|
|
use EDD\Gateways\PayPal\API;
|
|
use EDD\Gateways\PayPal\Exceptions\API_Exception;
|
|
|
|
class Webhook_Validator {
|
|
|
|
/**
|
|
* Headers from the webhook
|
|
*
|
|
* @var array
|
|
* @since 2.11
|
|
*/
|
|
private $headers;
|
|
|
|
/**
|
|
* Webhook event
|
|
*
|
|
* @var object
|
|
* @since 2.11
|
|
*/
|
|
private $event;
|
|
|
|
/**
|
|
* Maps the incoming header key to the outgoing API request key.
|
|
*
|
|
* @var string[]
|
|
* @since 2.11
|
|
*/
|
|
private $header_map = array(
|
|
'PAYPAL-AUTH-ALGO' => 'auth_algo',
|
|
'PAYPAL-CERT-URL' => 'cert_url',
|
|
'PAYPAL-TRANSMISSION-ID' => 'transmission_id',
|
|
'PAYPAL-TRANSMISSION-SIG' => 'transmission_sig',
|
|
'PAYPAL-TRANSMISSION-TIME' => 'transmission_time'
|
|
);
|
|
|
|
/**
|
|
* Webhook_Validator constructor.
|
|
*
|
|
* @param array $headers
|
|
* @param object $event
|
|
*
|
|
* @since 2.11
|
|
*/
|
|
public function __construct( $headers, $event ) {
|
|
$this->headers = array_change_key_case( $headers, CASE_UPPER );
|
|
$this->event = $event;
|
|
}
|
|
|
|
/**
|
|
* Verifies the signature.
|
|
*
|
|
* @since 2.11
|
|
* @return true
|
|
* @throws API_Exception
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function verify_signature() {
|
|
$api = new API();
|
|
|
|
$response = $api->make_request( 'v1/notifications/verify-webhook-signature', $this->get_body() );
|
|
|
|
if ( 200 !== $api->last_response_code ) {
|
|
throw new API_Exception( sprintf(
|
|
'Invalid response code: %d. Response: %s',
|
|
$api->last_response_code,
|
|
json_encode( $response )
|
|
) );
|
|
}
|
|
|
|
if ( empty( $response->verification_status ) || 'SUCCESS' !== strtoupper( $response->verification_status ) ) {
|
|
throw new API_Exception( sprintf(
|
|
'Verification failure. Response: %s',
|
|
json_encode( $response )
|
|
) );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Validates that we have all the required headers.
|
|
*
|
|
* @since 2.11
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
private function validate_headers() {
|
|
foreach ( array_keys( $this->header_map ) as $required_key ) {
|
|
if ( ! array_key_exists( $required_key, $this->headers ) ) {
|
|
throw new \InvalidArgumentException( sprintf(
|
|
'Missing PayPal header %s',
|
|
$required_key
|
|
) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the webhook ID for the current mode.
|
|
*
|
|
* @since 2.11
|
|
* @return string
|
|
* @throws \Exception
|
|
*/
|
|
private function get_webhook_id() {
|
|
$id = get_webhook_id();
|
|
|
|
if ( empty( $id ) ) {
|
|
throw new \Exception( 'No webhook created in current mode.' );
|
|
}
|
|
|
|
return $id;
|
|
}
|
|
|
|
/**
|
|
* Builds arguments for the body of the API request.
|
|
*
|
|
* @return array
|
|
* @throws \InvalidArgumentException
|
|
* @throws \Exception
|
|
*/
|
|
private function get_body() {
|
|
$this->validate_headers();
|
|
|
|
$body = array(
|
|
'webhook_id' => $this->get_webhook_id(),
|
|
'webhook_event' => $this->event
|
|
);
|
|
|
|
// Add arguments from the headers.
|
|
foreach ( $this->header_map as $header_key => $body_key ) {
|
|
$body[ $body_key ] = $this->headers[ $header_key ];
|
|
}
|
|
|
|
return $body;
|
|
}
|
|
|
|
/**
|
|
* Validates the webhook from the current request.
|
|
*
|
|
* @param object $event Webhook event.
|
|
*
|
|
* @since 2.11
|
|
* @return true
|
|
* @throws API_Exception
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public static function validate_from_request( $event ) {
|
|
$validator = new Webhook_Validator( getallheaders(), $event );
|
|
|
|
return $validator->verify_signature();
|
|
}
|
|
|
|
}
|