diff --git a/README.md b/README.md index 0f198b1c..f03f829e 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,32 @@ All URIs are relative to your region's base URL. | Europe | https://eu.api.fpjs.io | | Asia | https://ap.api.fpjs.io | +## Webhook Signing + +This SDK provides utility method for verifying the HMAC signature of the incoming webhook request. +You can use below code to verify signature: + +```php + Fingerprint\ServerAPI\Webhook\WebhookVerifier::IsValidWebhookSignature(string $header, string $data, string $secret): bool + +Verifies the HMAC signature extracted from the "fpjs-event-signature" header of the incoming request. This is a part of the webhook signing process, which is available only for enterprise customers. +If you wish to enable it, please [contact our support](https://fingerprint.com/support). + +### Required Parameters + +| Name | Type | Description | Notes | +|------------|------------|-----------------------------------------------------------|-------| +| **header** | **string** | Value of the `fpjs-event-signature` header. | | +| **data** | **string** | Body of the request from which above header was extracted. | | +| **secret** | **string** | Your generated secret used to sign the request. | | diff --git a/run_checks.php b/run_checks.php index 4f5831f2..5b890e7b 100644 --- a/run_checks.php +++ b/run_checks.php @@ -57,6 +57,17 @@ exit(1); } +$webhookSecret = "secret"; +$webhookData = "data"; +$webhookHeader = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; +$isValidWebhookSign = \Fingerprint\ServerAPI\Webhook\WebhookVerifier::IsValidWebhookSignature($webhookHeader, $webhookData, $webhookSecret); +if($isValidWebhookSign) { + fwrite(STDOUT, sprintf("\n\nVerified webhook signature\n")); +} else { + fwrite(STDERR, sprintf("\n\nWebhook signature verification failed\n")); + exit(1); +} + // Enable the deprecated ArrayAccess return type warning again if needed error_reporting(error_reporting() | E_DEPRECATED); diff --git a/scripts/generate.sh b/scripts/generate.sh index 7db1b68e..6dfff69c 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -65,7 +65,7 @@ java -jar ./bin/swagger-codegen-cli.jar generate -t ./template -l php -i ./res/f mv -f src/README.md ./README.md mv -f src/composer.json composer.json -find ./docs -type f ! -name "DecryptionKey.md" ! -name "Sealed.md" -exec rm {} + +find ./docs -type f ! -name "DecryptionKey.md" ! -name "Sealed.md" ! -name "Webhook.md" -exec rm {} + mv -f src/docs/* ./docs if [ -z "$GITHUB_ACTIONS" ]; then diff --git a/src/Webhook/WebhookVerifier.php b/src/Webhook/WebhookVerifier.php new file mode 100644 index 00000000..f8bb89a7 --- /dev/null +++ b/src/Webhook/WebhookVerifier.php @@ -0,0 +1,29 @@ +data, $this->secret); + $this->assertTrue($result, "With valid signature"); + } + + public function testWithInvalidHeader() + { + $result = WebhookVerifier::IsValidWebhookSignature("v2=invalid", $this->data, $this->secret); + $this->assertFalse($result, "With invalid header"); + } + + public function testWithHeaderWithoutVersion() + { + $result = WebhookVerifier::IsValidWebhookSignature("invalid", $this->data, $this->secret); + $this->assertFalse($result, "With header without version"); + } + + public function testWithEmptyHeader() + { + $result = WebhookVerifier::IsValidWebhookSignature("", $this->data, $this->secret); + $this->assertFalse($result, "With empty header"); + } + + public function testWithEmptySecret() + { + $validHeader = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; + $result = WebhookVerifier::IsValidWebhookSignature($validHeader, $this->data, ""); + $this->assertFalse($result, "With empty secret"); + } + + public function testWithEmptyData() + { + $validHeader = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; + $result = WebhookVerifier::IsValidWebhookSignature($validHeader, "", $this->secret); + $this->assertFalse($result, "With empty data"); + } +} \ No newline at end of file