Skip to content

Commit

Permalink
complete the test case for signature
Browse files Browse the repository at this point in the history
  • Loading branch information
ankurk91 committed Apr 18, 2023
1 parent a8a59db commit d0c052f
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/PayPalSignatureValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function isValid(Request $request, WebhookConfig $config): bool
]),
signature: base64_decode($request->header('PAYPAL-TRANSMISSION-SIG')),
public_key: openssl_pkey_get_public($this->downloadCert($request->header('PAYPAL-CERT-URL'))),
algorithm: 'sha256WithRSAEncryption'
algorithm: OPENSSL_ALGO_SHA256
) === 1;
} catch (RequestException $e) {
throw $e;
Expand Down
4 changes: 2 additions & 2 deletions tests/Factory/PayPalWebhookFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

class PayPalWebhookFactory
{
public function getCheckoutOrderApproved(): array
public static function checkoutOrderApproved(): array
{
$body = file_get_contents(__DIR__.'/Messages/checkout_order_approved.json');
return json_decode($body, true);
}

public function getCheckoutOrderCompleted(): array
public static function checkoutOrderCompleted(): array
{
$body = file_get_contents(__DIR__.'/Messages/checkout_order_completed.json');
return json_decode($body, true);
Expand Down
67 changes: 67 additions & 0 deletions tests/Factory/PaypalRequestFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);

namespace Ankurk91\PayPalWebhooks\Tests\Factory;

use Illuminate\Http\Request;
use Illuminate\Support\Str;

class PaypalRequestFactory
{
/**
* The certificate to sign the request.
*/
protected ?string $certificate;

protected function getSignature(string $stringToSign): string
{
$privateKey = openssl_pkey_new();

// Export certificate for later use
$csr = openssl_csr_new([], $privateKey);
$x509 = openssl_csr_sign($csr, null, $privateKey, 1);
openssl_x509_export($x509, $this->certificate);

openssl_sign($stringToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);

return base64_encode($signature);
}

public function getCertificate(): ?string
{
return $this->certificate;
}

public function make(string $webhookId): Request
{
$payload = PayPalWebhookFactory::checkoutOrderApproved();
$request = Request::create('/webhooks/paypal', 'POST', [], [], [], [], json_encode($payload));

$headers = [
'PAYPAL-TRANSMISSION-ID' => Str::random(),
'PAYPAL-TRANSMISSION-TIME' => now()->toDateTimeString(),
'PAYPAL-CERT-URL' => 'https://sandbox.paypal.com/cert.pem',
];

foreach ($headers as $name => $value) {
$request->headers->set($name, $value);
}

$request->headers->set(
'PAYPAL-TRANSMISSION-SIG',
$this->getSignature($this->getStringToSign($request, $webhookId))
);

return $request;
}

protected function getStringToSign(Request $request, string $webhookID): string
{
return implode('|', [
$request->header('PAYPAL-TRANSMISSION-ID'),
$request->header('PAYPAL-TRANSMISSION-TIME'),
$webhookID,
crc32($request->getContent()),
]);
}
}
24 changes: 22 additions & 2 deletions tests/PayPalSignatureValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

use Ankurk91\PayPalWebhooks\PayPalSignatureValidator;
use Ankurk91\PayPalWebhooks\PayPalWebhookConfig;
use Ankurk91\PayPalWebhooks\Tests\Factory\PaypalRequestFactory;
use Illuminate\Support\Facades\Http;
use Spatie\WebhookClient\WebhookConfig;

class PayPalSignatureValidatorTest extends TestCase
Expand All @@ -23,9 +25,27 @@ public function setUp(): void
$this->validator = new PayPalSignatureValidator();
}

public function testValidSignature(): void
public function test_passes_for_valid_signature(): void
{
$this->markTestSkipped('Should we ask ChatGPT to write tests?.');
$factory = new PaypalRequestFactory();

$request = $factory->make($this->webhookID);

Http::fake([
'paypal.com/*' => Http::response($factory->getCertificate())
]);

$this->assertTrue($this->validator->isValid($request, $this->config));
}

public function test_failed_on_invalid_signature_url()
{
$factory = new PaypalRequestFactory();

$request = $factory->make($this->webhookID);
$request->headers->set('PAYPAL-CERT-URL', 'https://example.com/cert.pem');

$this->assertFalse($this->validator->isValid($request, $this->config));
}

}
9 changes: 3 additions & 6 deletions tests/PayPalWebhookIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public function test_it_can_processes_webhook_successfully()
Event::fake();
Bus::fake(TestHandlerJob::class);

$messageFactory = new PayPalWebhookFactory();
$payload = $messageFactory->getCheckoutOrderApproved();
$payload = PayPalWebhookFactory::checkoutOrderApproved();

$this->postJson('/webhooks/paypal', $payload)
->assertSuccessful();
Expand All @@ -57,8 +56,7 @@ public function test_it_fails_when_invalid_job_class_configured()
{
Event::fake();

$messageFactory = new PayPalWebhookFactory();
$payload = $messageFactory->getCheckoutOrderCompleted();
$payload = PayPalWebhookFactory::checkoutOrderCompleted();

$this->postJson('/webhooks/paypal', $payload)
->assertSuccessful();
Expand All @@ -78,8 +76,7 @@ public function test_it_fails_when_invalid_job_class_configured()

public function test_it_process_same_webhook_only_once()
{
$messageFactory = new PayPalWebhookFactory();
$payload = $messageFactory->getCheckoutOrderApproved();
$payload = PayPalWebhookFactory::checkoutOrderApproved();

$this->postJson('/webhooks/paypal', $payload)
->assertSuccessful();
Expand Down

0 comments on commit d0c052f

Please sign in to comment.