Skip to content

Commit 11a8755

Browse files
authored
Merge pull request #32 from packagist/t/webhook-validation
Webhook: add service to validate incoming payload
2 parents 9cbd4ca + e0d448c commit 11a8755

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,18 @@ Returns the new Magento legacy key.
571571
$client->customers()->magentoLegacyKeys()->remove($customerId, $publicKey);
572572
```
573573

574+
### Validate incoming webhook payloads
575+
576+
When you create or update a webhook in Private Packagist an optional secret can be set. This secret gets used to create a signature which is sent with each request in the headers as `Packagist-Signature`. The secret and signature can then be used on your server to validate that the request was made by Private Packagist. If no secret is set then no signature is sent.
577+
578+
```php
579+
$request = /** any Psr7 request */;
580+
$secret = 'webhook-secret';
581+
$webhookSignature = new \PrivatePackagist\ApiClient\WebhookSignature($secret);
582+
$requestSignature = $request->hasHeader('Packagist-Signature') ? $request->getHeader('Packagist-Signature')[0] : null;
583+
$webhookSignature->validate($requestSignature, (string) $request->getBody());
584+
```
585+
574586
## License
575587

576588
`private-packagist/api-client` is licensed under the MIT License

src/WebhookSignature.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace PrivatePackagist\ApiClient;
4+
5+
class WebhookSignature
6+
{
7+
/** @var string */
8+
private $secret;
9+
10+
public function __construct($secret)
11+
{
12+
$this->secret = $secret;
13+
}
14+
15+
/**
16+
* @param string $signature
17+
* @param string $payload
18+
* @return bool
19+
*/
20+
public function validate($signature, $payload)
21+
{
22+
$payloadSignature = 'sha1='.hash_hmac('sha1', $payload, $this->secret);
23+
24+
return hash_equals($payloadSignature, (string) $signature);
25+
}
26+
}

tests/WebhookSignatureTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace PrivatePackagist\ApiClient;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class WebhookSignatureTest extends TestCase
8+
{
9+
/** @var WebhookSignature */
10+
private $webhookSignature;
11+
12+
protected function setUp()
13+
{
14+
$this->webhookSignature = new WebhookSignature('test');
15+
}
16+
17+
public function testValidate()
18+
{
19+
$this->assertTrue($this->webhookSignature->validate('sha1=b92a2ae52a340f2246a0ec24d45bb4ecfdf7b8ac', 'payload'));
20+
}
21+
22+
public function testValidateInvalid()
23+
{
24+
$this->assertFalse($this->webhookSignature->validate('sha1=invalid', 'payload'));
25+
}
26+
27+
public function testValidateNull()
28+
{
29+
$this->assertFalse($this->webhookSignature->validate('sha1=invalid', null));
30+
}
31+
}

0 commit comments

Comments
 (0)