PluginProbe
SuperFrete / trunk
SuperFrete vtrunk
trunk 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4
superfrete / api / Http / WebhookVerifier.php

WebhookVerifier.php in SuperFrete trunk, at api/Http/WebhookVerifier.php

128 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SuperFrete_API\Http;
4
5 use SuperFrete_API\Helpers\Logger;
6
7 if (!defined('ABSPATH')) {
8 exit; // Security check
9 }
10
11 class WebhookVerifier
12 {
13
14 /**
15 * Verify webhook signature using HMAC SHA-256
16 *
17 * @param array $payload The webhook payload
18 * @param string $signature The signature from x-me-signature header
19 * @param string $secret The webhook secret
20 * @return bool
21 */
22 public static function verify_signature($payload, $signature, $secret)
23 {
24 if (empty($signature) || empty($secret)) {
25 Logger::log('SuperFrete', 'Webhook verification failed: Missing signature or secret');
26 return false;
27 }
28
29 // Convert payload to JSON string for signature calculation
30 $payload_json = is_string($payload) ? $payload : wp_json_encode($payload);
31
32 // Calculate expected signature
33 $expected_signature = hash_hmac('sha256', $payload_json, $secret);
34
35 // Remove 'sha256=' prefix if present
36 $provided_signature = str_replace('sha256=', '', $signature);
37
38 // Use hash_equals for timing-safe comparison
39 $is_valid = hash_equals($expected_signature, $provided_signature);
40
41 if (!$is_valid) {
42 Logger::log('SuperFrete', 'Webhook signature verification failed', [
43 'expected' => $expected_signature,
44 'provided' => $provided_signature,
45 'payload_length' => strlen($payload_json)
46 ]);
47 }
48
49 return $is_valid;
50 }
51
52 /**
53 * Extract and validate webhook headers
54 *
55 * @return array
56 */
57 public static function get_webhook_headers()
58 {
59 $headers = [];
60
61 // Get signature from header
62 $signature = null;
63 if (function_exists('getallheaders')) {
64 $all_headers = getallheaders();
65 $signature = $all_headers['x-me-signature'] ?? $all_headers['X-Me-Signature'] ?? null;
66 }
67
68 // Fallback to $_SERVER
69 if (!$signature) {
70 $signature = $_SERVER['HTTP_X_ME_SIGNATURE'] ?? null;
71 }
72
73 $headers['signature'] = $signature;
74 $headers['content_type'] = $_SERVER['CONTENT_TYPE'] ?? '';
75 $headers['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
76
77 return $headers;
78 }
79
80 /**
81 * Validate webhook payload structure
82 *
83 * @param array $payload
84 * @return bool
85 */
86 public static function validate_payload_structure($payload)
87 {
88 if (!is_array($payload)) {
89 Logger::log('SuperFrete', 'Invalid webhook payload: Not an array');
90 return false;
91 }
92
93 // Check required fields
94 $required_fields = ['event', 'data'];
95 foreach ($required_fields as $field) {
96 if (!isset($payload[$field])) {
97 Logger::log('SuperFrete', "Invalid webhook payload: Missing field '$field'");
98 return false;
99 }
100 }
101
102 // Validate event type
103 $supported_events = ['order.posted', 'order.delivered'];
104 if (!in_array($payload['event'], $supported_events)) {
105 Logger::log('SuperFrete', 'Unsupported webhook event: ' . $payload['event']);
106 return false;
107 }
108
109 // Validate data structure
110 if (!isset($payload['data']['id'])) {
111 Logger::log('SuperFrete', 'Invalid webhook payload: Missing data.id');
112 return false;
113 }
114
115 return true;
116 }
117
118 /**
119 * Generate webhook secret
120 *
121 * @param int $length
122 * @return string
123 */
124 public static function generate_webhook_secret($length = 32)
125 {
126 return wp_generate_password($length, false);
127 }
128 }