From e29e9d0a88ae51025ca4593543a99ad787ba7f7c Mon Sep 17 00:00:00 2001 From: jillingk <93914435+jillingk@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:27:09 +0100 Subject: [PATCH] Refactor/hmac validator (#151) (#216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace doubles with singles for style * Bring hmac validator test closer to real life * Tidy-up hmac validator code * Backwards compatibility aliasing Co-authored-by: Matas Zanevičius --- lib/adyen/utils/hmac_validator.rb | 32 ++++++++++++------------------- spec/utils/hmac_validator_spec.rb | 30 ++++++++++++++--------------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/lib/adyen/utils/hmac_validator.rb b/lib/adyen/utils/hmac_validator.rb index 8a083c4f..bf718ba5 100644 --- a/lib/adyen/utils/hmac_validator.rb +++ b/lib/adyen/utils/hmac_validator.rb @@ -15,7 +15,8 @@ def valid_notification_hmac?(notification_request_item, hmac_key) def valid_webhook_hmac?(webhook_request_item, hmac_key) expected_sign = calculate_webhook_hmac(webhook_request_item, hmac_key) - merchant_sign = fetch(webhook_request_item, 'additionalData.hmacSignature') + merchant_sign = + webhook_request_item.dig('additionalData', 'hmacSignature') expected_sign == merchant_sign end @@ -29,29 +30,20 @@ def calculate_notification_hmac(notification_request_item, hmac_key) def calculate_webhook_hmac(webhook_request_item, hmac_key) data = data_to_sign(webhook_request_item) - Base64.strict_encode64(OpenSSL::HMAC.digest(HMAC_ALGORITHM, [hmac_key].pack('H*'), data)) + Base64.strict_encode64( + OpenSSL::HMAC.digest(HMAC_ALGORITHM, [hmac_key].pack('H*'), data) + ) end + # TODO: Deprecate instead of aliasing + alias valid_notification_hmac? valid_webhook_hmac? + alias calculate_notification_hmac calculate_webhook_hmac def data_to_sign(webhook_request_item) - data = WEBHOOK_VALIDATION_KEYS.map { |key| fetch(webhook_request_item, key).to_s } - .join(DATA_SEPARATOR) - end - - private - - def fetch(hash, keys) - value = hash - keys.to_s.split('.').each do |key| - value = if key.to_i.to_s == key - value[key.to_i] - else - value[key].nil? ? value[key.to_sym] : value[key] - end - break if value.nil? - end - - value + WEBHOOK_VALIDATION_KEYS + .map { webhook_request_item.dig(*_1.split('.')).to_s } + .compact + .join(DATA_SEPARATOR) end end end diff --git a/spec/utils/hmac_validator_spec.rb b/spec/utils/hmac_validator_spec.rb index 716c69c6..19fa90fe 100644 --- a/spec/utils/hmac_validator_spec.rb +++ b/spec/utils/hmac_validator_spec.rb @@ -6,19 +6,19 @@ let(:expected_sign) { 'coqCmt/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=' } let(:webhook_request_item) do { - additionalData: { - hmacSignature: expected_sign + 'additionalData' => { + 'hmacSignature' => expected_sign }, - amount: { - value: 1130, - currency: 'EUR' + 'amount' => { + 'value' => 1130, + 'currency' => 'EUR' }, - pspReference: '7914073381342284', - eventCode: 'AUTHORISATION', - merchantAccountCode: 'TestMerchant', - merchantReference: 'TestPayment-1407325143704', - paymentMethod: 'visa', - success: 'true' + 'pspReference' => '7914073381342284', + 'eventCode' => 'AUTHORISATION', + 'merchantAccountCode' => 'TestMerchant', + 'merchantReference' => 'TestPayment-1407325143704', + 'paymentMethod' => 'visa', + 'success' => 'true' } end @@ -44,22 +44,22 @@ end it 'should validate backslashes correctly' do - webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/backslash_webhook.json")) + webhook = JSON.parse(json_from_file('mocks/responses/Webhooks/backslash_webhook.json')) expect(validator.valid_webhook_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true end it 'should validate colons correctly' do - webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/colon_webhook.json")) + webhook = JSON.parse(json_from_file('mocks/responses/Webhooks/colon_webhook.json')) expect(validator.valid_webhook_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true end it 'should validate forward slashes correctly' do - webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/forwardslash_webhook.json")) + webhook = JSON.parse(json_from_file('mocks/responses/Webhooks/forwardslash_webhook.json')) expect(validator.valid_webhook_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true end it 'should validate mix of slashes and colon correctly' do - webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/mixed_webhook.json")) + webhook = JSON.parse(json_from_file('mocks/responses/Webhooks/mixed_webhook.json')) expect(validator.valid_webhook_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true end end