dpay 0.1.0 → 0.2.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +100 -4
  4. data/lib/dpay/blik/blik_alias_type.rb +2 -2
  5. data/lib/dpay/blik/blik_service.rb +0 -9
  6. data/lib/dpay/card/card_service.rb +21 -5
  7. data/lib/dpay/client.rb +3 -1
  8. data/lib/dpay/errors.rb +13 -6
  9. data/lib/dpay/internal/checksum_calculator.rb +27 -2
  10. data/lib/dpay/internal/error_mapper.rb +11 -2
  11. data/lib/dpay/internal/php.rb +6 -0
  12. data/lib/dpay/ipn/ipn_event.rb +2 -0
  13. data/lib/dpay/ipn/ipn_type.rb +1 -0
  14. data/lib/dpay/payment/payment_service.rb +4 -4
  15. data/lib/dpay/payment/register_payment_request.rb +92 -13
  16. data/lib/dpay/payment/registered_payment.rb +19 -0
  17. data/lib/dpay/payment/return_urls.rb +3 -1
  18. data/lib/dpay/payment/transaction_type.rb +1 -3
  19. data/lib/dpay/recurring/recurring_registration.rb +162 -0
  20. data/lib/dpay/recurring/recurring_registration_info.rb +45 -0
  21. data/lib/dpay/recurring/recurring_retry_result.rb +43 -0
  22. data/lib/dpay/recurring/recurring_service.rb +59 -0
  23. data/lib/dpay/recurring/recurring_status.rb +42 -0
  24. data/lib/dpay/refund/refund_service.rb +10 -4
  25. data/lib/dpay/version.rb +1 -1
  26. data/lib/dpay/webhook/event_page.rb +25 -0
  27. data/lib/dpay/webhook/event_service.rb +76 -0
  28. data/lib/dpay/webhook/webhook_event.rb +42 -0
  29. data/lib/dpay/webhook/webhook_event_type.rb +43 -0
  30. data/lib/dpay/webhook/webhook_target.rb +45 -0
  31. data/lib/dpay/webhook/webhook_verifier.rb +110 -0
  32. data/lib/dpay.rb +11 -3
  33. data/sig/dpay/blik/blik_alias_type.rbs +0 -1
  34. data/sig/dpay/blik/blik_service.rbs +0 -1
  35. data/sig/dpay/card/card_service.rbs +1 -1
  36. data/sig/dpay/client.rbs +2 -0
  37. data/sig/dpay/errors.rbs +6 -2
  38. data/sig/dpay/internal/checksum_calculator.rbs +8 -1
  39. data/sig/dpay/internal/error_mapper.rbs +1 -0
  40. data/sig/dpay/internal/php.rbs +2 -0
  41. data/sig/dpay/ipn/ipn_event.rbs +2 -0
  42. data/sig/dpay/ipn/ipn_type.rbs +1 -0
  43. data/sig/dpay/payment/register_payment_request.rbs +13 -1
  44. data/sig/dpay/payment/registered_payment.rbs +6 -0
  45. data/sig/dpay/payment/return_urls.rbs +2 -2
  46. data/sig/dpay/payment/transaction_type.rbs +0 -2
  47. data/sig/dpay/recurring/recurring_registration.rbs +45 -0
  48. data/sig/dpay/{blik/blik_recurring_registration_info.rbs → recurring/recurring_registration_info.rbs} +13 -3
  49. data/sig/dpay/recurring/recurring_retry_result.rbs +24 -0
  50. data/sig/dpay/recurring/recurring_service.rbs +15 -0
  51. data/sig/dpay/recurring/recurring_status.rbs +27 -0
  52. data/sig/dpay/refund/refund_service.rbs +2 -2
  53. data/sig/dpay/webhook/event_page.rbs +14 -0
  54. data/sig/dpay/webhook/event_service.rbs +21 -0
  55. data/sig/dpay/webhook/webhook_event.rbs +24 -0
  56. data/sig/dpay/webhook/webhook_event_type.rbs +23 -0
  57. data/sig/dpay/webhook/webhook_target.rbs +15 -0
  58. data/sig/dpay/webhook/webhook_verifier.rbs +37 -0
  59. metadata +26 -10
  60. data/lib/dpay/blik/blik_recurring_registration.rb +0 -74
  61. data/lib/dpay/blik/blik_recurring_registration_info.rb +0 -26
  62. data/lib/dpay/blik/blik_recurring_status.rb +0 -28
  63. data/sig/dpay/blik/blik_recurring_registration.rbs +0 -24
  64. data/sig/dpay/blik/blik_recurring_status.rbs +0 -17
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "openssl"
5
+
6
+ module DPay
7
+ # Verifies dpay webhooks (Standard Webhooks):
8
+ # "webhook-signature" = "v1," + base64(HMAC-SHA256(key, id.timestamp.body)), where the key is the base64-decoded
9
+ # secret without the "whsec_" prefix. During a secret rotation dpay sends two signatures separated by a space -
10
+ # one match is enough.
11
+ module WebhookVerifier
12
+ DEFAULT_TOLERANCE = 300
13
+ SECRET_PREFIX = "whsec_"
14
+ SIGNATURE_VERSION = "v1"
15
+ ID_HEADER = "webhook-id"
16
+ TIMESTAMP_HEADER = "webhook-timestamp"
17
+ SIGNATURE_HEADER = "webhook-signature"
18
+ RACK_PREFIX = "http-"
19
+ TIMESTAMP = /\A\d+\z/
20
+ BASE64 = %r{\A([A-Za-z0-9+/]*)(=*)\z}
21
+ BASE64_WHITESPACE = " \t\r\n"
22
+ INVALID_SECRET = "Webhook secret must be the whsec_ value from the dpay panel"
23
+
24
+ module_function
25
+
26
+ # Verifies the signature and returns the event. Pass the raw request body exactly as received. headers: Hash
27
+ # (or anything with #each yielding name and value) with String or Symbol names in any letter case, also in
28
+ # the Rack format (HTTP_WEBHOOK_ID); a value may be an Array (the first element counts). secrets: the "whsec_..."
29
+ # secret or an Array of secrets during a rotation.
30
+ def construct_event(raw_body, headers, secrets, tolerance = DEFAULT_TOLERANCE, now = nil)
31
+ verify(raw_body, headers, secrets, tolerance, now)
32
+
33
+ payload = begin
34
+ JSON.parse(raw_body.to_s)
35
+ rescue JSON::ParserError
36
+ nil
37
+ end
38
+ raise SignatureVerificationError, "Invalid webhook payload" unless payload.is_a?(Hash)
39
+
40
+ WebhookEvent.from_api(payload)
41
+ end
42
+
43
+ def verify(raw_body, headers, secrets, tolerance = DEFAULT_TOLERANCE, now = nil)
44
+ id = header(headers, ID_HEADER)
45
+ timestamp = header(headers, TIMESTAMP_HEADER)
46
+ signature = header(headers, SIGNATURE_HEADER)
47
+ if id.nil? || timestamp.nil? || signature.nil?
48
+ raise SignatureVerificationError, "Missing webhook-id, webhook-timestamp or webhook-signature header"
49
+ end
50
+ raise SignatureVerificationError, "Invalid webhook-timestamp header" unless TIMESTAMP.match?(timestamp)
51
+ if ((now || Time.now.to_i) - timestamp.to_i).abs > tolerance
52
+ raise SignatureVerificationError, "Webhook timestamp is outside the tolerance zone"
53
+ end
54
+
55
+ signed = "#{id}.#{timestamp}.".b + raw_body.to_s.b
56
+ expected = (secrets.is_a?(Array) ? secrets : [secrets]).map do |secret|
57
+ OpenSSL::HMAC.base64digest("SHA256", key(secret), signed)
58
+ end
59
+ return nil if signature_matches?(signature, expected)
60
+
61
+ raise SignatureVerificationError, "No valid webhook signature found"
62
+ end
63
+
64
+ def header(headers, name)
65
+ headers.each do |key, value|
66
+ next unless header_name(key) == name
67
+
68
+ value = value.first if value.is_a?(Array)
69
+ return value.is_a?(String) && !value.empty? ? value : nil
70
+ end
71
+
72
+ nil
73
+ end
74
+
75
+ def header_name(key)
76
+ key.to_s.downcase.tr("_", "-").delete_prefix(RACK_PREFIX)
77
+ end
78
+
79
+ def signature_matches?(header_value, expected)
80
+ header_value.strip.split(/\s+/).any? do |entry|
81
+ version, value = entry.split(",", 2)
82
+ next false unless version == SIGNATURE_VERSION && value.is_a?(String)
83
+
84
+ expected.any? { |candidate| secure_compare(candidate, value) }
85
+ end
86
+ end
87
+
88
+ def secure_compare(expected, actual)
89
+ expected.bytesize == actual.bytesize && OpenSSL.fixed_length_secure_compare(expected, actual)
90
+ end
91
+
92
+ # Decodes the secret like PHP base64_decode($secret, true): whitespace is skipped, the padding may be missing,
93
+ # any other character outside the alphabet makes the secret invalid.
94
+ def key(secret)
95
+ raise InvalidArgumentError, INVALID_SECRET unless secret.is_a?(String)
96
+
97
+ match = BASE64.match(secret.delete_prefix(SECRET_PREFIX).delete(BASE64_WHITESPACE))
98
+ data = match.nil? ? "" : match[1].to_s
99
+ padding = match.nil? ? "" : match[2].to_s
100
+ if data.empty? || data.length % 4 == 1 || padding.length > 2 ||
101
+ (!padding.empty? && (data.length + padding.length) % 4 != 0)
102
+ raise InvalidArgumentError, INVALID_SECRET
103
+ end
104
+
105
+ "#{data}#{"=" * (-data.length % 4)}".unpack1("m").to_s
106
+ end
107
+
108
+ private_class_method :header, :header_name, :signature_matches?, :secure_compare, :key
109
+ end
110
+ end
data/lib/dpay.rb CHANGED
@@ -35,11 +35,19 @@ require_relative "dpay/card/card_service"
35
35
  require_relative "dpay/blik/blik_alias_type"
36
36
  require_relative "dpay/blik/blik_app"
37
37
  require_relative "dpay/blik/blik_alias"
38
- require_relative "dpay/blik/blik_recurring_registration_info"
39
- require_relative "dpay/blik/blik_recurring_status"
40
38
  require_relative "dpay/blik/blik_alias_registration"
41
- require_relative "dpay/blik/blik_recurring_registration"
42
39
  require_relative "dpay/blik/blik_service"
40
+ require_relative "dpay/recurring/recurring_registration"
41
+ require_relative "dpay/recurring/recurring_registration_info"
42
+ require_relative "dpay/recurring/recurring_status"
43
+ require_relative "dpay/recurring/recurring_retry_result"
44
+ require_relative "dpay/recurring/recurring_service"
45
+ require_relative "dpay/webhook/webhook_event_type"
46
+ require_relative "dpay/webhook/webhook_target"
47
+ require_relative "dpay/webhook/webhook_event"
48
+ require_relative "dpay/webhook/webhook_verifier"
49
+ require_relative "dpay/webhook/event_page"
50
+ require_relative "dpay/webhook/event_service"
43
51
  require_relative "dpay/ipn/ipn_type"
44
52
  require_relative "dpay/ipn/ipn_event"
45
53
  require_relative "dpay/ipn/ipn_verifier"
@@ -1,7 +1,6 @@
1
1
  module DPay
2
2
  module BlikAliasType
3
3
  UID: String
4
- PAYID: String
5
4
 
6
5
  ALL: Array[String]
7
6
 
@@ -3,7 +3,6 @@ module DPay
3
3
  def initialize: (Internal::ApiRequestor api) -> void
4
4
  def alias: (String alias_value, ?String alias_type) -> BlikAlias
5
5
  def unregister_alias: (String alias_value, ?String alias_type, ?String? reason) -> nil
6
- def recurring_status: (String alias_value) -> BlikRecurringStatus
7
6
 
8
7
  private
9
8
 
@@ -4,7 +4,7 @@ module DPay
4
4
  def public_key: () -> String
5
5
  def pay_otp: (String transaction_id, CardPaymentRequest request) -> CardPaymentResult
6
6
  def pre_auth: (String transaction_id, CardPaymentRequest request) -> CardPaymentResult
7
- def capture: (String transaction_id, Money amount) -> CardPaymentResult
7
+ def capture: (String transaction_id, Money amount, ?WebhookTarget? webhook) -> CardPaymentResult
8
8
  def cancel: (String transaction_id, ?Money? amount) -> CardPaymentResult
9
9
  def google_pay: (String transaction_id, GooglePayRequest request) -> CardPaymentResult
10
10
  def apple_pay: (String transaction_id, ApplePayRequest request) -> CardPaymentResult
data/sig/dpay/client.rbs CHANGED
@@ -9,6 +9,8 @@ module DPay
9
9
  attr_reader blik: BlikService
10
10
  attr_reader cards: CardService
11
11
  attr_reader payouts: PayoutService
12
+ attr_reader recurring: RecurringService
13
+ attr_reader events: EventService
12
14
 
13
15
  def initialize: (
14
16
  service: String,
data/sig/dpay/errors.rbs CHANGED
@@ -25,13 +25,15 @@ module DPay
25
25
  attr_reader error_code: String?
26
26
  attr_reader field_errors: Hash[String, Array[String]]
27
27
  attr_reader raw_body: String
28
+ attr_reader reason: String?
28
29
 
29
30
  def initialize: (
30
31
  String message,
31
32
  Integer http_status,
32
33
  ?String? error_code,
33
34
  ?Hash[String, Array[String]] field_errors,
34
- ?String raw_body
35
+ ?String raw_body,
36
+ ?String? reason
35
37
  ) -> void
36
38
  end
37
39
 
@@ -67,6 +69,7 @@ module DPay
67
69
 
68
70
  class PaymentRejectedError < ApiError
69
71
  attr_reader transaction_id: String?
72
+ attr_reader error_description: String?
70
73
 
71
74
  def self.from_api: (Hash[String, untyped] data) -> PaymentRejectedError
72
75
 
@@ -76,7 +79,8 @@ module DPay
76
79
  ?String? error_code,
77
80
  ?Hash[String, Array[String]] field_errors,
78
81
  ?String raw_body,
79
- ?String? transaction_id
82
+ ?String? transaction_id,
83
+ ?String? error_description
80
84
  ) -> void
81
85
  end
82
86
 
@@ -1,9 +1,16 @@
1
1
  module DPay
2
2
  module Internal
3
3
  class ChecksumCalculator
4
+ CHECKSUM_KEY: String
5
+
4
6
  def initialize: (String secret_hash) -> void
5
7
  def secret_second: (String service, Array[untyped] fields) -> String
6
- def ordered_body: (Array[untyped] values) -> String
8
+ def ordered_body: (Hash[untyped, untyped] | Array[untyped] body) -> String
9
+ def operation: (String operation, String service, String transaction_id, String? amount) -> String
10
+
11
+ private
12
+
13
+ def leaves: (untyped value) -> Array[untyped]
7
14
  end
8
15
  end
9
16
  end
@@ -4,6 +4,7 @@ module DPay
4
4
  DEFAULT_MESSAGE: String
5
5
 
6
6
  def self?.map: (HTTP::Response response) -> ApiError
7
+ def self?.extract_code: (Hash[String, untyped] data) -> String?
7
8
  def self?.error_class: (Integer status) -> singleton(ApiError)
8
9
  def self?.extract_message: (Hash[String, untyped] data) -> String
9
10
  def self?.rate_limit: (HTTP::Response response, String message) -> RateLimitError
@@ -3,7 +3,9 @@ module DPay
3
3
  module PHP
4
4
  SAFE_INTEGRAL_FLOAT: Integer
5
5
  NON_UNRESERVED: Regexp
6
+ TRIM_EDGES: Regexp
6
7
 
8
+ def self?.trim: (String value) -> String
7
9
  def self?.strval: (untyped value) -> String
8
10
  def self?.round: (Float value) -> Integer
9
11
  def self?.json_encode: (untyped data, ?escape_slashes: bool) -> String
@@ -13,10 +13,12 @@ module DPay
13
13
  def signature: () -> String
14
14
  def email: () -> String?
15
15
  def custom: () -> String?
16
+ %a{deprecated: dpay no longer sends capture IPNs - use the payment.captured webhook event}
16
17
  def capture_payment_id: () -> String?
17
18
  def attempt: () -> Integer
18
19
  def version: () -> Integer
19
20
  def transfer?: () -> bool
21
+ %a{deprecated: dpay no longer sends capture IPNs - use the payment.captured webhook event}
20
22
  def capture?: () -> bool
21
23
  def dcb?: () -> bool
22
24
 
@@ -1,6 +1,7 @@
1
1
  module DPay
2
2
  module IpnType
3
3
  TRANSFER: String
4
+ # Deprecated: dpay no longer sends capture IPNs - use the payment.captured webhook event.
4
5
  CAPTURE: String
5
6
  DCB: String
6
7
 
@@ -3,9 +3,14 @@ module DPay
3
3
  BLIK_CODE: Regexp
4
4
  PARTNER_PLATFORM: Regexp
5
5
  HTTP_URL: Regexp
6
+ CONTROL_CHARACTERS: Regexp
7
+ RECURRING_ALIAS_MAX: Integer
8
+ REFERENCE_MAX: Integer
6
9
  TOGGLES: Hash[String, Symbol]
10
+ RECURRING_CONFLICTS: Array[String]
7
11
 
8
12
  @optional: Hash[String, untyped]
13
+ @recurring_registration: RecurringRegistration?
9
14
 
10
15
  attr_reader amount: Money
11
16
 
@@ -30,7 +35,11 @@ module DPay
30
35
  def with_blik_code: (String blik_code, String user_agent, String user_ip) -> self
31
36
  def with_blik_alias: (String alias_value, String user_agent, String user_ip) -> self
32
37
  def with_register_blik_alias: (BlikAliasRegistration registration) -> self
33
- def with_register_blik_recurring_alias: (BlikRecurringRegistration registration) -> self
38
+ def with_recurring_registration: (RecurringRegistration registration) -> self
39
+ def with_recurring_alias: (String alias_value) -> self
40
+ def with_client_context: (String user_agent, String user_ip) -> self
41
+ def with_webhook: (WebhookTarget webhook) -> self
42
+ def with_reference: (String reference) -> self
34
43
  def with_alias_ipn_url: (String url) -> self
35
44
  def with_no_delay: (bool no_delay) -> self
36
45
  def with_card_recurring: (CardRecurringRegistration registration) -> self
@@ -52,5 +61,8 @@ module DPay
52
61
  def append: (Hash[String, untyped] body, String key) -> void
53
62
  def append_payer: (Hash[String, untyped] body) -> void
54
63
  def append_toggles: (Hash[String, untyped] body) -> void
64
+ def ip_address?: (untyped value) -> bool
65
+ def assert_recurring_combination: () -> void
66
+ def assert_recurring_requirements: (bool charge) -> void
55
67
  end
56
68
  end
@@ -16,5 +16,11 @@ module DPay
16
16
  def paid?: () -> bool
17
17
  def internal_processing?: () -> bool
18
18
  def card_recurring_alias: () -> String?
19
+ def recurring_alias: () -> String?
20
+ def recurring_methods: () -> Array[String]
21
+
22
+ private
23
+
24
+ def recurring_registration: () -> Hash[String, untyped]
19
25
  end
20
26
  end
@@ -4,8 +4,8 @@ module DPay
4
4
 
5
5
  attr_reader success: String
6
6
  attr_reader fail: String
7
- attr_reader ipn: String
7
+ attr_reader ipn: String?
8
8
 
9
- def initialize: (String success, String fail, String ipn) -> void
9
+ def initialize: (String success, String fail, ?String? ipn) -> void
10
10
  end
11
11
  end
@@ -4,8 +4,6 @@ module DPay
4
4
  DCB_GATEWAY: String
5
5
  CARD_AUTH: String
6
6
  MB_WAY_DIRECT: String
7
- BIZUM_DIRECT: String
8
- BLIK_RECURRING: String
9
7
  CARD_RECURRING: String
10
8
 
11
9
  ALL: Array[String]
@@ -0,0 +1,45 @@
1
+ module DPay
2
+ class RecurringRegistration
3
+ MODEL_A: String
4
+ MODEL_M: String
5
+ MODEL_O: String
6
+ MODELS: Array[String]
7
+ METHOD_BLIK: String
8
+ METHODS: Array[String]
9
+ FREQUENCY: Regexp
10
+ DATE: Regexp
11
+ HTTP_URL: Regexp
12
+ TERMS_URL_MAX: Integer
13
+ ALIAS_MAX: Integer
14
+ MODEL_O_FORBIDDEN: Array[String]
15
+ MODEL_A_REQUIRED: Array[String]
16
+ OPTIONAL_ORDER: Array[String]
17
+
18
+ @label: String
19
+ @terms_url: String
20
+ @optional: Hash[String, untyped]
21
+
22
+ attr_reader model: String
23
+
24
+ def self.create: (String label, String model, String terms_url) -> RecurringRegistration
25
+
26
+ def initialize: (String label, String model, String terms_url) -> void
27
+ def with_alias: (String alias_value) -> self
28
+ def with_terms_version: (String terms_version) -> self
29
+ def with_methods: (Array[String] names) -> self
30
+ def with_frequency: (String frequency) -> self
31
+ def with_limit_amt: (Integer limit_amt) -> self
32
+ def with_tot_limit_amt: (Integer tot_limit_amt) -> self
33
+ def with_limit_amt_fixed: (bool fixed) -> self
34
+ def with_expiration_date: (String expiration_date) -> self
35
+ def with_init_date: (String init_date) -> self
36
+ def to_h: () -> Hash[String, untyped]
37
+
38
+ private
39
+
40
+ def set: (String key, untyped value) -> self
41
+ def assert_model_rules: () -> void
42
+ def assert_positive: (untyped value, String field) -> Integer
43
+ def assert_date: (untyped date) -> String
44
+ end
45
+ end
@@ -1,17 +1,27 @@
1
1
  module DPay
2
- class BlikRecurringRegistrationInfo
2
+ class RecurringRegistrationInfo
3
+ DIGITS: Regexp
4
+
5
+ attr_reader transaction_id: String?
6
+ attr_reader label: String?
3
7
  attr_reader model: String?
4
8
  attr_reader frequency: String?
5
9
  attr_reader limit_amt: Integer?
6
10
  attr_reader tot_limit_amt: Integer?
7
11
  attr_reader limit_amt_fixed: bool?
8
12
  attr_reader init_date: String?
9
- attr_reader label: String?
13
+ attr_reader terms_url: String?
14
+ attr_reader terms_version: String?
10
15
  attr_reader registered_at: String?
11
16
  attr_reader raw: Hash[String, untyped]
12
17
 
13
- def self.from_api: (Hash[String, untyped] data) -> BlikRecurringRegistrationInfo
18
+ def self.from_api: (Hash[String, untyped] data) -> RecurringRegistrationInfo
14
19
 
15
20
  def initialize: (Hash[String, untyped] data) -> void
21
+
22
+ private
23
+
24
+ def string: (untyped value) -> String?
25
+ def integer: (untyped value) -> Integer?
16
26
  end
17
27
  end
@@ -0,0 +1,24 @@
1
+ module DPay
2
+ class RecurringRetryResult
3
+ STATUS_PENDING: String
4
+ STATUS_FAILED: String
5
+ STATUS_SUCCESS: String
6
+
7
+ attr_reader transaction_id: String
8
+ attr_reader status: String?
9
+ attr_reader count: Integer?
10
+ attr_reader error_code: String?
11
+ attr_reader error_description: String?
12
+ attr_reader raw: Hash[String, untyped]
13
+
14
+ def self.from_api: (Hash[String, untyped] data) -> RecurringRetryResult
15
+
16
+ def initialize: (Hash[String, untyped] data) -> void
17
+ def pending?: () -> bool
18
+ def failed?: () -> bool
19
+
20
+ private
21
+
22
+ def string: (untyped value) -> String?
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module DPay
2
+ class RecurringService
3
+ CANCEL: String
4
+
5
+ def initialize: (Internal::ApiRequestor api) -> void
6
+ def status: (String alias_value) -> RecurringStatus
7
+ def retry: (String transaction_id) -> RecurringRetryResult
8
+ def cancel: (String alias_value, ?String? reason) -> String
9
+
10
+ private
11
+
12
+ def post: (String path, Hash[String, untyped] body) -> Hash[String, untyped]
13
+ def payload: (Hash[String, untyped] data) -> Hash[String, untyped]
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module DPay
2
+ class RecurringStatus
3
+ ACTIVE: String
4
+ INACTIVE: String
5
+ UNREGISTERED: String
6
+ EXPIRED: String
7
+ DECLINED: String
8
+
9
+ ALL: Array[String]
10
+
11
+ attr_reader alias: String
12
+ attr_reader payment_method: String?
13
+ attr_reader status: String?
14
+ attr_reader expiration_date: String?
15
+ attr_reader registration: RecurringRegistrationInfo?
16
+ attr_reader raw: Hash[String, untyped]
17
+
18
+ def self.from_api: (Hash[String, untyped] data) -> RecurringStatus
19
+
20
+ def initialize: (Hash[String, untyped] data) -> void
21
+ def active?: () -> bool
22
+
23
+ private
24
+
25
+ def string: (untyped value) -> String?
26
+ end
27
+ end
@@ -3,12 +3,12 @@ module DPay
3
3
  AVAILABILITY_STATUSES: Array[Integer]
4
4
 
5
5
  def initialize: (Internal::ApiRequestor api) -> void
6
- def create: (String transaction_id, ?Money? amount, ?String? reason) -> Refund
6
+ def create: (String transaction_id, ?Money? amount, ?String? reason, ?WebhookTarget? webhook) -> Refund
7
7
  def check_availability: (String transaction_id, ?Money? amount, ?String? reason) -> RefundAvailability
8
8
 
9
9
  private
10
10
 
11
11
  def availability_outcome?: (Integer status, Hash[String, untyped] data) -> bool
12
- def signed_body: (String transaction_id, Money? amount, String? reason) -> Hash[String, untyped]
12
+ def signed_body: (String transaction_id, Money? amount, String? reason, ?WebhookTarget? webhook) -> Hash[String, untyped]
13
13
  end
14
14
  end
@@ -0,0 +1,14 @@
1
+ module DPay
2
+ class EventPage
3
+ attr_reader data: Array[WebhookEvent]
4
+ attr_reader next_starting_after: String?
5
+ attr_reader raw: Hash[String, untyped]
6
+
7
+ @has_more: bool
8
+
9
+ def self.from_api: (Hash[String, untyped] response) -> EventPage
10
+
11
+ def initialize: (Hash[String, untyped] response) -> void
12
+ def has_more?: () -> bool
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module DPay
2
+ class EventService
3
+ PATH: String
4
+ STARTING_AFTER: Regexp
5
+ DATE_FIELDS: Array[String]
6
+ LIMIT: Range[Integer]
7
+
8
+ type params = Hash[String | Symbol, untyped]
9
+
10
+ def initialize: (Internal::ApiRequestor api) -> void
11
+ def list: (?params params, ?Integer? timestamp) -> EventPage
12
+ def iterate: (?params params) { (WebhookEvent event) -> void } -> nil
13
+ | (?params params) -> Enumerator[WebhookEvent, nil]
14
+
15
+ private
16
+
17
+ def append_types: (Hash[String, untyped] body, untyped types) -> void
18
+ def append_starting_after: (Hash[String, untyped] body, untyped starting_after) -> void
19
+ def append_limit: (Hash[String, untyped] body, untyped limit) -> void
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module DPay
2
+ class WebhookEvent
3
+ attr_reader id: String
4
+ attr_reader type: String
5
+ attr_reader api_version: String?
6
+ attr_reader created: String?
7
+ attr_reader service: String?
8
+ attr_reader merchant_ref: String?
9
+ attr_reader object: Hash[String, untyped]
10
+ attr_reader object_type: String?
11
+ attr_reader raw: Hash[String, untyped]
12
+
13
+ @livemode: bool
14
+
15
+ def self.from_api: (Hash[String, untyped] data) -> WebhookEvent
16
+
17
+ def initialize: (Hash[String, untyped] data) -> void
18
+ def livemode?: () -> bool
19
+
20
+ private
21
+
22
+ def string: (untyped value) -> String?
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module DPay
2
+ module WebhookEventType
3
+ PAYMENT_SUCCEEDED: String
4
+ PAYMENT_FAILED: String
5
+ PAYMENT_CAPTURED: String
6
+ REFUND_SUCCEEDED: String
7
+ REFUND_FAILED: String
8
+ RECURRING_PAYMENT_ACTIVATED: String
9
+ RECURRING_PAYMENT_CANCELED: String
10
+ RECURRING_PAYMENT_EXPIRED: String
11
+ RECURRING_PAYMENT_DECLINED: String
12
+ PAYOUT_PAID: String
13
+ PAYOUT_FAILED: String
14
+ WEBHOOK_TEST: String
15
+
16
+ PAYMENT_REGISTRATION: Array[String]
17
+ MERCHANT: Array[String]
18
+ REFUND: Array[String]
19
+ CAPTURE: Array[String]
20
+
21
+ def self.assert_allowed: (Array[untyped] events, Array[String] allowed, String context) -> nil
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module DPay
2
+ class WebhookTarget
3
+ HTTPS_URL: Regexp
4
+ URL_MAX: Integer
5
+
6
+ attr_reader url: String
7
+ attr_reader events: Array[String]
8
+
9
+ def self.create: (String url, ?Array[String] events) -> WebhookTarget
10
+
11
+ def initialize: (String url, ?Array[String] events) -> void
12
+ def assert_events_allowed: (Array[String] allowed, String context) -> nil
13
+ def to_h: () -> Hash[String, untyped]
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module DPay
2
+ module WebhookVerifier
3
+ DEFAULT_TOLERANCE: Integer
4
+ SECRET_PREFIX: String
5
+ SIGNATURE_VERSION: String
6
+ ID_HEADER: String
7
+ TIMESTAMP_HEADER: String
8
+ SIGNATURE_HEADER: String
9
+ RACK_PREFIX: String
10
+ TIMESTAMP: Regexp
11
+ BASE64: Regexp
12
+ BASE64_WHITESPACE: String
13
+ INVALID_SECRET: String
14
+
15
+ # headers: a Hash (or anything with #each yielding name and value), names as String or Symbol in any letter
16
+ # case or in the Rack format (HTTP_WEBHOOK_ID), values as String or Array[String].
17
+ def self?.construct_event: (
18
+ untyped raw_body,
19
+ untyped headers,
20
+ String | Array[String] secrets,
21
+ ?Integer tolerance,
22
+ ?Integer? now
23
+ ) -> WebhookEvent
24
+ def self?.verify: (
25
+ untyped raw_body,
26
+ untyped headers,
27
+ String | Array[String] secrets,
28
+ ?Integer tolerance,
29
+ ?Integer? now
30
+ ) -> nil
31
+ def self?.header: (untyped headers, String name) -> String?
32
+ def self?.header_name: (untyped key) -> String
33
+ def self?.signature_matches?: (String header_value, Array[String] expected) -> bool
34
+ def self?.secure_compare: (String expected, String actual) -> bool
35
+ def self?.key: (untyped secret) -> String
36
+ end
37
+ end