abacatepay-ruby 1.1.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +137 -19
- data/README.md +43 -24
- data/abacatepay-ruby.gemspec +1 -1
- data/lib/abacate_pay/clients/billing_client.rb +2 -2
- data/lib/abacate_pay/clients/checkout_client.rb +1 -1
- data/lib/abacate_pay/clients/client.rb +66 -15
- data/lib/abacate_pay/clients/coupon_client.rb +4 -1
- data/lib/abacate_pay/clients/customer_client.rb +4 -1
- data/lib/abacate_pay/clients/payment_link_client.rb +2 -2
- data/lib/abacate_pay/clients/payout_client.rb +7 -1
- data/lib/abacate_pay/clients/pix_client.rb +11 -3
- data/lib/abacate_pay/clients/product_client.rb +4 -1
- data/lib/abacate_pay/clients/store_client.rb +3 -1
- data/lib/abacate_pay/clients/subscription_client.rb +5 -10
- data/lib/abacate_pay/clients/transparent_client.rb +4 -2
- data/lib/abacate_pay/clients/webhook_client.rb +21 -4
- data/lib/abacate_pay/clients.rb +1 -1
- data/lib/abacate_pay/configuration.rb +3 -3
- data/lib/abacate_pay/enums/billings/methods.rb +1 -1
- data/lib/abacate_pay/enums/checkouts/statuses.rb +4 -1
- data/lib/abacate_pay/enums/coupons/statuses.rb +4 -1
- data/lib/abacate_pay/enums/webhooks/event_types.rb +1 -1
- data/lib/abacate_pay/resources/coupons.rb +29 -3
- data/lib/abacate_pay/resources/customers.rb +62 -21
- data/lib/abacate_pay/resources/payouts.rb +6 -0
- data/lib/abacate_pay/resources/resource.rb +21 -5
- data/lib/abacate_pay/resources/transparents.rb +21 -4
- data/lib/abacate_pay/resources/webhook_endpoints.rb +1 -1
- data/lib/abacate_pay/resources.rb +1 -1
- data/lib/abacate_pay/version.rb +1 -1
- data/lib/abacate_pay/webhooks.rb +53 -7
- data/lib/abacatepay-ruby.rb +14 -0
- metadata +4 -3
data/lib/abacate_pay/webhooks.rb
CHANGED
|
@@ -17,33 +17,65 @@ module AbacatePay
|
|
|
17
17
|
# Raised when a webhook body is not a JSON object the SDK can interpret.
|
|
18
18
|
class PayloadError < AbacatePay::Error; end
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# AbacatePay signs every delivery with this fixed key, published at
|
|
21
|
+
# https://docs.abacatepay.com/pages/webhooks/security and hard-coded in the
|
|
22
|
+
# Node, Python and Go samples there.
|
|
23
|
+
#
|
|
24
|
+
# It is public and global, so it proves only that the body was not altered
|
|
25
|
+
# in transit, it does NOT prove the request came from AbacatePay, since
|
|
26
|
+
# anyone can compute a valid signature with it. Origin is authenticated by
|
|
27
|
+
# the `webhookSecret` query parameter; see {verify_secret!}. Use both.
|
|
28
|
+
PUBLIC_KEY = "t9dXRhHHo3yDEj5pVDYz0frf7q6bMKyMRmxxCPIPp3RCplBfXRxqlC6ZpiWmOqj4L63qEaeUOtrCI8P0VMU" \
|
|
29
|
+
"go6iIga2ri9ogaHFs0WIIywSMg0q7RmBfybe1E5XJcfC4IW3alNqym0tXoAKkzvfEjZxV6bE0oG2zJrNNYmU" \
|
|
30
|
+
"CKZyV0KZ3JS8Votf9EAWWYdiDkMkpbMdPggfh1EqHlVkMiTady6jOR3hyzGEHrIz2Ret0xHKMbiqkr9HS1Jh" \
|
|
31
|
+
"NHDX9"
|
|
32
|
+
|
|
33
|
+
# Verifies the `X-Webhook-Signature` header: HMAC-SHA256 over the raw body,
|
|
34
|
+
# base64-encoded.
|
|
21
35
|
#
|
|
22
36
|
# @param payload [String] The raw request body
|
|
23
37
|
# @param signature [String] The X-Webhook-Signature header value
|
|
24
|
-
# @param secret [String]
|
|
38
|
+
# @param secret [String] HMAC key. Defaults to {PUBLIC_KEY}, which is what
|
|
39
|
+
# AbacatePay signs with.
|
|
25
40
|
# @return [true] if signature is valid
|
|
26
41
|
# @raise [SignatureError] if the signature is missing or invalid
|
|
27
|
-
def self.verify!(payload:, signature:, secret:)
|
|
42
|
+
def self.verify!(payload:, signature:, secret: PUBLIC_KEY)
|
|
28
43
|
raise SignatureError, "Missing webhook signature" if signature.nil? || signature.to_s.empty?
|
|
29
44
|
raise SignatureError, "Missing webhook secret" if secret.nil? || secret.to_s.empty?
|
|
30
45
|
|
|
31
|
-
expected =
|
|
46
|
+
expected = base64_hmac(secret.to_s, payload.to_s)
|
|
32
47
|
raise SignatureError, "Invalid webhook signature" unless secure_compare(expected, signature.to_s)
|
|
33
48
|
|
|
34
49
|
true
|
|
35
50
|
end
|
|
36
51
|
|
|
52
|
+
# Verifies the `webhookSecret` query parameter, which is what actually
|
|
53
|
+
# authenticates the request as coming from AbacatePay.
|
|
54
|
+
#
|
|
55
|
+
# The HMAC signature alone cannot do this: it is computed with a public key.
|
|
56
|
+
#
|
|
57
|
+
# @param received [String] The `webhookSecret` query parameter as received
|
|
58
|
+
# @param expected [String] The secret you configured on the webhook
|
|
59
|
+
# @return [true] if they match
|
|
60
|
+
# @raise [SignatureError] if either is missing or they differ
|
|
61
|
+
def self.verify_secret!(received:, expected:)
|
|
62
|
+
raise SignatureError, "Missing webhook secret parameter" if received.nil? || received.to_s.empty?
|
|
63
|
+
raise SignatureError, "Missing expected webhook secret" if expected.nil? || expected.to_s.empty?
|
|
64
|
+
raise SignatureError, "Invalid webhook secret" unless secure_compare(expected.to_s, received.to_s)
|
|
65
|
+
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
|
|
37
69
|
# Checks if a webhook signature is valid.
|
|
38
70
|
#
|
|
39
|
-
# Never raises for untrusted input
|
|
71
|
+
# Never raises for untrusted input, a missing header, an empty secret, or a
|
|
40
72
|
# forged signature all return false.
|
|
41
73
|
#
|
|
42
74
|
# @param payload [String] The raw request body
|
|
43
75
|
# @param signature [String] The X-Webhook-Signature header value
|
|
44
76
|
# @param secret [String] Your webhook secret/public key
|
|
45
77
|
# @return [Boolean]
|
|
46
|
-
def self.valid?(payload:, signature:, secret:)
|
|
78
|
+
def self.valid?(payload:, signature:, secret: PUBLIC_KEY)
|
|
47
79
|
verify!(payload: payload, signature: signature, secret: secret)
|
|
48
80
|
true
|
|
49
81
|
rescue SignatureError
|
|
@@ -78,11 +110,25 @@ module AbacatePay
|
|
|
78
110
|
# @return [Event] The verified, parsed event
|
|
79
111
|
# @raise [SignatureError] if the signature is missing or invalid
|
|
80
112
|
# @raise [PayloadError] if the body is not a JSON object
|
|
81
|
-
def self.construct_event(payload:, signature:, secret:)
|
|
113
|
+
def self.construct_event(payload:, signature:, secret: PUBLIC_KEY)
|
|
82
114
|
verify!(payload: payload, signature: signature, secret: secret)
|
|
83
115
|
parse(payload)
|
|
84
116
|
end
|
|
85
117
|
|
|
118
|
+
# Base64-encoded HMAC-SHA256, matching what AbacatePay sends.
|
|
119
|
+
#
|
|
120
|
+
# Uses Array#pack rather than the base64 gem: base64 stopped being a default
|
|
121
|
+
# gem in Ruby 3.4, and requiring it would add a runtime dependency for one
|
|
122
|
+
# call.
|
|
123
|
+
#
|
|
124
|
+
# @param secret [String] The HMAC key
|
|
125
|
+
# @param payload [String] The raw body
|
|
126
|
+
# @return [String] The base64 signature
|
|
127
|
+
def self.base64_hmac(secret, payload)
|
|
128
|
+
[OpenSSL::HMAC.digest("SHA256", secret, payload)].pack("m0")
|
|
129
|
+
end
|
|
130
|
+
private_class_method :base64_hmac
|
|
131
|
+
|
|
86
132
|
# Constant-time comparison to prevent timing attacks.
|
|
87
133
|
#
|
|
88
134
|
# @param expected [String] The signature computed from the payload
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Entry point matching the gem name.
|
|
4
|
+
#
|
|
5
|
+
# Bundler requires a gem by its own name, so `gem "abacatepay-ruby"` in a
|
|
6
|
+
# Gemfile makes Rails call `require "abacatepay-ruby"` (and then
|
|
7
|
+
# `require "abacatepay/ruby"`). Neither matched `lib/abacate_pay.rb`, so the SDK
|
|
8
|
+
# silently failed to load and the first call raised
|
|
9
|
+
# `undefined method 'configure' for module AbacatePay` — the module existed with
|
|
10
|
+
# only VERSION in it, defined as a side effect of the gemspec.
|
|
11
|
+
#
|
|
12
|
+
# This file makes the default `gem "abacatepay-ruby"` work without a `require:`
|
|
13
|
+
# option. `require "abacate_pay"` keeps working for anyone already using it.
|
|
14
|
+
require_relative "abacate_pay"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: abacatepay-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matheus Cardoso
|
|
@@ -105,14 +105,14 @@ dependencies:
|
|
|
105
105
|
requirements:
|
|
106
106
|
- - "~>"
|
|
107
107
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: '0
|
|
108
|
+
version: '1.0'
|
|
109
109
|
type: :development
|
|
110
110
|
prerelease: false
|
|
111
111
|
version_requirements: !ruby/object:Gem::Requirement
|
|
112
112
|
requirements:
|
|
113
113
|
- - "~>"
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: '0
|
|
115
|
+
version: '1.0'
|
|
116
116
|
description: The easiest way to integrate your Ruby application with AbacatePay Gateway
|
|
117
117
|
for payments, subscriptions, PIX transfers, and more.
|
|
118
118
|
email:
|
|
@@ -178,6 +178,7 @@ files:
|
|
|
178
178
|
- lib/abacate_pay/version.rb
|
|
179
179
|
- lib/abacate_pay/webhooks.rb
|
|
180
180
|
- lib/abacate_pay/webhooks/event.rb
|
|
181
|
+
- lib/abacatepay-ruby.rb
|
|
181
182
|
homepage: https://www.abacatepay.com/
|
|
182
183
|
licenses:
|
|
183
184
|
- MIT
|