acquiring-sdk-ruby 0.1.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 (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +140 -0
  5. data/Rakefile +34 -0
  6. data/acquiring-sdk-ruby.gemspec +30 -0
  7. data/lib/worldline/acquiring/sdk/api_resource.rb +53 -0
  8. data/lib/worldline/acquiring/sdk/authentication/authenticator.rb +21 -0
  9. data/lib/worldline/acquiring/sdk/authentication/authorization_type.rb +17 -0
  10. data/lib/worldline/acquiring/sdk/authentication/oauth2_authenticator.rb +142 -0
  11. data/lib/worldline/acquiring/sdk/authentication/oauth2_exception.rb +15 -0
  12. data/lib/worldline/acquiring/sdk/authentication.rb +1 -0
  13. data/lib/worldline/acquiring/sdk/call_context.rb +9 -0
  14. data/lib/worldline/acquiring/sdk/client.rb +69 -0
  15. data/lib/worldline/acquiring/sdk/communication/communication_exception.rb +21 -0
  16. data/lib/worldline/acquiring/sdk/communication/connection.rb +50 -0
  17. data/lib/worldline/acquiring/sdk/communication/default_connection.rb +429 -0
  18. data/lib/worldline/acquiring/sdk/communication/metadata_provider.rb +162 -0
  19. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_object.rb +54 -0
  20. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_request.rb +15 -0
  21. data/lib/worldline/acquiring/sdk/communication/not_found_exception.rb +21 -0
  22. data/lib/worldline/acquiring/sdk/communication/param_request.rb +16 -0
  23. data/lib/worldline/acquiring/sdk/communication/pooled_connection.rb +28 -0
  24. data/lib/worldline/acquiring/sdk/communication/request_header.rb +64 -0
  25. data/lib/worldline/acquiring/sdk/communication/request_param.rb +30 -0
  26. data/lib/worldline/acquiring/sdk/communication/response_exception.rb +58 -0
  27. data/lib/worldline/acquiring/sdk/communication/response_header.rb +80 -0
  28. data/lib/worldline/acquiring/sdk/communication.rb +1 -0
  29. data/lib/worldline/acquiring/sdk/communicator.rb +506 -0
  30. data/lib/worldline/acquiring/sdk/communicator_configuration.rb +197 -0
  31. data/lib/worldline/acquiring/sdk/domain/data_object.rb +34 -0
  32. data/lib/worldline/acquiring/sdk/domain/shopping_cart_extension.rb +62 -0
  33. data/lib/worldline/acquiring/sdk/domain/uploadable_file.rb +35 -0
  34. data/lib/worldline/acquiring/sdk/domain.rb +1 -0
  35. data/lib/worldline/acquiring/sdk/factory.rb +183 -0
  36. data/lib/worldline/acquiring/sdk/json/default_marshaller.rb +36 -0
  37. data/lib/worldline/acquiring/sdk/json/marshaller.rb +29 -0
  38. data/lib/worldline/acquiring/sdk/json/marshaller_syntax_exception.rb +11 -0
  39. data/lib/worldline/acquiring/sdk/json.rb +1 -0
  40. data/lib/worldline/acquiring/sdk/logging/communicator_logger.rb +26 -0
  41. data/lib/worldline/acquiring/sdk/logging/log_message_builder.rb +91 -0
  42. data/lib/worldline/acquiring/sdk/logging/logging_capable.rb +19 -0
  43. data/lib/worldline/acquiring/sdk/logging/obfuscation/body_obfuscator.rb +101 -0
  44. data/lib/worldline/acquiring/sdk/logging/obfuscation/header_obfuscator.rb +54 -0
  45. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_capable.rb +23 -0
  46. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_rule.rb +49 -0
  47. data/lib/worldline/acquiring/sdk/logging/obfuscation.rb +1 -0
  48. data/lib/worldline/acquiring/sdk/logging/request_log_message_builder.rb +52 -0
  49. data/lib/worldline/acquiring/sdk/logging/response_log_message_builder.rb +43 -0
  50. data/lib/worldline/acquiring/sdk/logging/ruby_communicator_logger.rb +63 -0
  51. data/lib/worldline/acquiring/sdk/logging/stdout_communicator_logger.rb +33 -0
  52. data/lib/worldline/acquiring/sdk/logging.rb +1 -0
  53. data/lib/worldline/acquiring/sdk/proxy_configuration.rb +76 -0
  54. data/lib/worldline/acquiring/sdk/v1/acquirer/acquirer_client.rb +35 -0
  55. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications/account_verifications_client.rb +60 -0
  56. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications.rb +4 -0
  57. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion/dynamic_currency_conversion_client.rb +60 -0
  58. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion.rb +4 -0
  59. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/merchant_client.rb +66 -0
  60. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/get_payment_status_params.rb +34 -0
  61. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/payments_client.rb +224 -0
  62. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments.rb +4 -0
  63. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/get_refund_params.rb +34 -0
  64. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/refunds_client.rb +157 -0
  65. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds.rb +4 -0
  66. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals/technical_reversals_client.rb +64 -0
  67. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals.rb +4 -0
  68. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant.rb +4 -0
  69. data/lib/worldline/acquiring/sdk/v1/acquirer.rb +4 -0
  70. data/lib/worldline/acquiring/sdk/v1/api_exception.rb +63 -0
  71. data/lib/worldline/acquiring/sdk/v1/authorization_exception.rb +23 -0
  72. data/lib/worldline/acquiring/sdk/v1/domain/address_verification_data.rb +41 -0
  73. data/lib/worldline/acquiring/sdk/v1/domain/amount_data.rb +48 -0
  74. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_request.rb +70 -0
  75. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_response.rb +87 -0
  76. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response.rb +71 -0
  77. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response_for_refund.rb +71 -0
  78. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request.rb +75 -0
  79. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request_for_refund.rb +43 -0
  80. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_request.rb +61 -0
  81. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_response.rb +43 -0
  82. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_error_response.rb +62 -0
  83. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_refund_request.rb +77 -0
  84. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_request.rb +95 -0
  85. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_resource.rb +103 -0
  86. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_response.rb +126 -0
  87. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_reversal_request.rb +61 -0
  88. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_summary_for_response.rb +66 -0
  89. data/lib/worldline/acquiring/sdk/v1/domain/api_references_for_responses.rb +48 -0
  90. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_request.rb +88 -0
  91. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_resource.rb +110 -0
  92. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_response.rb +133 -0
  93. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_summary_for_response.rb +66 -0
  94. data/lib/worldline/acquiring/sdk/v1/domain/api_reversal_response.rb +36 -0
  95. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_request.rb +50 -0
  96. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_response.rb +62 -0
  97. data/lib/worldline/acquiring/sdk/v1/domain/card_data_for_dcc.rb +48 -0
  98. data/lib/worldline/acquiring/sdk/v1/domain/card_on_file_data.rb +52 -0
  99. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data.rb +114 -0
  100. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_refund.rb +82 -0
  101. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_resource.rb +43 -0
  102. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_response.rb +52 -0
  103. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_verification.rb +91 -0
  104. data/lib/worldline/acquiring/sdk/v1/domain/dcc_data.rb +55 -0
  105. data/lib/worldline/acquiring/sdk/v1/domain/dcc_proposal.rb +60 -0
  106. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data.rb +52 -0
  107. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_account_verification.rb +45 -0
  108. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_response.rb +41 -0
  109. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_request.rb +75 -0
  110. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_response.rb +57 -0
  111. data/lib/worldline/acquiring/sdk/v1/domain/initial_card_on_file_data.rb +41 -0
  112. data/lib/worldline/acquiring/sdk/v1/domain/merchant_data.rb +76 -0
  113. data/lib/worldline/acquiring/sdk/v1/domain/network_token_data.rb +41 -0
  114. data/lib/worldline/acquiring/sdk/v1/domain/payment_references.rb +48 -0
  115. data/lib/worldline/acquiring/sdk/v1/domain/plain_card_data.rb +48 -0
  116. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data.rb +34 -0
  117. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data_for_dcc.rb +41 -0
  118. data/lib/worldline/acquiring/sdk/v1/domain/rate_data.rb +64 -0
  119. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation.rb +94 -0
  120. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation_for_refund.rb +87 -0
  121. data/lib/worldline/acquiring/sdk/v1/domain/subsequent_card_on_file_data.rb +48 -0
  122. data/lib/worldline/acquiring/sdk/v1/domain/three_d_secure.rb +62 -0
  123. data/lib/worldline/acquiring/sdk/v1/domain/transaction_data_for_dcc.rb +52 -0
  124. data/lib/worldline/acquiring/sdk/v1/domain.rb +4 -0
  125. data/lib/worldline/acquiring/sdk/v1/exception_factory.rb +48 -0
  126. data/lib/worldline/acquiring/sdk/v1/ping/ping_client.rb +52 -0
  127. data/lib/worldline/acquiring/sdk/v1/ping.rb +4 -0
  128. data/lib/worldline/acquiring/sdk/v1/platform_exception.rb +23 -0
  129. data/lib/worldline/acquiring/sdk/v1/reference_exception.rb +23 -0
  130. data/lib/worldline/acquiring/sdk/v1/v1_client.rb +43 -0
  131. data/lib/worldline/acquiring/sdk/v1/validation_exception.rb +23 -0
  132. data/lib/worldline/acquiring/sdk/v1.rb +4 -0
  133. data/lib/worldline/acquiring/sdk.rb +1 -0
  134. data/spec/comparable_extension.rb +29 -0
  135. data/spec/fixtures/resources/authentication/oauth2AccessToken.expired.json +4 -0
  136. data/spec/fixtures/resources/authentication/oauth2AccessToken.invalidClient.json +4 -0
  137. data/spec/fixtures/resources/authentication/oauth2AccessToken.json +4 -0
  138. data/spec/fixtures/resources/communication/getWithQueryParams.json +3 -0
  139. data/spec/fixtures/resources/communication/getWithoutQueryParams.json +3 -0
  140. data/spec/fixtures/resources/communication/notFound.html +1 -0
  141. data/spec/fixtures/resources/communication/postWithBadRequestResponse.json +11 -0
  142. data/spec/fixtures/resources/communication/postWithCreatedResponse.json +6 -0
  143. data/spec/fixtures/resources/communication/unknownServerError.json +10 -0
  144. data/spec/fixtures/resources/logging/bodyNoObfuscation.json +7 -0
  145. data/spec/fixtures/resources/logging/bodyWithBinObfuscated.json +3 -0
  146. data/spec/fixtures/resources/logging/bodyWithBinOriginal.json +3 -0
  147. data/spec/fixtures/resources/logging/bodyWithCardCustomObfuscated.json +13 -0
  148. data/spec/fixtures/resources/logging/bodyWithCardObfuscated.json +13 -0
  149. data/spec/fixtures/resources/logging/bodyWithCardOriginal.json +13 -0
  150. data/spec/fixtures/resources/logging/bodyWithObjectObfuscated.json +5 -0
  151. data/spec/fixtures/resources/logging/bodyWithObjectOriginal.json +5 -0
  152. data/spec/fixtures/resources/properties.oauth2.yml +8 -0
  153. data/spec/fixtures/resources/properties.proxy.yml +14 -0
  154. data/spec/integration/connection_pooling_spec.rb +74 -0
  155. data/spec/integration/multipart_form_data_spec.rb +216 -0
  156. data/spec/integration/process_payment_spec.rb +43 -0
  157. data/spec/integration/request_dcc_rate_spec.rb +24 -0
  158. data/spec/integration/sdk_proxy_spec.rb +70 -0
  159. data/spec/integration_setup.rb +111 -0
  160. data/spec/lib/authentication/oauth2_authenticator_spec.rb +68 -0
  161. data/spec/lib/client_spec.rb +47 -0
  162. data/spec/lib/communication/default_connection_logger_spec.rb +484 -0
  163. data/spec/lib/communication/default_connection_spec.rb +352 -0
  164. data/spec/lib/communication/metadata_provider_spec.rb +93 -0
  165. data/spec/lib/communicator_configuration_spec.rb +181 -0
  166. data/spec/lib/communicator_spec.rb +34 -0
  167. data/spec/lib/factory_spec.rb +38 -0
  168. data/spec/lib/json/default_marshaller_spec.rb +39 -0
  169. data/spec/lib/logging/obfuscation/body_obfuscator_spec.rb +86 -0
  170. data/spec/lib/logging/obfuscation/header_obfuscator_spec.rb +100 -0
  171. data/spec/lib/logging/ruby_communicator_logger_spec.rb +92 -0
  172. data/spec/lib/logging/stdout_communicator_logger_spec.rb +64 -0
  173. data/spec/spec_helper.rb +32 -0
  174. metadata +375 -0
@@ -0,0 +1,91 @@
1
+ require 'worldline/acquiring/sdk/logging/obfuscation/body_obfuscator'
2
+ require 'worldline/acquiring/sdk/logging/obfuscation/header_obfuscator'
3
+
4
+ module Worldline
5
+ module Acquiring
6
+ module SDK
7
+ module Logging
8
+ # Abstract class used to construct a message describing a request or response.
9
+ #
10
+ # @attr_reader [String] request_id An identifier assigned to the request and response
11
+ # @attr_reader [String] headers Request or response headers in string form
12
+ # @attr_reader [String] body Request or response body as a string
13
+ # @attr_reader [String] content_type Content type of the body, generally 'application/json' or 'text/html'
14
+ # @attr_reader [Worldline::Acquiring::SDK::Logging::Obfuscation::BodyObfuscator] body_obfuscator
15
+ # @attr_reader [Worldline::Acquiring::SDK::Logging::Obfuscation::HeaderObfuscator] header_obfuscator
16
+ class LogMessageBuilder
17
+
18
+ attr_reader :request_id
19
+ attr_reader :headers
20
+ attr_reader :body
21
+ attr_reader :content_type
22
+ attr_reader :body_obfuscator
23
+ attr_reader :header_obfuscator
24
+
25
+ # Create a new LogMessageBuilder
26
+ def initialize(request_id,
27
+ body_obfuscator = Obfuscation::BodyObfuscator.default_obfuscator,
28
+ header_obfuscator = Obfuscation::HeaderObfuscator.default_obfuscator)
29
+ raise ArgumentError if request_id.nil? or request_id.empty?
30
+ raise ArgumentError if body_obfuscator.nil?
31
+ raise ArgumentError if header_obfuscator.nil?
32
+ @request_id = request_id
33
+ @headers = ''
34
+ @body_obfuscator = body_obfuscator
35
+ @header_obfuscator = header_obfuscator
36
+ end
37
+
38
+ # Adds a single header to the #headers string
39
+ def add_headers(name, value)
40
+ @headers += ', ' if @headers.length > 0
41
+ @headers += name + '="'
42
+ @headers += @header_obfuscator.obfuscate_header(name, value) unless value.nil?
43
+ @headers += '"'
44
+ end
45
+
46
+ # Sets the body of this message to the parameter body.
47
+
48
+ # @param body [String] the message body
49
+ # @param content_type [String] the content type of the body
50
+ def set_body(body, content_type)
51
+ if is_binary(content_type)
52
+ @body = "<binary content>"
53
+ else
54
+ @body = @body_obfuscator.obfuscate_body(body)
55
+ end
56
+ @content_type = content_type
57
+ end
58
+
59
+ # Constructs and returns the log message as a string.
60
+ # @return [String]
61
+ def get_message
62
+ raise NotImplementedError.new("#{self.class.name}#get_message() is not implemented.")
63
+ end
64
+
65
+ def to_s
66
+ if self.class == LogMessageBuilder
67
+ super.to_s
68
+ else
69
+ get_message
70
+ end
71
+ end
72
+
73
+ # Returns an empty string if the parameter is nil, and returns the parameter itself otherwise
74
+ protected def empty_if_null(value)
75
+ value.nil? ? '' : value
76
+ end
77
+
78
+ # Returns whether or not the content type is binary
79
+ def is_binary(content_type)
80
+ if content_type.nil?
81
+ false
82
+ else
83
+ content_type = content_type.downcase
84
+ !(content_type.start_with?("text/") || content_type.include?("json") || content_type.include?("xml"))
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,19 @@
1
+ module Worldline
2
+ module Acquiring
3
+ module SDK
4
+ module Logging
5
+ # Abstract mixin module that allows loggers to be registered to an object.
6
+ module LoggingCapable
7
+
8
+ def enable_logging(communicator_logger)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def disable_logging
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,101 @@
1
+ require 'worldline/acquiring/sdk/logging/obfuscation/obfuscation_rule'
2
+
3
+ module Worldline
4
+ module Acquiring
5
+ module SDK
6
+ module Logging
7
+ module Obfuscation
8
+ # A class that can be used to obfuscate properties in JSON bodies.
9
+ class BodyObfuscator
10
+
11
+ # Creates a new body obfuscator.
12
+ # This will contain some pre-defined obfuscation rules, as well as any provided custom rules
13
+ #
14
+ # @param additional_rules [Hash] An optional hash where the keys are property names and the values are
15
+ # functions that obfuscate a single value
16
+ def initialize(additional_rules = nil)
17
+ @obfuscation_rules = {
18
+ "address" => Obfuscation.obfuscate_all,
19
+ "authenticationValue" => Obfuscation.obfuscate_all_but_first(4),
20
+ "bin" => Obfuscation.obfuscate_all_but_first(6),
21
+ "cardholderAddress" => Obfuscation.obfuscate_all,
22
+ "cardholderPostalCode" => Obfuscation.obfuscate_all,
23
+ "cardNumber" => Obfuscation.obfuscate_all_but_last(4),
24
+ "cardSecurityCode" => Obfuscation.obfuscate_all,
25
+ "city" => Obfuscation.obfuscate_all,
26
+ "cryptogram" => Obfuscation.obfuscate_all_but_first(4),
27
+ "expiryDate" => Obfuscation.obfuscate_all_but_last(4),
28
+ "name" => Obfuscation.obfuscate_all,
29
+ "paymentAccountReference" => Obfuscation.obfuscate_all_but_first(6),
30
+ "postalCode" => Obfuscation.obfuscate_all,
31
+ "stateCode" => Obfuscation.obfuscate_all,
32
+ }
33
+ if additional_rules
34
+ additional_rules.each do |name, rule|
35
+ @obfuscation_rules[name] = rule
36
+ end
37
+ end
38
+
39
+ @property_pattern = build_property_pattern(@obfuscation_rules.keys)
40
+ end
41
+
42
+ private
43
+
44
+ def build_property_pattern(pn)
45
+ return /$^/ if pn.empty? # no possible match
46
+ # Regex to create:
47
+ # (["'])(X|Y|Z)\1\s*:\s*(?:(["'])(.*?)(?<!\\)\3|([^"'\s\[\{]\S*))
48
+ # Groups:
49
+ # 1: opening " or ' for the property name
50
+ # 2: property name
51
+ # 3: opening " or ' for the value
52
+ # 4: quoted value
53
+ # 5: non-quoted-value
54
+ # The negative lookbehind is to allow escaped quotes to be part of
55
+ # the value. What this does not allow currently is having values end
56
+ # with a \ (which would be escaped to \\).
57
+ regex = pn.inject("([\"'])(") { |r, p| "#{r}#{Regexp.quote(p)}|" }.chop <<
58
+ ")\\1\\s*:\\s*(?:([\"'])(.*?)(?<!\\\\)\\3|([^\"'\\s\\[\\{]((?!,)\\S)*))"
59
+ /#{regex}/m # dotall mode
60
+ end
61
+
62
+ def obfuscate_value(property_name, value)
63
+ obfuscation_rule = @obfuscation_rules[property_name]
64
+ return obfuscation_rule.call(value) if obfuscation_rule
65
+ value
66
+ end
67
+
68
+ public
69
+
70
+ # Obfuscates the given body as necessary.
71
+ #
72
+ # @return (String)
73
+ def obfuscate_body(body)
74
+ return nil if body.nil?
75
+ return '' if body.empty?
76
+
77
+ body.gsub(@property_pattern) do
78
+ m = Regexp.last_match
79
+ property_name = m[2]
80
+ value = m[4] || m[5]
81
+ # copy value 'cause it's part of m[0]
82
+ m[0].sub(value, obfuscate_value(property_name, value.dup))
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ DEFAULT_OBFUSCATOR = BodyObfuscator.new
89
+
90
+ public
91
+
92
+ # @return [BodyObfuscator]
93
+ def self.default_obfuscator
94
+ DEFAULT_OBFUSCATOR
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,54 @@
1
+ require 'worldline/acquiring/sdk/logging/obfuscation/obfuscation_rule'
2
+
3
+ module Worldline
4
+ module Acquiring
5
+ module SDK
6
+ module Logging
7
+ module Obfuscation
8
+ # A class that can be used to obfuscate headers.
9
+ class HeaderObfuscator
10
+
11
+ # Creates a new header obfuscator.
12
+ # This will contain some pre-defined obfuscation rules, as well as any provided custom rules
13
+ #
14
+ # @param additional_rules [Hash] An optional hash where the keys are header names and the values are
15
+ # functions that obfuscate a single value
16
+ def initialize(additional_rules = nil)
17
+ @obfuscation_rules = {
18
+ "authorization" => Obfuscation.obfuscate_with_fixed_length(8),
19
+ "www-authenticate" => Obfuscation.obfuscate_with_fixed_length(8),
20
+ "proxy-authenticate" => Obfuscation.obfuscate_with_fixed_length(8),
21
+ "proxy-authorization" => Obfuscation.obfuscate_with_fixed_length(8),
22
+ }
23
+ if additional_rules
24
+ additional_rules.each do |name, rule|
25
+ @obfuscation_rules[name.downcase] = rule
26
+ end
27
+ end
28
+ end
29
+
30
+ # Obfuscates the value for the given header as necessary.
31
+ #
32
+ # @return (String)
33
+ def obfuscate_header(header_name, value)
34
+ obfuscation_rule = @obfuscation_rules[header_name.downcase]
35
+ return obfuscation_rule.call(value) if obfuscation_rule
36
+ value
37
+ end
38
+
39
+ private
40
+
41
+ DEFAULT_OBFUSCATOR = HeaderObfuscator.new
42
+
43
+ public
44
+
45
+ # @return [HeaderObfuscator]
46
+ def self.default_obfuscator
47
+ DEFAULT_OBFUSCATOR
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ module Worldline
2
+ module Acquiring
3
+ module SDK
4
+ module Logging
5
+ module Obfuscation
6
+ # Abstract mixin module that allows specifying body and header obfuscators for an object.
7
+ module ObfuscationCapable
8
+
9
+ # Sets the current body obfuscator to use.
10
+ def set_body_obfuscator(body_obfuscator)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ # Sets the current header obfuscator to use.
15
+ def set_header_obfuscator(header_obfuscator)
16
+ raise NotImplementedError
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ module Worldline
2
+ module Acquiring
3
+ module SDK
4
+ module Logging
5
+ module Obfuscation
6
+
7
+ # Returns an obfuscation rule (callable) that will replace all characters with *
8
+ def self.obfuscate_all
9
+ ->(value) do
10
+ return value if value.nil? or value.empty?
11
+ '*' * (value || '').length
12
+ end
13
+ end
14
+
15
+ # Returns an obfuscation rule (function) that will replace values with a fixed length string containing only *
16
+ def self.obfuscate_with_fixed_length(fixed_length)
17
+ ->(value) { '*' * fixed_length }
18
+ end
19
+
20
+ # Returns an obfuscation rule (function) that will keep a fixed number of characters at the start,
21
+ # then replaces all other characters with *
22
+ def self.obfuscate_all_but_first(count)
23
+ ->(value) do
24
+ return value if value.nil? or value.empty?
25
+ return value if value.length < count
26
+ # range describes the range of characters to replace with asterisks
27
+ range = count...value.length
28
+ value[range] = '*' * range.size
29
+ value
30
+ end
31
+ end
32
+
33
+ # Returns an obfuscation rule that will keep a fixed number of characters at the end,
34
+ # then replaces all other characters with *
35
+ def self.obfuscate_all_but_last(count)
36
+ ->(value) do
37
+ return value if value.nil? or value.empty?
38
+ return value if value.length < count
39
+ # range describes the range of characters to replace with asterisks
40
+ range = 0...(value.length - count)
41
+ value[range] = '*' * range.size
42
+ value
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1 @@
1
+ Dir[File.join(__dir__, 'obfuscation', '*.rb')].each { |f| require f }
@@ -0,0 +1,52 @@
1
+ require 'worldline/acquiring/sdk/logging/obfuscation/body_obfuscator'
2
+ require 'worldline/acquiring/sdk/logging/obfuscation/header_obfuscator'
3
+ require 'worldline/acquiring/sdk/logging/log_message_builder'
4
+
5
+ module Worldline
6
+ module Acquiring
7
+ module SDK
8
+ module Logging
9
+ # Class that converts data about a request into a properly formatted log message.
10
+ # Formats request id, http method, uri, headers and body into a helpful message.
11
+ class RequestLogMessageBuilder < LogMessageBuilder
12
+
13
+ def initialize(request_id, method, uri,
14
+ body_obfuscator = Obfuscation::BodyObfuscator.default_obfuscator,
15
+ header_obfuscator = Obfuscation::HeaderObfuscator.default_obfuscator)
16
+ super(request_id, body_obfuscator, header_obfuscator)
17
+ @method = method
18
+ @uri = uri
19
+ end
20
+
21
+ # Constructs and returns a log message based on the request data. The log message is a string.
22
+ def get_message
23
+ msg_template_without_body = "Outgoing request (requestId='%s'):\n" +
24
+ " method: '%s'\n" +
25
+ " uri: '%s'\n" +
26
+ " headers: '%s'"
27
+ msg_template_with_body = msg_template_without_body + "\n" +
28
+ " content-type: '%s'\n" +
29
+ " body: '%s'"
30
+
31
+ return sprintf(msg_template_without_body, @request_id, empty_if_null(@method),
32
+ format_uri, @headers) if @body.nil?
33
+ sprintf(msg_template_with_body, @request_id, empty_if_null(@method),
34
+ format_uri, @headers, empty_if_null(@content_type), @body)
35
+ end
36
+
37
+ private
38
+
39
+ def format_uri
40
+ '' unless @uri && @uri.path
41
+ if @uri.query.nil?
42
+ @uri.path
43
+ else
44
+ "#{@uri.path}?#{@uri.query}" unless @uri.query.nil?
45
+ end
46
+ # @uri.path + '?' + empty_if_null(@uri.query)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ require 'worldline/acquiring/sdk/logging/obfuscation/body_obfuscator'
2
+ require 'worldline/acquiring/sdk/logging/obfuscation/header_obfuscator'
3
+ require 'worldline/acquiring/sdk/logging/log_message_builder'
4
+
5
+ module Worldline
6
+ module Acquiring
7
+ module SDK
8
+ module Logging
9
+ # Class that converts data about a response into a properly formatted log message.
10
+ # Formats request id, status code, headers, body and time between request and response into a helpful message.
11
+ class ResponseLogMessageBuilder < LogMessageBuilder
12
+
13
+ # @param request_id [String] identifier of the request corresponding to this response.
14
+ # @param status_code [Integer] HTTP status code of the response.
15
+ # @param duration [Float] time elapsed between request and response.
16
+ def initialize(request_id, status_code, duration = -1,
17
+ body_obfuscator = Obfuscation::BodyObfuscator.default_obfuscator,
18
+ header_obfuscator = Obfuscation::HeaderObfuscator.default_obfuscator)
19
+ super(request_id, body_obfuscator, header_obfuscator)
20
+ @status_code = status_code
21
+ @duration = duration
22
+ end
23
+
24
+ # Constructs and returns a log message based on the request data. The log message is a string.
25
+ def get_message
26
+ msg_template = "Incoming response (requestId='%s'" +
27
+ ((@duration < 0) ? "" : ", %.3f ms") +
28
+ "):\n" +
29
+ " status-code: '%s'\n" +
30
+ " headers: '%s'\n" +
31
+ " content-type: '%s'\n" +
32
+ " body: '%s'"
33
+
34
+ return sprintf(msg_template, @request_id, @status_code, @headers,
35
+ empty_if_null(@content_type), empty_if_null(@body)) if @duration < 0
36
+ sprintf(msg_template, @request_id, @duration, @status_code, @headers,
37
+ empty_if_null(@content_type), empty_if_null(@body))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ require 'English'
2
+ require 'worldline/acquiring/sdk/logging/communicator_logger'
3
+
4
+ module Worldline
5
+ module Acquiring
6
+ module SDK
7
+ module Logging
8
+ # Logging class that Logs messages and errors to a logger.
9
+ # Errors can be logged at a separate level compared to regular messages.
10
+ class RubyCommunicatorLogger < CommunicatorLogger
11
+
12
+ # Creates a new RubyCommunicatorLogger instance.
13
+ #
14
+ # @param logger [Logger] the logger to log messages to. Messages to log will be provided using logger#log(message level, message)
15
+ # @param log_level [String] log level to use for non-error messages.
16
+ # @param error_level [String, nil] error logging level to use.
17
+ def initialize(logger, log_level, error_level = nil)
18
+ # implement the interface
19
+ error_level ||= log_level
20
+ raise ArgumentError unless logger
21
+ raise ArgumentError unless log_level
22
+ raise ArgumentError unless error_level
23
+
24
+ @logger = logger
25
+ @log_level = log_level
26
+ @error_level = error_level
27
+ end
28
+
29
+ # Logs a single error or non-error message to the logger.
30
+ def log(msg, thrown = nil)
31
+ # use Ruby Logger
32
+ if thrown
33
+ @logger.log(@error_level) { msg + $RS + thrown.to_s + $RS + thrown.backtrace.join($RS) }
34
+ else
35
+ @logger.log(@log_level, msg)
36
+ end
37
+ end
38
+
39
+ # Opens or creates a new file in write-only mode with _filename_.
40
+ def self.create_logfile(filename)
41
+ logdev = begin
42
+ open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
43
+ rescue Errno::EEXIST
44
+ # file is created by another process
45
+ open_logfile(filename)
46
+ end
47
+ logdev.sync = true
48
+ logdev
49
+ end
50
+
51
+ # Opens or creates a new file in write-only mode with _filename_.
52
+ def self.open_logfile(filename)
53
+ begin
54
+ open(filename, (File::WRONLY | File::APPEND))
55
+ rescue Errno::ENOENT
56
+ create_logfile(filename)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,33 @@
1
+ require 'English'
2
+ require 'singleton'
3
+ require 'worldline/acquiring/sdk/logging/communicator_logger'
4
+
5
+ module Worldline
6
+ module Acquiring
7
+ module SDK
8
+ module Logging
9
+ # Logging class that logs the messages to $stdout.
10
+ class StdoutCommunicatorLogger < CommunicatorLogger
11
+ include Singleton
12
+
13
+ def initialize
14
+ # implement the interface
15
+ end
16
+
17
+ # Logs a single error or non-error message to $stdout.
18
+ def log(msg, thrown = nil)
19
+ $stdout.puts get_date_prefix + msg
20
+ $stdout.puts thrown.to_s if thrown
21
+ $stdout.puts thrown.backtrace.join($RS) if thrown
22
+ end
23
+
24
+ private
25
+
26
+ def get_date_prefix
27
+ Time.now.strftime("%Y-%m-%dT%H:%M:%S ")
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ Dir[File.join(__dir__, 'logging', '*.rb')].each { |f| require f }
@@ -0,0 +1,76 @@
1
+ module Worldline
2
+ module Acquiring
3
+ module SDK
4
+ # Contains the URL, username and password of a proxy.
5
+ #
6
+ # @attr [String] scheme Proxy scheme (http or https)
7
+ # @attr [String] host Proxy hostname
8
+ # @attr [Integer] port Proxy port
9
+ # @attr [String] username Proxy authentication username
10
+ # @attr [String] password Proxy authentication password
11
+ class ProxyConfiguration
12
+
13
+ # Initialize a new ProxyConfiguration from the parameter hash.
14
+ # In order to be complete either host, port and scheme, or an address is required.
15
+ #
16
+ # @param args [Hash] the parameters to initialize the proxy configuration with
17
+ # @option args [String] :host host part of the URL to the proxy.
18
+ # @option args [Integer] :port port the proxy will be accessed through.
19
+ # @option args [String] :scheme HTTP scheme used to communicate with the proxy (http or https).
20
+ # @option args [String] :address full URI to the proxy excluding username and password.
21
+ # If given this uri takes precedence over individual host, port and scheme.
22
+ # @option args [String] :username username used in authentication to the proxy.
23
+ # @option args [String] :password password used to authenticate to the proxy.
24
+ def initialize(args)
25
+ host = args[:host]
26
+ port = args[:port]
27
+ username = args[:username]
28
+ password = args[:password]
29
+ scheme = args[:scheme] || 'http'
30
+
31
+ # Don't switch the order, a given address overrides host, port and username
32
+ address = args[:address]
33
+ host = address.host if address
34
+ port = address.port if address
35
+ scheme = address.scheme if address
36
+
37
+ raise ArgumentError.new('scheme is required') unless scheme and not scheme.strip.empty?
38
+ raise ArgumentError.new('host is required') unless host and not host.strip.empty?
39
+ raise ArgumentError.new('port is required') unless port and port > 0 and port <= 65535
40
+
41
+ @host = host
42
+ @port = port
43
+ @username = username
44
+ @password = password
45
+ @scheme = scheme
46
+ end
47
+
48
+ attr_accessor :scheme
49
+ attr_accessor :host
50
+ attr_accessor :port
51
+
52
+ attr_accessor :username
53
+ attr_accessor :password
54
+
55
+ # @return [String] a URL string representation of the proxy, excluding authentication.
56
+ def proxy_uri
57
+ "#{scheme}://#{host}:#{port}"
58
+ end
59
+
60
+ def to_s
61
+ proxy_uri
62
+ end
63
+
64
+ private
65
+
66
+ def self.get_port(address)
67
+ port = address.port
68
+ return port if port != -1
69
+ return 80 if address.scheme.casecmp('http') == 0
70
+ return 443 if address.scheme.casecmp('https') == 0
71
+ raise ArgumentError.new('unsupported scheme: ' + address.scheme)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,35 @@
1
+ #
2
+ # This file was automatically generated.
3
+ #
4
+ require 'worldline/acquiring/sdk/api_resource'
5
+ require 'worldline/acquiring/sdk/v1/acquirer/merchant/merchant_client'
6
+
7
+ module Worldline
8
+ module Acquiring
9
+ module SDK
10
+ module V1
11
+ module Acquirer
12
+ # Acquirer client. Thread-safe.
13
+ class AcquirerClient < Worldline::Acquiring::SDK::ApiResource
14
+
15
+ # @param parent [Worldline::Acquiring::SDK::ApiResource]
16
+ # @param path_context [Hash, nil]
17
+ def initialize(parent, path_context)
18
+ super(parent: parent, path_context: path_context)
19
+ end
20
+
21
+ # Resource /processing/v1/{acquirerId}/{merchantId}
22
+ #
23
+ # @param merchant_id [String]
24
+ # @return [Worldline::Acquiring::SDK::V1::Acquirer::Merchant::MerchantClient]
25
+ def merchant(merchant_id)
26
+ Worldline::Acquiring::SDK::V1::Acquirer::Merchant::MerchantClient.new(self, {
27
+ 'merchantId'.freeze => merchant_id,
28
+ })
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end