diff --git a/src/Utility.php b/src/Utility.php index 9f3a527..440fa5d 100644 --- a/src/Utility.php +++ b/src/Utility.php @@ -41,17 +41,49 @@ public function verifyPaymentSignature($attributes) } $secret = Api::getSecret(); + + // If we're using OAuth token authentication, check if secret is provided in attributes + if (empty($secret) && Api::getToken() !== null) + { + if (isset($attributes['secret']) === true) + { + $secret = $attributes['secret']; + } + else + { + throw new Errors\SignatureVerificationError( + 'When using OAuth authentication, you must provide the secret as an attribute for signature verification.'); + } + } self::verifySignature($payload, $actualSignature, $secret); } - public function verifyWebhookSignature($payload, $actualSignature, $secret) + public function verifyWebhookSignature($payload, $actualSignature, $secret = null) { + // If secret isn't provided and we're using OAuth token authentication + if ($secret === null) + { + $secret = Api::getSecret(); + + if (empty($secret) && Api::getToken() !== null) + { + throw new Errors\SignatureVerificationError( + 'When using OAuth authentication, you must explicitly provide the secret for webhook signature verification.'); + } + } + self::verifySignature($payload, $actualSignature, $secret); } public function verifySignature($payload, $actualSignature, $secret) { + if (empty($secret)) + { + throw new Errors\SignatureVerificationError( + 'No secret available for signature verification. Make sure to provide it or initialize Api with a secret key.'); + } + $expectedSignature = hash_hmac(self::SHA256, $payload, $secret); // Use lang's built-in hash_equals if exists to mitigate timing attacks @@ -90,7 +122,7 @@ private function encrypt($dataToEncrypt, $secret) { $encryptedData = openssl_encrypt($dataToEncrypt, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, '', 16); if ($encryptedData === false) { - throw new Exception('Encryption failed'); + throw new \Exception('Encryption failed'); } // Concatenate encrypted data with the authentication tag @@ -98,8 +130,8 @@ private function encrypt($dataToEncrypt, $secret) { // Convert to hex string return bin2hex($finalData); - } catch (Exception $e) { - throw new Exception('Encryption failed: ' . $e->getMessage()); + } catch (\Exception $e) { + throw new \Exception('Encryption failed: ' . $e->getMessage()); } } diff --git a/tests/SignatureVerificationTest.php b/tests/SignatureVerificationTest.php index 1037676..e0ad223 100644 --- a/tests/SignatureVerificationTest.php +++ b/tests/SignatureVerificationTest.php @@ -3,9 +3,12 @@ namespace Razorpay\Tests; use Razorpay\Api\Request; +use Razorpay\Api\Api; +use Razorpay\Api\Utility; class SignatureVerificationTest extends TestCase { + protected $api; private static $subscriptionId; public function setUp(): void @@ -64,4 +67,49 @@ public function testSubscriptionVerification() 'razorpay_signature' => $signature ))); } + + /** + * Test verification with OAuth token authentication + */ + public function testOAuthTokenVerification() + { + $orderId = 'order_123456789'; + $paymentId = 'pay_123456789'; + $secret = 'test_secret_key'; + + // The payload that would be used for signature verification + $payload = $orderId . '|' . $paymentId; + + // Generate a valid signature using the test secret + $expectedSignature = hash_hmac('sha256', $payload, $secret); + + // Create a new API instance with OAuth token + $apiWithOAuth = new Api(null, null, 'test_oauth_token'); + + // This should work now with the secret passed in attributes + $this->assertNull($apiWithOAuth->utility->verifyPaymentSignature([ + 'razorpay_order_id' => $orderId, + 'razorpay_payment_id' => $paymentId, + 'razorpay_signature' => $expectedSignature, + 'secret' => $secret + ])); + } + + /** + * Test webhook verification with OAuth token authentication + */ + public function testOAuthTokenWebhookVerification() + { + $payload = '{"payment_id":"pay_123456789","order_id":"order_123456789"}'; + $secret = 'webhook_secret_key'; + + // Generate a valid signature using the test secret + $expectedSignature = hash_hmac('sha256', $payload, $secret); + + // Create a new API instance with OAuth token + $apiWithOAuth = new Api(null, null, 'test_oauth_token'); + + // Verify webhook signature with explicit secret + $this->assertNull($apiWithOAuth->utility->verifyWebhookSignature($payload, $expectedSignature, $secret)); + } } \ No newline at end of file