perata-sdk 0.1.1 → 0.3.0
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/README.md +23 -8
- data/lib/perata/client.rb +53 -0
- data/lib/perata/models.rb +1905 -221
- data/lib/perata/params.rb +644 -0
- data/lib/perata/services.rb +534 -18
- data/lib/perata/version.rb +1 -1
- data/lib/perata/webhooks.rb +108 -12
- metadata +2 -2
data/lib/perata/version.rb
CHANGED
data/lib/perata/webhooks.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Code generated by sdk/generator. DO NOT EDIT.
|
|
4
|
+
|
|
3
5
|
require "json"
|
|
4
6
|
require "openssl"
|
|
5
7
|
|
|
@@ -15,13 +17,19 @@ module Perata
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
#
|
|
20
|
+
# A webhook Peráta sent, verified: one subclass a kind of data
|
|
21
|
+
# (OrderWebhookEvent carries an Order…), or UnknownWebhookEvent for a type
|
|
22
|
+
# this SDK does not know yet. Within a class, +type+ says what happened.
|
|
19
23
|
class WebhookEvent < Model
|
|
20
24
|
MEMBERS = %i[id type timestamp data].freeze
|
|
21
25
|
|
|
22
|
-
# @return [String]
|
|
23
|
-
attr_reader :id
|
|
24
|
-
# @return [
|
|
26
|
+
# @return [String] the message's id, the same as the webhook-id header
|
|
27
|
+
attr_reader :id
|
|
28
|
+
# @return [String] what happened: order.paid…
|
|
29
|
+
attr_reader :type
|
|
30
|
+
# @return [String] when it happened, in RFC 3339
|
|
31
|
+
attr_reader :timestamp
|
|
32
|
+
# @return [Object] what the event carries
|
|
25
33
|
attr_reader :data
|
|
26
34
|
|
|
27
35
|
def initialize(id:, type:, timestamp:, data:)
|
|
@@ -33,16 +41,86 @@ module Perata
|
|
|
33
41
|
end
|
|
34
42
|
end
|
|
35
43
|
|
|
44
|
+
# The events that carry a WebhookBenefit; +data+ is WebhookBenefit.
|
|
45
|
+
class BenefitWebhookEvent < WebhookEvent
|
|
46
|
+
TYPES = %w[benefit.created benefit.updated].freeze
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The events that carry a BenefitGrant; +data+ is BenefitGrant.
|
|
50
|
+
class BenefitGrantWebhookEvent < WebhookEvent
|
|
51
|
+
TYPES = %w[benefit_grant.created benefit_grant.revoked benefit_grant.updated].freeze
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The events that carry a WebhookCheckout; +data+ is WebhookCheckout.
|
|
55
|
+
class CheckoutWebhookEvent < WebhookEvent
|
|
56
|
+
TYPES = %w[checkout.created checkout.expired checkout.updated].freeze
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The events that carry a Customer; +data+ is Customer.
|
|
60
|
+
class CustomerWebhookEvent < WebhookEvent
|
|
61
|
+
TYPES = %w[customer.created customer.deleted customer.updated].freeze
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The events that carry a WebhookDiscount; +data+ is WebhookDiscount.
|
|
65
|
+
class DiscountWebhookEvent < WebhookEvent
|
|
66
|
+
TYPES = %w[discount.created discount.deleted discount.updated].freeze
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The events that carry a WebhookDispute; +data+ is WebhookDispute.
|
|
70
|
+
class DisputeWebhookEvent < WebhookEvent
|
|
71
|
+
TYPES = %w[dispute.lost dispute.opened dispute.won].freeze
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The events that carry the event's identifiers; +data+ is Hash{String => String}.
|
|
75
|
+
class IdentifiersWebhookEvent < WebhookEvent
|
|
76
|
+
TYPES = %w[benefit.archived benefit.version_created benefit_product_link.linked benefit_product_link.unlinked checkout_link.archived checkout_link.created checkout_payment.authorized checkout_payment.canceled checkout_payment.captured checkout_payment.partially_refunded checkout_payment.refunded checkout_payment.refused checkout_session.confirmed checkout_session.expired checkout_session.failed checkout_session.opened checkout_session.succeeded customer.archived discount.exhausted discount.expired discount.reactivated discount.redeemed discount_redemption.released invoice.drafted invoice.issued invoice.settled invoice.uncollectible invoice.voided price.archived price.created product.archived refund.canceled refund.failed refund.requested refund.succeeded seat_allocation.opened seat_allocation.resized seat_assignment.claimed seat_assignment.invited seat_assignment.revoked usage_event.recorded usage_period.closed usage_period.opened usage_period_adjustment.created].freeze
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# The events that carry an Order; +data+ is Order.
|
|
80
|
+
class OrderWebhookEvent < WebhookEvent
|
|
81
|
+
TYPES = %w[order.created order.paid order.refunded order.updated].freeze
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The events that carry a Product; +data+ is Product.
|
|
85
|
+
class ProductWebhookEvent < WebhookEvent
|
|
86
|
+
TYPES = %w[product.created product.updated].freeze
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The events that carry a Refund; +data+ is Refund.
|
|
90
|
+
class RefundWebhookEvent < WebhookEvent
|
|
91
|
+
TYPES = %w[refund.created refund.updated].freeze
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The events that carry a Subscription; +data+ is Subscription.
|
|
95
|
+
class SubscriptionWebhookEvent < WebhookEvent
|
|
96
|
+
TYPES = %w[subscription.active subscription.canceled subscription.created subscription.cycled subscription.past_due subscription.paused subscription.resumed subscription.revoked subscription.uncanceled subscription.updated].freeze
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# An event of a type this SDK does not know yet, its data as it was sent.
|
|
100
|
+
class UnknownWebhookEvent < WebhookEvent
|
|
101
|
+
end
|
|
102
|
+
|
|
36
103
|
# Checks a webhook Peráta sent and answers its event.
|
|
37
104
|
#
|
|
38
105
|
# The signature is an HMAC-SHA256 of +{webhook-id}.{webhook-timestamp}.{body}+
|
|
39
|
-
# under the key the endpoint's +whsec_+ secret encodes
|
|
40
|
-
#
|
|
41
|
-
#
|
|
106
|
+
# under the key the endpoint's +whsec_+ secret encodes, one of the signatures
|
|
107
|
+
# in the +webhook-signature+ header, which carries more than one while a
|
|
108
|
+
# secret is rotated. Pass the body exactly as it arrived, before parsing it;
|
|
109
|
+
# +headers+ is a hash of the request's headers, in any case, or a Rack env.
|
|
42
110
|
#
|
|
43
111
|
# @return [WebhookEvent]
|
|
44
112
|
# @raise [WebhookVerificationError]
|
|
45
113
|
def self.verify_webhook(secret, headers, body, now: Time.now)
|
|
114
|
+
verify_webhook_signature(secret, headers, body, now: now)
|
|
115
|
+
webhook_event(body.to_s.b.force_encoding(Encoding::UTF_8))
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Checks a webhook's signature as verify_webhook does, without reading its
|
|
119
|
+
# body.
|
|
120
|
+
#
|
|
121
|
+
# @return [nil]
|
|
122
|
+
# @raise [WebhookVerificationError]
|
|
123
|
+
def self.verify_webhook_signature(secret, headers, body, now: Time.now)
|
|
46
124
|
key = begin
|
|
47
125
|
secret.delete_prefix("whsec_").unpack1("m0")
|
|
48
126
|
rescue ArgumentError
|
|
@@ -66,15 +144,33 @@ module Perata
|
|
|
66
144
|
rescue ArgumentError
|
|
67
145
|
next
|
|
68
146
|
end
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
event = JSON.parse(raw.force_encoding(Encoding::UTF_8))
|
|
72
|
-
return WebhookEvent.new(id: event.fetch("id"), type: event.fetch("type"), timestamp: event.fetch("timestamp"),
|
|
73
|
-
data: event["data"] || {})
|
|
147
|
+
return nil if decoded.bytesize == expected.bytesize && OpenSSL.fixed_length_secure_compare(decoded, expected)
|
|
74
148
|
end
|
|
75
149
|
raise WebhookVerificationError
|
|
76
150
|
end
|
|
77
151
|
|
|
152
|
+
# A verified body as the event its type names.
|
|
153
|
+
def self.webhook_event(raw)
|
|
154
|
+
event = JSON.parse(raw)
|
|
155
|
+
data = event["data"] || {}
|
|
156
|
+
message = { id: event.fetch("id"), type: event.fetch("type"), timestamp: event.fetch("timestamp") }
|
|
157
|
+
case message[:type]
|
|
158
|
+
when *BenefitWebhookEvent::TYPES then BenefitWebhookEvent.new(**message, data: WebhookBenefit.from_hash(data))
|
|
159
|
+
when *BenefitGrantWebhookEvent::TYPES then BenefitGrantWebhookEvent.new(**message, data: BenefitGrant.from_hash(data))
|
|
160
|
+
when *CheckoutWebhookEvent::TYPES then CheckoutWebhookEvent.new(**message, data: WebhookCheckout.from_hash(data))
|
|
161
|
+
when *CustomerWebhookEvent::TYPES then CustomerWebhookEvent.new(**message, data: Customer.from_hash(data))
|
|
162
|
+
when *DiscountWebhookEvent::TYPES then DiscountWebhookEvent.new(**message, data: WebhookDiscount.from_hash(data))
|
|
163
|
+
when *DisputeWebhookEvent::TYPES then DisputeWebhookEvent.new(**message, data: WebhookDispute.from_hash(data))
|
|
164
|
+
when *IdentifiersWebhookEvent::TYPES then IdentifiersWebhookEvent.new(**message, data: data)
|
|
165
|
+
when *OrderWebhookEvent::TYPES then OrderWebhookEvent.new(**message, data: Order.from_hash(data))
|
|
166
|
+
when *ProductWebhookEvent::TYPES then ProductWebhookEvent.new(**message, data: Product.from_hash(data))
|
|
167
|
+
when *RefundWebhookEvent::TYPES then RefundWebhookEvent.new(**message, data: Refund.from_hash(data))
|
|
168
|
+
when *SubscriptionWebhookEvent::TYPES then SubscriptionWebhookEvent.new(**message, data: Subscription.from_hash(data))
|
|
169
|
+
else UnknownWebhookEvent.new(**message, data: data)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
private_class_method :webhook_event
|
|
173
|
+
|
|
78
174
|
# A header's value, looked up in any case; a Rack env's HTTP_WEBHOOK_ID
|
|
79
175
|
# names webhook-id.
|
|
80
176
|
def self.webhook_header(headers, name)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: perata-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peráta
|
|
@@ -45,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: '0'
|
|
47
47
|
requirements: []
|
|
48
|
-
rubygems_version:
|
|
48
|
+
rubygems_version: 3.6.9
|
|
49
49
|
specification_version: 4
|
|
50
50
|
summary: 'Peráta''s SDK for Ruby: products, customers, checkouts, payments, subscriptions
|
|
51
51
|
and webhooks.'
|