WebhookNotificationGateway.php 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. <?php
  2. namespace Braintree;
  3. class WebhookNotificationGateway
  4. {
  5. public function __construct($gateway)
  6. {
  7. $this->config = $gateway->config;
  8. $this->config->assertHasAccessTokenOrKeys();
  9. }
  10. public function parse($signature, $payload)
  11. {
  12. if (is_null($signature)) {
  13. throw new Exception\InvalidSignature("signature cannot be null");
  14. }
  15. if (is_null($payload)) {
  16. throw new Exception\InvalidSignature("payload cannot be null");
  17. }
  18. if (preg_match("/[^A-Za-z0-9+=\/\n]/", $payload) === 1) {
  19. throw new Exception\InvalidSignature("payload contains illegal characters");
  20. }
  21. self::_validateSignature($signature, $payload);
  22. $xml = base64_decode($payload);
  23. $attributes = Xml::buildArrayFromXml($xml);
  24. return WebhookNotification::factory($attributes['notification']);
  25. }
  26. public function verify($challenge)
  27. {
  28. if (!preg_match('/^[a-f0-9]{20,32}$/', $challenge)) {
  29. throw new Exception\InvalidChallenge("challenge contains non-hex characters");
  30. }
  31. $publicKey = $this->config->getPublicKey();
  32. $digest = Digest::hexDigestSha1($this->config->getPrivateKey(), $challenge);
  33. return "{$publicKey}|{$digest}";
  34. }
  35. private function _payloadMatches($signature, $payload)
  36. {
  37. $payloadSignature = Digest::hexDigestSha1($this->config->getPrivateKey(), $payload);
  38. return Digest::secureCompare($signature, $payloadSignature);
  39. }
  40. private function _validateSignature($signatureString, $payload)
  41. {
  42. $signaturePairs = preg_split("/&/", $signatureString);
  43. $signature = self::_matchingSignature($signaturePairs);
  44. if (!$signature) {
  45. throw new Exception\InvalidSignature("no matching public key");
  46. }
  47. if (!(self::_payloadMatches($signature, $payload) || self::_payloadMatches($signature, $payload . "\n"))) {
  48. throw new Exception\InvalidSignature("signature does not match payload - one has been modified");
  49. }
  50. }
  51. private function _matchingSignature($signaturePairs)
  52. {
  53. foreach ($signaturePairs as $pair)
  54. {
  55. $components = preg_split("/\|/", $pair);
  56. if ($components[0] == $this->config->getPublicKey()) {
  57. return $components[1];
  58. }
  59. }
  60. return null;
  61. }
  62. }
  63. class_alias('Braintree\WebhookNotificationGateway', 'Braintree_WebhookNotificationGateway');