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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/README.md +100 -4
- data/lib/dpay/blik/blik_alias_type.rb +2 -2
- data/lib/dpay/blik/blik_service.rb +0 -9
- data/lib/dpay/card/card_service.rb +21 -5
- data/lib/dpay/client.rb +3 -1
- data/lib/dpay/errors.rb +13 -6
- data/lib/dpay/internal/checksum_calculator.rb +27 -2
- data/lib/dpay/internal/error_mapper.rb +11 -2
- data/lib/dpay/internal/php.rb +6 -0
- data/lib/dpay/ipn/ipn_event.rb +2 -0
- data/lib/dpay/ipn/ipn_type.rb +1 -0
- data/lib/dpay/payment/payment_service.rb +4 -4
- data/lib/dpay/payment/register_payment_request.rb +92 -13
- data/lib/dpay/payment/registered_payment.rb +19 -0
- data/lib/dpay/payment/return_urls.rb +3 -1
- data/lib/dpay/payment/transaction_type.rb +1 -3
- data/lib/dpay/recurring/recurring_registration.rb +162 -0
- data/lib/dpay/recurring/recurring_registration_info.rb +45 -0
- data/lib/dpay/recurring/recurring_retry_result.rb +43 -0
- data/lib/dpay/recurring/recurring_service.rb +59 -0
- data/lib/dpay/recurring/recurring_status.rb +42 -0
- data/lib/dpay/refund/refund_service.rb +10 -4
- data/lib/dpay/version.rb +1 -1
- data/lib/dpay/webhook/event_page.rb +25 -0
- data/lib/dpay/webhook/event_service.rb +76 -0
- data/lib/dpay/webhook/webhook_event.rb +42 -0
- data/lib/dpay/webhook/webhook_event_type.rb +43 -0
- data/lib/dpay/webhook/webhook_target.rb +45 -0
- data/lib/dpay/webhook/webhook_verifier.rb +110 -0
- data/lib/dpay.rb +11 -3
- data/sig/dpay/blik/blik_alias_type.rbs +0 -1
- data/sig/dpay/blik/blik_service.rbs +0 -1
- data/sig/dpay/card/card_service.rbs +1 -1
- data/sig/dpay/client.rbs +2 -0
- data/sig/dpay/errors.rbs +6 -2
- data/sig/dpay/internal/checksum_calculator.rbs +8 -1
- data/sig/dpay/internal/error_mapper.rbs +1 -0
- data/sig/dpay/internal/php.rbs +2 -0
- data/sig/dpay/ipn/ipn_event.rbs +2 -0
- data/sig/dpay/ipn/ipn_type.rbs +1 -0
- data/sig/dpay/payment/register_payment_request.rbs +13 -1
- data/sig/dpay/payment/registered_payment.rbs +6 -0
- data/sig/dpay/payment/return_urls.rbs +2 -2
- data/sig/dpay/payment/transaction_type.rbs +0 -2
- data/sig/dpay/recurring/recurring_registration.rbs +45 -0
- data/sig/dpay/{blik/blik_recurring_registration_info.rbs → recurring/recurring_registration_info.rbs} +13 -3
- data/sig/dpay/recurring/recurring_retry_result.rbs +24 -0
- data/sig/dpay/recurring/recurring_service.rbs +15 -0
- data/sig/dpay/recurring/recurring_status.rbs +27 -0
- data/sig/dpay/refund/refund_service.rbs +2 -2
- data/sig/dpay/webhook/event_page.rbs +14 -0
- data/sig/dpay/webhook/event_service.rbs +21 -0
- data/sig/dpay/webhook/webhook_event.rbs +24 -0
- data/sig/dpay/webhook/webhook_event_type.rbs +23 -0
- data/sig/dpay/webhook/webhook_target.rbs +15 -0
- data/sig/dpay/webhook/webhook_verifier.rbs +37 -0
- metadata +26 -10
- data/lib/dpay/blik/blik_recurring_registration.rb +0 -74
- data/lib/dpay/blik/blik_recurring_registration_info.rb +0 -26
- data/lib/dpay/blik/blik_recurring_status.rb +0 -28
- data/sig/dpay/blik/blik_recurring_registration.rbs +0 -24
- 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"
|
|
@@ -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
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]
|
|
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
|
data/sig/dpay/internal/php.rbs
CHANGED
|
@@ -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
|
data/sig/dpay/ipn/ipn_event.rbs
CHANGED
|
@@ -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
|
|
data/sig/dpay/ipn/ipn_type.rbs
CHANGED
|
@@ -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
|
|
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
|
|
@@ -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
|
|
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
|
|
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) ->
|
|
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
|