adyen-ruby-api-library 6.2.0 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -1
- data/.github/workflows/codeql.yml +41 -0
- data/.github/workflows/ruby.yml +1 -1
- data/.github/workflows/rubygems_release.yml +1 -1
- data/lib/adyen/client.rb +16 -4
- data/lib/adyen/errors.rb +2 -2
- data/lib/adyen/services/checkout.rb +43 -11
- data/lib/adyen/services/service.rb +5 -0
- data/lib/adyen/utils/hmac_validator.rb +2 -3
- data/lib/adyen/version.rb +2 -2
- data/spec/checkout_spec.rb +50 -0
- data/spec/client_spec.rb +1 -1
- data/spec/errors_spec.rb +1 -1
- data/spec/mocks/responses/Checkout/stored_payment_methods.json +1 -0
- data/spec/mocks/responses/Webhooks/backslash_notification.json +41 -0
- data/spec/mocks/responses/Webhooks/colon_notification.json +41 -0
- data/spec/mocks/responses/Webhooks/forwardslash_notification.json +41 -0
- data/spec/mocks/responses/Webhooks/mixed_notification.json +41 -0
- data/spec/utils/hmac_validator_spec.rb +20 -6
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45627b45fc5df26d004c1a86d7640412d615383ccac35201f24f0e3ebed99394
|
4
|
+
data.tar.gz: 72a067ba4b95419ed87e526a371db2377d5b1af7056f9ac035a6e11327715da0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a893d921b3236805bb89b6ca5fc1c553888d010c84c1927689f6bc47e1a78b23302c081edbc979d596ac70c0b6f23cad61b9a83cc11c6f8b22e1d73520951bdb
|
7
|
+
data.tar.gz: 3cc14ff3d1550ffb11f6ec08c37ae7858b5e39e1b14023e6323e3a132441b59ee383e39ca6db6dcb83eff24e4b9ae937bff416bc9684e1ba6cb8ba7b20e37405
|
data/.github/CODEOWNERS
CHANGED
@@ -1 +1 @@
|
|
1
|
-
* @
|
1
|
+
* @Adyen/api-libraries-reviewers
|
@@ -0,0 +1,41 @@
|
|
1
|
+
name: "CodeQL"
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ "develop", "main" ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "develop" ]
|
8
|
+
schedule:
|
9
|
+
- cron: "40 12 * * 0"
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
analyze:
|
13
|
+
name: Analyze
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
permissions:
|
16
|
+
actions: read
|
17
|
+
contents: read
|
18
|
+
security-events: write
|
19
|
+
|
20
|
+
strategy:
|
21
|
+
fail-fast: false
|
22
|
+
matrix:
|
23
|
+
language: [ javascript ]
|
24
|
+
|
25
|
+
steps:
|
26
|
+
- name: Checkout
|
27
|
+
uses: actions/checkout@v3
|
28
|
+
|
29
|
+
- name: Initialize CodeQL
|
30
|
+
uses: github/codeql-action/init@v2
|
31
|
+
with:
|
32
|
+
languages: ${{ matrix.language }}
|
33
|
+
queries: +security-and-quality
|
34
|
+
|
35
|
+
- name: Autobuild
|
36
|
+
uses: github/codeql-action/autobuild@v2
|
37
|
+
|
38
|
+
- name: Perform CodeQL Analysis
|
39
|
+
uses: github/codeql-action/analyze@v2
|
40
|
+
with:
|
41
|
+
category: "/language:${{ matrix.language }}"
|
data/.github/workflows/ruby.yml
CHANGED
data/lib/adyen/client.rb
CHANGED
@@ -144,6 +144,13 @@ module Adyen
|
|
144
144
|
raise connection_error, "Connection to #{url} failed"
|
145
145
|
end
|
146
146
|
end
|
147
|
+
if action.fetch(:method) == "delete"
|
148
|
+
begin
|
149
|
+
response = conn.delete
|
150
|
+
rescue Faraday::ConnectionFailed => connection_error
|
151
|
+
raise connection_error, "Connection to #{url} failed"
|
152
|
+
end
|
153
|
+
end
|
147
154
|
if action.fetch(:method) == "patch"
|
148
155
|
begin
|
149
156
|
response = conn.patch do |req|
|
@@ -169,11 +176,16 @@ module Adyen
|
|
169
176
|
when 401
|
170
177
|
raise Adyen::AuthenticationError.new("Invalid API authentication; https://docs.adyen.com/user-management/how-to-get-the-api-key", request_data)
|
171
178
|
when 403
|
172
|
-
raise Adyen::PermissionError.new("Missing user permissions; https://docs.adyen.com/user-management/user-roles", request_data)
|
179
|
+
raise Adyen::PermissionError.new("Missing user permissions; https://docs.adyen.com/user-management/user-roles", request_data, response.body)
|
173
180
|
end
|
174
|
-
|
175
|
-
|
176
|
-
|
181
|
+
|
182
|
+
# delete has no response.body (unless it throws an error)
|
183
|
+
if response.body == nil
|
184
|
+
formatted_response = AdyenResult.new("{}", response.headers, response.status)
|
185
|
+
else
|
186
|
+
formatted_response = AdyenResult.new(response.body, response.headers, response.status)
|
187
|
+
end
|
188
|
+
|
177
189
|
formatted_response
|
178
190
|
end
|
179
191
|
|
data/lib/adyen/errors.rb
CHANGED
@@ -2,7 +2,7 @@ require_relative "service"
|
|
2
2
|
|
3
3
|
module Adyen
|
4
4
|
class Checkout < Service
|
5
|
-
DEFAULT_VERSION =
|
5
|
+
DEFAULT_VERSION = 70
|
6
6
|
|
7
7
|
def initialize(client, version = DEFAULT_VERSION)
|
8
8
|
service = "Checkout"
|
@@ -13,7 +13,7 @@ module Adyen
|
|
13
13
|
]
|
14
14
|
|
15
15
|
with_application_info = [
|
16
|
-
:payment_session
|
16
|
+
:payment_session
|
17
17
|
]
|
18
18
|
|
19
19
|
super(client, version, service, method_names, with_application_info)
|
@@ -42,7 +42,7 @@ module Adyen
|
|
42
42
|
else
|
43
43
|
action = "paymentLinks"
|
44
44
|
args[1] ||= {} # optional headers arg
|
45
|
-
@client.call_adyen_api(@service, action, args[0], args[1], @version
|
45
|
+
@client.call_adyen_api(@service, action, args[0], args[1], @version)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -75,6 +75,10 @@ module Adyen
|
|
75
75
|
def modifications
|
76
76
|
@modifications ||= Adyen::Modifications.new(@client, @version)
|
77
77
|
end
|
78
|
+
|
79
|
+
def stored_payment_methods
|
80
|
+
@stored_payment_methods ||= Adyen::StoredPaymentMethods.new(@client, @version)
|
81
|
+
end
|
78
82
|
end
|
79
83
|
|
80
84
|
class CheckoutDetail < Service
|
@@ -93,6 +97,16 @@ module Adyen
|
|
93
97
|
action = "payments/result"
|
94
98
|
@client.call_adyen_api(@service, action, request, headers, @version)
|
95
99
|
end
|
100
|
+
|
101
|
+
def donations(request, headers = {})
|
102
|
+
action = "donations"
|
103
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
104
|
+
end
|
105
|
+
|
106
|
+
def card_details(request, headers = {})
|
107
|
+
action = "cardDetails"
|
108
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
109
|
+
end
|
96
110
|
end
|
97
111
|
|
98
112
|
class CheckoutLink < Service
|
@@ -104,12 +118,12 @@ module Adyen
|
|
104
118
|
|
105
119
|
def get(linkId, headers = {})
|
106
120
|
action = { method: 'get', url: "paymentLinks/" + linkId }
|
107
|
-
@client.call_adyen_api(@service, action, {}, headers, @version
|
121
|
+
@client.call_adyen_api(@service, action, {}, headers, @version)
|
108
122
|
end
|
109
123
|
|
110
124
|
def update(linkId, request, headers = {})
|
111
125
|
action = { method: 'patch', url: "paymentLinks/" + linkId }
|
112
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
126
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
113
127
|
end
|
114
128
|
end
|
115
129
|
|
@@ -161,12 +175,12 @@ module Adyen
|
|
161
175
|
|
162
176
|
def capture(linkId, request, headers = {})
|
163
177
|
action = "payments/" + linkId + "/captures"
|
164
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
178
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
165
179
|
end
|
166
180
|
|
167
181
|
def cancel(linkId, request, headers = {})
|
168
182
|
action = "payments/" + linkId + "/cancels"
|
169
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
183
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
170
184
|
end
|
171
185
|
|
172
186
|
def genericCancel(request, headers = {})
|
@@ -176,17 +190,35 @@ module Adyen
|
|
176
190
|
|
177
191
|
def refund(linkId, request, headers = {})
|
178
192
|
action = "payments/" + linkId + "/refunds"
|
179
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
193
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
180
194
|
end
|
181
195
|
|
182
196
|
def reversal(linkId, request, headers = {})
|
183
197
|
action = "payments/" + linkId + "/reversals"
|
184
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
198
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
185
199
|
end
|
186
200
|
|
187
201
|
def amountUpdate(linkId, request, headers = {})
|
188
202
|
action = "payments/" + linkId + "/amountUpdates"
|
189
|
-
@client.call_adyen_api(@service, action, request, headers, @version
|
203
|
+
@client.call_adyen_api(@service, action, request, headers, @version)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class StoredPaymentMethods < Service
|
208
|
+
def initialize(client, version = DEFAULT_VERSION)
|
209
|
+
@service = "Checkout"
|
210
|
+
@client = client
|
211
|
+
@version = version
|
212
|
+
end
|
213
|
+
|
214
|
+
def get(query_array={}, headers = {})
|
215
|
+
action = { method: 'get', url: "storedPaymentMethods" + create_query_string(query_array)}
|
216
|
+
@client.call_adyen_api(@service, action, {}, headers, @version)
|
217
|
+
end
|
218
|
+
|
219
|
+
def delete(recurringId, query_array={}, headers = {})
|
220
|
+
action = { method: 'delete', url: "storedPaymentMethods/%s" % recurringId + create_query_string(query_array)}
|
221
|
+
@client.call_adyen_api(@service, action, {}, headers, @version)
|
190
222
|
end
|
191
223
|
end
|
192
|
-
end
|
224
|
+
end
|
@@ -22,16 +22,15 @@ module Adyen
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def data_to_sign(notification_request_item)
|
25
|
-
NOTIFICATION_VALIDATION_KEYS.map { |key| fetch(notification_request_item, key).to_s }
|
26
|
-
.map { |value| value.gsub('\\', '\\\\').gsub(':', '\\:') }
|
25
|
+
data = NOTIFICATION_VALIDATION_KEYS.map { |key| fetch(notification_request_item, key).to_s }
|
27
26
|
.join(DATA_SEPARATOR)
|
27
|
+
return data
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def fetch(hash, keys)
|
33
33
|
value = hash
|
34
|
-
|
35
34
|
keys.to_s.split('.').each do |key|
|
36
35
|
value = if key.to_i.to_s == key
|
37
36
|
value[key.to_i]
|
data/lib/adyen/version.rb
CHANGED
data/spec/checkout_spec.rb
CHANGED
@@ -597,6 +597,56 @@ RSpec.describe Adyen::Checkout, service: "checkout" do
|
|
597
597
|
to eq("12345")
|
598
598
|
end
|
599
599
|
|
600
|
+
it "makes a get storedPaymentMethods call" do
|
601
|
+
response_body = json_from_file("mocks/responses/Checkout/stored_payment_methods.json")
|
602
|
+
|
603
|
+
url = @shared_values[:client].service_url(@shared_values[:service], "storedPaymentMethods?merchantAccount=TestMerchantAccount&shopperReference=test-1234", @shared_values[:client].checkout.version)
|
604
|
+
WebMock.stub_request(:get, url).
|
605
|
+
with(
|
606
|
+
headers: {
|
607
|
+
"x-api-key" => @shared_values[:client].api_key
|
608
|
+
}
|
609
|
+
).
|
610
|
+
to_return(
|
611
|
+
body: response_body
|
612
|
+
)
|
613
|
+
|
614
|
+
result = @shared_values[:client].checkout.stored_payment_methods.get({"merchantAccount" => "TestMerchantAccount", "shopperReference" => "test-1234"})
|
615
|
+
response_hash = result.response
|
616
|
+
|
617
|
+
expect(result.status).
|
618
|
+
to eq(200)
|
619
|
+
expect(response_hash).
|
620
|
+
to eq(JSON.parse(response_body))
|
621
|
+
expect(response_hash).
|
622
|
+
to be_a Adyen::HashWithAccessors
|
623
|
+
expect(response_hash).
|
624
|
+
to be_a_kind_of Hash
|
625
|
+
expect(response_hash["shopperReference"]).
|
626
|
+
to eq("test-1234")
|
627
|
+
end
|
628
|
+
|
629
|
+
it "makes a delete storedPaymentMethods call" do
|
630
|
+
response_body = json_from_file("mocks/responses/Checkout/stored_payment_methods.json")
|
631
|
+
|
632
|
+
url = @shared_values[:client].service_url(@shared_values[:service], "storedPaymentMethods/RL8FW7WZM6KXWD82?merchantAccount=TestMerchantAccount&shopperReference=test-1234", @shared_values[:client].checkout.version)
|
633
|
+
WebMock.stub_request(:delete, url).
|
634
|
+
with(
|
635
|
+
headers: {
|
636
|
+
"x-api-key" => @shared_values[:client].api_key
|
637
|
+
}
|
638
|
+
).
|
639
|
+
to_return(
|
640
|
+
body: response_body
|
641
|
+
)
|
642
|
+
|
643
|
+
result = @shared_values[:client].checkout.stored_payment_methods.delete("RL8FW7WZM6KXWD82", {"merchantAccount" => "TestMerchantAccount", "shopperReference" => "test-1234"})
|
644
|
+
response_hash = result.response
|
645
|
+
|
646
|
+
expect(result.status).
|
647
|
+
to eq(200)
|
648
|
+
end
|
649
|
+
|
600
650
|
# create client for automated tests
|
601
651
|
client = create_client(:api_key)
|
602
652
|
|
data/spec/client_spec.rb
CHANGED
@@ -106,7 +106,7 @@ RSpec.describe Adyen do
|
|
106
106
|
mock_response = Faraday::Response.new(status: 200)
|
107
107
|
|
108
108
|
expect(Adyen::AdyenResult).to receive(:new)
|
109
|
-
expect(Faraday).to receive(:new).with("http://localhost:3001/
|
109
|
+
expect(Faraday).to receive(:new).with("http://localhost:3001/v70/payments/details", connection_options).and_return(mock_faraday_connection)
|
110
110
|
expect(mock_faraday_connection).to receive(:post).and_return(mock_response)
|
111
111
|
client.checkout.payments.details(request_body)
|
112
112
|
end
|
data/spec/errors_spec.rb
CHANGED
@@ -33,7 +33,7 @@ RSpec.describe Adyen::AdyenError do
|
|
33
33
|
expect(Adyen::AdyenError.new(@shared_values[:request], nil, nil, 'code').to_s).to eq("Adyen::AdyenError code:code, request:#{@shared_values[:request]}")
|
34
34
|
end
|
35
35
|
it 'uses the proper error class name' do
|
36
|
-
expect(Adyen::PermissionError.new('message', @shared_values[:request]).to_s).to eq("Adyen::PermissionError code:403, msg:message, request:#{@shared_values[:request]}")
|
36
|
+
expect(Adyen::PermissionError.new('message', @shared_values[:request], 'response').to_s).to eq("Adyen::PermissionError code:403, msg:message, request:#{@shared_values[:request]}, response:response")
|
37
37
|
end
|
38
38
|
end
|
39
39
|
describe '#masking' do
|
@@ -0,0 +1 @@
|
|
1
|
+
{"merchantAccount":"TestMerchantAccount", "shopperReference":"test-1234"}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"additionalData": {
|
3
|
+
"acquirerCode": "TestPmmAcquirer",
|
4
|
+
"acquirerReference": "DZMKWLXW6N6",
|
5
|
+
"authCode": "076181",
|
6
|
+
"avsResult": "5 No AVS data provided",
|
7
|
+
"avsResultRaw": "5",
|
8
|
+
"cardSummary": "1111",
|
9
|
+
"checkout.cardAddedBrand": "visa",
|
10
|
+
"cvcResult": "1 Matches",
|
11
|
+
"cvcResultRaw": "M",
|
12
|
+
"expiryDate": "03/2030",
|
13
|
+
"hmacSignature": "nIgT81gaB5oJpn2jPXupDq68iRo2wUlBsuYjtYfwKqo=",
|
14
|
+
"paymentMethod": "visa",
|
15
|
+
"refusalReasonRaw": "AUTHORISED",
|
16
|
+
"retry.attempt1.acquirer": "TestPmmAcquirer",
|
17
|
+
"retry.attempt1.acquirerAccount": "TestPmmAcquirerAccount",
|
18
|
+
"retry.attempt1.avsResultRaw": "5",
|
19
|
+
"retry.attempt1.rawResponse": "AUTHORISED",
|
20
|
+
"retry.attempt1.responseCode": "Approved",
|
21
|
+
"retry.attempt1.scaExemptionRequested": "lowValue",
|
22
|
+
"scaExemptionRequested": "lowValue"
|
23
|
+
},
|
24
|
+
"amount": {
|
25
|
+
"currency": "EUR",
|
26
|
+
"value": 1000
|
27
|
+
},
|
28
|
+
"eventCode": "AUTHORISATION",
|
29
|
+
"eventDate": "2023-01-09T16:27:29+01:00",
|
30
|
+
"merchantAccountCode": "AntoniStroinski",
|
31
|
+
"merchantReference": "\\\\slashes are fun",
|
32
|
+
"operations": [
|
33
|
+
"CANCEL",
|
34
|
+
"CAPTURE",
|
35
|
+
"REFUND"
|
36
|
+
],
|
37
|
+
"paymentMethod": "visa",
|
38
|
+
"pspReference": "T7FD4VM4D3RZNN82",
|
39
|
+
"reason": "076181:1111:03/2030",
|
40
|
+
"success": "true"
|
41
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"additionalData": {
|
3
|
+
"acquirerCode": "TestPmmAcquirer",
|
4
|
+
"acquirerReference": "8NQH5BNF58M",
|
5
|
+
"authCode": "039404",
|
6
|
+
"avsResult": "5 No AVS data provided",
|
7
|
+
"avsResultRaw": "5",
|
8
|
+
"cardSummary": "1111",
|
9
|
+
"checkout.cardAddedBrand": "visa",
|
10
|
+
"cvcResult": "1 Matches",
|
11
|
+
"cvcResultRaw": "M",
|
12
|
+
"expiryDate": "03/2030",
|
13
|
+
"hmacSignature": "2EQYm7YJpKO4EtHSPu55SQTyWf8dkW5u2nD1tJFpViA=",
|
14
|
+
"paymentMethod": "visa",
|
15
|
+
"refusalReasonRaw": "AUTHORISED",
|
16
|
+
"retry.attempt1.acquirer": "TestPmmAcquirer",
|
17
|
+
"retry.attempt1.acquirerAccount": "TestPmmAcquirerAccount",
|
18
|
+
"retry.attempt1.avsResultRaw": "5",
|
19
|
+
"retry.attempt1.rawResponse": "AUTHORISED",
|
20
|
+
"retry.attempt1.responseCode": "Approved",
|
21
|
+
"retry.attempt1.scaExemptionRequested": "lowValue",
|
22
|
+
"scaExemptionRequested": "lowValue"
|
23
|
+
},
|
24
|
+
"amount": {
|
25
|
+
"currency": "EUR",
|
26
|
+
"value": 1000
|
27
|
+
},
|
28
|
+
"eventCode": "AUTHORISATION",
|
29
|
+
"eventDate": "2023-01-10T13:40:54+01:00",
|
30
|
+
"merchantAccountCode": "AntoniStroinski",
|
31
|
+
"merchantReference": ":slashes are fun",
|
32
|
+
"operations": [
|
33
|
+
"CANCEL",
|
34
|
+
"CAPTURE",
|
35
|
+
"REFUND"
|
36
|
+
],
|
37
|
+
"paymentMethod": "visa",
|
38
|
+
"pspReference": "M8NB66SBZSGLNK82",
|
39
|
+
"reason": "039404:1111:03/2030",
|
40
|
+
"success": "true"
|
41
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"amount": {
|
3
|
+
"value": 1000,
|
4
|
+
"currency": "EUR"
|
5
|
+
},
|
6
|
+
"reason": "087330:1111:03/2030",
|
7
|
+
"success": "true",
|
8
|
+
"eventCode": "AUTHORISATION",
|
9
|
+
"eventDate": "2023-01-10T13:37:30+01:00",
|
10
|
+
"operations": [
|
11
|
+
"CANCEL",
|
12
|
+
"CAPTURE",
|
13
|
+
"REFUND"
|
14
|
+
],
|
15
|
+
"pspReference": "X3GWNS6KJ8NKGK82",
|
16
|
+
"paymentMethod": "visa",
|
17
|
+
"additionalData": {
|
18
|
+
"authCode": "087330",
|
19
|
+
"avsResult": "5 No AVS data provided",
|
20
|
+
"cvcResult": "1 Matches",
|
21
|
+
"expiryDate": "03/2030",
|
22
|
+
"cardSummary": "1111",
|
23
|
+
"acquirerCode": "TestPmmAcquirer",
|
24
|
+
"avsResultRaw": "5",
|
25
|
+
"cvcResultRaw": "M",
|
26
|
+
"hmacSignature": "9Z0xdpG9Xi3zcmXv14t/BvMBut77O/Xq9D4CQXSDUi4=",
|
27
|
+
"paymentMethod": "visa",
|
28
|
+
"refusalReasonRaw": "AUTHORISED",
|
29
|
+
"acquirerReference": "HHCCC326PH6",
|
30
|
+
"scaExemptionRequested": "lowValue",
|
31
|
+
"checkout.cardAddedBrand": "visa",
|
32
|
+
"retry.attempt1.acquirer": "TestPmmAcquirer",
|
33
|
+
"retry.attempt1.rawResponse": "AUTHORISED",
|
34
|
+
"retry.attempt1.avsResultRaw": "5",
|
35
|
+
"retry.attempt1.responseCode": "Approved",
|
36
|
+
"retry.attempt1.acquirerAccount": "TestPmmAcquirerAccount",
|
37
|
+
"retry.attempt1.scaExemptionRequested": "lowValue"
|
38
|
+
},
|
39
|
+
"merchantReference": "//slashes are fun",
|
40
|
+
"merchantAccountCode": "AntoniStroinski"
|
41
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"additionalData": {
|
3
|
+
"acquirerCode": "TestPmmAcquirer",
|
4
|
+
"acquirerReference": "J8DXDJ2PV6P",
|
5
|
+
"authCode": "052095",
|
6
|
+
"avsResult": "5 No AVS data provided",
|
7
|
+
"avsResultRaw": "5",
|
8
|
+
"cardSummary": "1111",
|
9
|
+
"checkout.cardAddedBrand": "visa",
|
10
|
+
"cvcResult": "1 Matches",
|
11
|
+
"cvcResultRaw": "M",
|
12
|
+
"expiryDate": "03/2030",
|
13
|
+
"hmacSignature": "CZErGCNQaSsxbaQfZaJlakqo7KPP+mIa8a+wx3yNs9A=",
|
14
|
+
"paymentMethod": "visa",
|
15
|
+
"refusalReasonRaw": "AUTHORISED",
|
16
|
+
"retry.attempt1.acquirer": "TestPmmAcquirer",
|
17
|
+
"retry.attempt1.acquirerAccount": "TestPmmAcquirerAccount",
|
18
|
+
"retry.attempt1.avsResultRaw": "5",
|
19
|
+
"retry.attempt1.rawResponse": "AUTHORISED",
|
20
|
+
"retry.attempt1.responseCode": "Approved",
|
21
|
+
"retry.attempt1.scaExemptionRequested": "lowValue",
|
22
|
+
"scaExemptionRequested": "lowValue"
|
23
|
+
},
|
24
|
+
"amount": {
|
25
|
+
"currency": "EUR",
|
26
|
+
"value": 1000
|
27
|
+
},
|
28
|
+
"eventCode": "AUTHORISATION",
|
29
|
+
"eventDate": "2023-01-10T13:42:29+01:00",
|
30
|
+
"merchantAccountCode": "AntoniStroinski",
|
31
|
+
"merchantReference": "\\:/\\/slashes are fun",
|
32
|
+
"operations": [
|
33
|
+
"CANCEL",
|
34
|
+
"CAPTURE",
|
35
|
+
"REFUND"
|
36
|
+
],
|
37
|
+
"paymentMethod": "visa",
|
38
|
+
"pspReference": "ZVWN7D3WSMK2WN82",
|
39
|
+
"reason": "052095:1111:03/2030",
|
40
|
+
"success": "true"
|
41
|
+
}
|
@@ -28,12 +28,6 @@ RSpec.describe Adyen::Utils::HmacValidator do
|
|
28
28
|
expect(data_to_sign).to eq '7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true'
|
29
29
|
end
|
30
30
|
|
31
|
-
it 'should get correct data with escaped characters' do
|
32
|
-
notification_request_item['merchantAccountCode'] = 'Test:\\Merchant'
|
33
|
-
data_to_sign = validator.data_to_sign(notification_request_item)
|
34
|
-
expect(data_to_sign).to eq '7914073381342284::Test\\:\\Merchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true'
|
35
|
-
end
|
36
|
-
|
37
31
|
it 'should encrypt properly' do
|
38
32
|
encrypted = validator.calculate_notification_hmac(notification_request_item, key)
|
39
33
|
expect(encrypted).to eq expected_sign
|
@@ -48,5 +42,25 @@ RSpec.describe Adyen::Utils::HmacValidator do
|
|
48
42
|
|
49
43
|
expect(validator.valid_notification_hmac?(notification_request_item, key)).to be false
|
50
44
|
end
|
45
|
+
|
46
|
+
it 'should validate backslashes correctly' do
|
47
|
+
webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/backslash_notification.json"))
|
48
|
+
expect(validator.valid_notification_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should validate colons correctly' do
|
52
|
+
webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/colon_notification.json"))
|
53
|
+
expect(validator.valid_notification_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should validate forward slashes correctly' do
|
57
|
+
webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/forwardslash_notification.json"))
|
58
|
+
expect(validator.valid_notification_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should validate mix of slashes and colon correctly' do
|
62
|
+
webhook = JSON.parse(json_from_file("mocks/responses/Webhooks/mixed_notification.json"))
|
63
|
+
expect(validator.valid_notification_hmac?(webhook, '74F490DD33F7327BAECC88B2947C011FC02D014A473AAA33A8EC93E4DC069174')).to be true
|
64
|
+
end
|
51
65
|
end
|
52
66
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adyen-ruby-api-library
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adyen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
82
82
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
83
83
|
- ".github/dependabot.yml"
|
84
|
+
- ".github/workflows/codeql.yml"
|
84
85
|
- ".github/workflows/ruby.yml"
|
85
86
|
- ".github/workflows/rubygems_release.yml"
|
86
87
|
- ".gitignore"
|
@@ -256,6 +257,7 @@ files:
|
|
256
257
|
- spec/mocks/responses/Checkout/psp_cancel.json
|
257
258
|
- spec/mocks/responses/Checkout/refund.json
|
258
259
|
- spec/mocks/responses/Checkout/sessions-success.json
|
260
|
+
- spec/mocks/responses/Checkout/stored_payment_methods.json
|
259
261
|
- spec/mocks/responses/Checkout/update-payment-link.json
|
260
262
|
- spec/mocks/responses/Checkout/verify.json
|
261
263
|
- spec/mocks/responses/DataProtectionService/request_subject_erasure.json
|
@@ -303,6 +305,10 @@ files:
|
|
303
305
|
- spec/mocks/responses/Terminal/assign_terminals.json
|
304
306
|
- spec/mocks/responses/Terminal/find_terminal.json
|
305
307
|
- spec/mocks/responses/Terminal/get_terminals_under_account.json
|
308
|
+
- spec/mocks/responses/Webhooks/backslash_notification.json
|
309
|
+
- spec/mocks/responses/Webhooks/colon_notification.json
|
310
|
+
- spec/mocks/responses/Webhooks/forwardslash_notification.json
|
311
|
+
- spec/mocks/responses/Webhooks/mixed_notification.json
|
306
312
|
- spec/notification_spec.rb
|
307
313
|
- spec/payments_spec.rb
|
308
314
|
- spec/payouts_spec.rb
|
@@ -333,7 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
333
339
|
- !ruby/object:Gem::Version
|
334
340
|
version: '0'
|
335
341
|
requirements: []
|
336
|
-
rubygems_version: 3.
|
342
|
+
rubygems_version: 3.1.2
|
337
343
|
signing_key:
|
338
344
|
specification_version: 4
|
339
345
|
summary: Official Adyen Ruby API Library
|