Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,108 @@
1
+<?php
2
+
3
+namespace Telnyx;
4
+
5
+/**
6
+ * @internal
7
+ * @covers \Telnyx\Webhook
8
+ * @covers \Telnyx\WebhookSignature
9
+ */
10
+final class WebhookTest extends \Telnyx\TestCase
11
+{
12
+    const EVENT_PAYLOAD = '{
13
+  "data": {
14
+    "id": "evt_test_webhook",
15
+    "record_type": "event"
16
+  }
17
+}';
18
+    const SECRET = 'whsec_test_secret';
19
+
20
+    private function generateKeypairSignature($timestamp = 0, $payload = self::EVENT_PAYLOAD) {
21
+        $keypair = sodium_crypto_sign_keypair();
22
+
23
+        $result['publicKey'] = sodium_crypto_sign_publicKey($keypair); // 32 bytes
24
+        $result['secretKey'] = sodium_crypto_sign_secretKey($keypair); // 64 bytes
25
+        $result['signature'] = sodium_crypto_sign_detached($timestamp . '|' . $payload, $result['secretKey']);
26
+
27
+        return $result;
28
+    }
29
+    private function generateHeader($opts = [])
30
+    {
31
+        $timestamp = \array_key_exists('timestamp', $opts) ? $opts['timestamp'] : \time();
32
+        $payload = \array_key_exists('payload', $opts) ? $opts['payload'] : self::EVENT_PAYLOAD;
33
+        $secret = \array_key_exists('secret', $opts) ? $opts['secret'] : self::SECRET;
34
+        $signature = \array_key_exists('signature', $opts) ? $opts['signature'] : null;
35
+        if (null === $signature) {
36
+            $signedPayload = "{$timestamp}.{$payload}";
37
+            $signature = \hash_hmac('sha256', $signedPayload, $secret);
38
+        }
39
+
40
+        return "t={$timestamp},{$signature}";
41
+    }
42
+
43
+    public function testValidJsonAndHeader()
44
+    {
45
+        $timestamp = 0;
46
+        $keypair = self::generateKeypairSignature($timestamp, self::EVENT_PAYLOAD);
47
+        $event = Webhook::constructEvent(self::EVENT_PAYLOAD, base64_encode($keypair['signature']), $timestamp, base64_encode($keypair['publicKey']), 0);
48
+        static::assertSame('evt_test_webhook', $event->data['id']);
49
+    }
50
+
51
+    public function testInvalidJson()
52
+    {
53
+        $this->expectException(\Telnyx\Exception\UnexpectedValueException::class);
54
+
55
+        $payload = 'this is not valid JSON';
56
+        $keypair = self::generateKeypairSignature(0, $payload);
57
+        $event = Webhook::constructEvent($payload, base64_encode($keypair['signature']), 0, base64_encode($keypair['publicKey']), 0);
58
+    }
59
+
60
+    public function testValidJsonAndInvalidHeader()
61
+    {
62
+        $this->expectException(\Telnyx\Exception\SignatureVerificationException::class);
63
+
64
+        $sigHeader = 'bad_header';
65
+        Webhook::constructEvent(self::EVENT_PAYLOAD, $sigHeader, self::SECRET);
66
+    }
67
+
68
+    public function testMalformedHeader()
69
+    {
70
+        $this->expectException(\Telnyx\Exception\SignatureVerificationException::class);
71
+        $this->expectExceptionMessage('Unable to extract timestamp and signatures from header');
72
+
73
+        Webhook::constructFromRequest();
74
+    }
75
+
76
+    public function testTimestampTooOld()
77
+    {
78
+        $this->expectException(\Telnyx\Exception\SignatureVerificationException::class);
79
+        $this->expectExceptionMessage('Timestamp outside the tolerance zone');
80
+
81
+        $timestamp = \time() - 15;
82
+        $keypair = self::generateKeypairSignature($timestamp, self::EVENT_PAYLOAD);
83
+        WebhookSignature::verifyHeader(self::EVENT_PAYLOAD, base64_encode($keypair['signature']), $timestamp, base64_encode($keypair['publicKey']), 10);
84
+    }
85
+
86
+    public function testTimestampTooRecent()
87
+    {
88
+        $this->expectException(\Telnyx\Exception\SignatureVerificationException::class);
89
+        $this->expectExceptionMessage('Timestamp outside the tolerance zone');
90
+
91
+        $timestamp = \time() + 15;
92
+        $keypair = self::generateKeypairSignature($timestamp, self::EVENT_PAYLOAD);
93
+        WebhookSignature::verifyHeader(self::EVENT_PAYLOAD, base64_encode($keypair['signature']), $timestamp, base64_encode($keypair['publicKey']), 10);
94
+    }
95
+
96
+    public function testValidHeaderAndSignature()
97
+    {
98
+        $keypair = self::generateKeypairSignature();
99
+        static::assertTrue(WebhookSignature::verifyHeader(self::EVENT_PAYLOAD, base64_encode($keypair['signature']), 0, base64_encode($keypair['publicKey']), 0));
100
+    }
101
+
102
+    public function testTimestampOffButNoTolerance()
103
+    {
104
+        $timestamp = 12345;
105
+        $keypair = self::generateKeypairSignature($timestamp, self::EVENT_PAYLOAD);
106
+        static::assertTrue(WebhookSignature::verifyHeader(self::EVENT_PAYLOAD, base64_encode($keypair['signature']), $timestamp, base64_encode($keypair['publicKey']), 0));
107
+    }
108
+}