direct-sdk-ruby 1.0.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 (238) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +141 -0
  5. data/Rakefile +34 -0
  6. data/direct-sdk-ruby.gemspec +28 -0
  7. data/lib/ingenico/direct/sdk.rb +26 -0
  8. data/lib/ingenico/direct/sdk/api_exception.rb +42 -0
  9. data/lib/ingenico/direct/sdk/api_resource.rb +115 -0
  10. data/lib/ingenico/direct/sdk/authenticator.rb +16 -0
  11. data/lib/ingenico/direct/sdk/authorization_exception.rb +13 -0
  12. data/lib/ingenico/direct/sdk/call_context.rb +26 -0
  13. data/lib/ingenico/direct/sdk/client.rb +85 -0
  14. data/lib/ingenico/direct/sdk/communication_exception.rb +16 -0
  15. data/lib/ingenico/direct/sdk/communicator.rb +301 -0
  16. data/lib/ingenico/direct/sdk/communicator_configuration.rb +59 -0
  17. data/lib/ingenico/direct/sdk/connection.rb +41 -0
  18. data/lib/ingenico/direct/sdk/data_object.rb +32 -0
  19. data/lib/ingenico/direct/sdk/declined_payment_exception.rb +30 -0
  20. data/lib/ingenico/direct/sdk/declined_payout_exception.rb +32 -0
  21. data/lib/ingenico/direct/sdk/declined_refund_exception.rb +32 -0
  22. data/lib/ingenico/direct/sdk/declined_transaction_exception.rb +16 -0
  23. data/lib/ingenico/direct/sdk/defaultimpl.rb +6 -0
  24. data/lib/ingenico/direct/sdk/defaultimpl/authorization_type.rb +24 -0
  25. data/lib/ingenico/direct/sdk/defaultimpl/default_authenticator.rb +108 -0
  26. data/lib/ingenico/direct/sdk/defaultimpl/default_connection.rb +293 -0
  27. data/lib/ingenico/direct/sdk/defaultimpl/default_marshaller.rb +32 -0
  28. data/lib/ingenico/direct/sdk/direct_exception.rb +15 -0
  29. data/lib/ingenico/direct/sdk/domain/account_on_file.rb +50 -0
  30. data/lib/ingenico/direct/sdk/domain/account_on_file_attribute.rb +39 -0
  31. data/lib/ingenico/direct/sdk/domain/account_on_file_display_hints.rb +38 -0
  32. data/lib/ingenico/direct/sdk/domain/additional_order_input.rb +47 -0
  33. data/lib/ingenico/direct/sdk/domain/address.rb +51 -0
  34. data/lib/ingenico/direct/sdk/domain/address_personal.rb +59 -0
  35. data/lib/ingenico/direct/sdk/domain/airline_data.rb +129 -0
  36. data/lib/ingenico/direct/sdk/domain/airline_flight_leg.rb +99 -0
  37. data/lib/ingenico/direct/sdk/domain/airline_passenger.rb +39 -0
  38. data/lib/ingenico/direct/sdk/domain/amount_breakdown.rb +31 -0
  39. data/lib/ingenico/direct/sdk/domain/amount_of_money.rb +31 -0
  40. data/lib/ingenico/direct/sdk/domain/api_error.rb +47 -0
  41. data/lib/ingenico/direct/sdk/domain/browser_data.rb +39 -0
  42. data/lib/ingenico/direct/sdk/domain/cancel_payment_response.rb +31 -0
  43. data/lib/ingenico/direct/sdk/domain/capture.rb +47 -0
  44. data/lib/ingenico/direct/sdk/domain/capture_output.rb +79 -0
  45. data/lib/ingenico/direct/sdk/domain/capture_payment_request.rb +31 -0
  46. data/lib/ingenico/direct/sdk/domain/capture_response.rb +47 -0
  47. data/lib/ingenico/direct/sdk/domain/capture_status_output.rb +27 -0
  48. data/lib/ingenico/direct/sdk/domain/captures_response.rb +34 -0
  49. data/lib/ingenico/direct/sdk/domain/card.rb +39 -0
  50. data/lib/ingenico/direct/sdk/domain/card_essentials.rb +31 -0
  51. data/lib/ingenico/direct/sdk/domain/card_fraud_results.rb +35 -0
  52. data/lib/ingenico/direct/sdk/domain/card_payment_method_specific_input.rb +95 -0
  53. data/lib/ingenico/direct/sdk/domain/card_payment_method_specific_input_base.rb +79 -0
  54. data/lib/ingenico/direct/sdk/domain/card_payment_method_specific_output.rb +67 -0
  55. data/lib/ingenico/direct/sdk/domain/card_payout_method_specific_input.rb +39 -0
  56. data/lib/ingenico/direct/sdk/domain/card_recurrence_details.rb +27 -0
  57. data/lib/ingenico/direct/sdk/domain/card_without_cvv.rb +35 -0
  58. data/lib/ingenico/direct/sdk/domain/company_information.rb +27 -0
  59. data/lib/ingenico/direct/sdk/domain/complete_payment_card_payment_method_specific_input.rb +31 -0
  60. data/lib/ingenico/direct/sdk/domain/complete_payment_request.rb +39 -0
  61. data/lib/ingenico/direct/sdk/domain/complete_payment_response.rb +47 -0
  62. data/lib/ingenico/direct/sdk/domain/contact_details.rb +43 -0
  63. data/lib/ingenico/direct/sdk/domain/create_hosted_checkout_request.rb +63 -0
  64. data/lib/ingenico/direct/sdk/domain/create_hosted_checkout_response.rb +49 -0
  65. data/lib/ingenico/direct/sdk/domain/create_hosted_tokenization_request.rb +39 -0
  66. data/lib/ingenico/direct/sdk/domain/create_hosted_tokenization_response.rb +41 -0
  67. data/lib/ingenico/direct/sdk/domain/create_payment_request.rb +67 -0
  68. data/lib/ingenico/direct/sdk/domain/create_payment_response.rb +47 -0
  69. data/lib/ingenico/direct/sdk/domain/create_payout_request.rb +47 -0
  70. data/lib/ingenico/direct/sdk/domain/create_token_request.rb +35 -0
  71. data/lib/ingenico/direct/sdk/domain/created_payment_output.rb +35 -0
  72. data/lib/ingenico/direct/sdk/domain/created_token_response.rb +51 -0
  73. data/lib/ingenico/direct/sdk/domain/customer.rb +87 -0
  74. data/lib/ingenico/direct/sdk/domain/customer_account.rb +71 -0
  75. data/lib/ingenico/direct/sdk/domain/customer_account_authentication.rb +31 -0
  76. data/lib/ingenico/direct/sdk/domain/customer_device.rb +51 -0
  77. data/lib/ingenico/direct/sdk/domain/customer_payment_activity.rb +35 -0
  78. data/lib/ingenico/direct/sdk/domain/customer_token.rb +47 -0
  79. data/lib/ingenico/direct/sdk/domain/decrypted_payment_data.rb +43 -0
  80. data/lib/ingenico/direct/sdk/domain/directory_entry.rb +35 -0
  81. data/lib/ingenico/direct/sdk/domain/empty_validator.rb +13 -0
  82. data/lib/ingenico/direct/sdk/domain/error_response.rb +38 -0
  83. data/lib/ingenico/direct/sdk/domain/external_cardholder_authentication_data.rb +59 -0
  84. data/lib/ingenico/direct/sdk/domain/external_token_linked.rb +27 -0
  85. data/lib/ingenico/direct/sdk/domain/fixed_list_validator.rb +33 -0
  86. data/lib/ingenico/direct/sdk/domain/fraud_fields.rb +31 -0
  87. data/lib/ingenico/direct/sdk/domain/fraud_results.rb +27 -0
  88. data/lib/ingenico/direct/sdk/domain/g_pay_three_d_secure.rb +47 -0
  89. data/lib/ingenico/direct/sdk/domain/get_hosted_checkout_response.rb +35 -0
  90. data/lib/ingenico/direct/sdk/domain/get_hosted_tokenization_response.rb +35 -0
  91. data/lib/ingenico/direct/sdk/domain/get_payment_product_groups_response.rb +34 -0
  92. data/lib/ingenico/direct/sdk/domain/get_payment_products_response.rb +34 -0
  93. data/lib/ingenico/direct/sdk/domain/gift_card_purchase.rb +35 -0
  94. data/lib/ingenico/direct/sdk/domain/hosted_checkout_specific_input.rb +55 -0
  95. data/lib/ingenico/direct/sdk/domain/hosted_checkout_specific_output.rb +31 -0
  96. data/lib/ingenico/direct/sdk/domain/label_template_element.rb +31 -0
  97. data/lib/ingenico/direct/sdk/domain/length_validator.rb +31 -0
  98. data/lib/ingenico/direct/sdk/domain/line_item.rb +47 -0
  99. data/lib/ingenico/direct/sdk/domain/line_item_invoice_data.rb +27 -0
  100. data/lib/ingenico/direct/sdk/domain/loan_recipient.rb +43 -0
  101. data/lib/ingenico/direct/sdk/domain/merchant_action.rb +35 -0
  102. data/lib/ingenico/direct/sdk/domain/mobile_payment_data.rb +31 -0
  103. data/lib/ingenico/direct/sdk/domain/mobile_payment_method_specific_input.rb +63 -0
  104. data/lib/ingenico/direct/sdk/domain/mobile_payment_method_specific_output.rb +59 -0
  105. data/lib/ingenico/direct/sdk/domain/mobile_payment_product320_specific_input.rb +31 -0
  106. data/lib/ingenico/direct/sdk/domain/order.rb +71 -0
  107. data/lib/ingenico/direct/sdk/domain/order_line_details.rb +55 -0
  108. data/lib/ingenico/direct/sdk/domain/order_references.rb +31 -0
  109. data/lib/ingenico/direct/sdk/domain/order_status_output.rb +50 -0
  110. data/lib/ingenico/direct/sdk/domain/order_type_information.rb +31 -0
  111. data/lib/ingenico/direct/sdk/domain/payment_account_on_file.rb +31 -0
  112. data/lib/ingenico/direct/sdk/domain/payment_creation_output.rb +39 -0
  113. data/lib/ingenico/direct/sdk/domain/payment_error_response.rb +46 -0
  114. data/lib/ingenico/direct/sdk/domain/payment_output.rb +79 -0
  115. data/lib/ingenico/direct/sdk/domain/payment_product.rb +77 -0
  116. data/lib/ingenico/direct/sdk/domain/payment_product5100_specific_input.rb +27 -0
  117. data/lib/ingenico/direct/sdk/domain/payment_product5402_specific_output.rb +27 -0
  118. data/lib/ingenico/direct/sdk/domain/payment_product5500_specific_output.rb +35 -0
  119. data/lib/ingenico/direct/sdk/domain/payment_product771_specific_output.rb +13 -0
  120. data/lib/ingenico/direct/sdk/domain/payment_product840_customer_account.rb +55 -0
  121. data/lib/ingenico/direct/sdk/domain/payment_product840_specific_output.rb +54 -0
  122. data/lib/ingenico/direct/sdk/domain/payment_product_display_hints.rb +35 -0
  123. data/lib/ingenico/direct/sdk/domain/payment_product_field.rb +47 -0
  124. data/lib/ingenico/direct/sdk/domain/payment_product_field_data_restrictions.rb +35 -0
  125. data/lib/ingenico/direct/sdk/domain/payment_product_field_display_element.rb +39 -0
  126. data/lib/ingenico/direct/sdk/domain/payment_product_field_display_hints.rb +71 -0
  127. data/lib/ingenico/direct/sdk/domain/payment_product_field_form_element.rb +38 -0
  128. data/lib/ingenico/direct/sdk/domain/payment_product_field_tooltip.rb +31 -0
  129. data/lib/ingenico/direct/sdk/domain/payment_product_field_validators.rb +91 -0
  130. data/lib/ingenico/direct/sdk/domain/payment_product_filter.rb +43 -0
  131. data/lib/ingenico/direct/sdk/domain/payment_product_filters_hosted_checkout.rb +38 -0
  132. data/lib/ingenico/direct/sdk/domain/payment_product_group.rb +43 -0
  133. data/lib/ingenico/direct/sdk/domain/payment_product_networks_response.rb +33 -0
  134. data/lib/ingenico/direct/sdk/domain/payment_references.rb +27 -0
  135. data/lib/ingenico/direct/sdk/domain/payment_response.rb +55 -0
  136. data/lib/ingenico/direct/sdk/domain/payment_status_output.rb +58 -0
  137. data/lib/ingenico/direct/sdk/domain/payout_error_response.rb +46 -0
  138. data/lib/ingenico/direct/sdk/domain/payout_output.rb +31 -0
  139. data/lib/ingenico/direct/sdk/domain/payout_response.rb +47 -0
  140. data/lib/ingenico/direct/sdk/domain/payout_result.rb +47 -0
  141. data/lib/ingenico/direct/sdk/domain/payout_status_output.rb +35 -0
  142. data/lib/ingenico/direct/sdk/domain/personal_information.rb +39 -0
  143. data/lib/ingenico/direct/sdk/domain/personal_information_token.rb +31 -0
  144. data/lib/ingenico/direct/sdk/domain/personal_name.rb +35 -0
  145. data/lib/ingenico/direct/sdk/domain/personal_name_token.rb +31 -0
  146. data/lib/ingenico/direct/sdk/domain/product_directory.rb +34 -0
  147. data/lib/ingenico/direct/sdk/domain/protection_eligibility.rb +31 -0
  148. data/lib/ingenico/direct/sdk/domain/range_validator.rb +31 -0
  149. data/lib/ingenico/direct/sdk/domain/redirect_data.rb +31 -0
  150. data/lib/ingenico/direct/sdk/domain/redirect_payment_method_specific_input.rb +67 -0
  151. data/lib/ingenico/direct/sdk/domain/redirect_payment_method_specific_output.rb +67 -0
  152. data/lib/ingenico/direct/sdk/domain/redirect_payment_product809_specific_input.rb +27 -0
  153. data/lib/ingenico/direct/sdk/domain/redirect_payment_product840_specific_input.rb +27 -0
  154. data/lib/ingenico/direct/sdk/domain/redirection_data.rb +27 -0
  155. data/lib/ingenico/direct/sdk/domain/refund_card_method_specific_output.rb +31 -0
  156. data/lib/ingenico/direct/sdk/domain/refund_e_wallet_method_specific_output.rb +39 -0
  157. data/lib/ingenico/direct/sdk/domain/refund_error_response.rb +46 -0
  158. data/lib/ingenico/direct/sdk/domain/refund_mobile_method_specific_output.rb +35 -0
  159. data/lib/ingenico/direct/sdk/domain/refund_output.rb +79 -0
  160. data/lib/ingenico/direct/sdk/domain/refund_payment_product840_customer_account.rb +35 -0
  161. data/lib/ingenico/direct/sdk/domain/refund_payment_product840_specific_output.rb +31 -0
  162. data/lib/ingenico/direct/sdk/domain/refund_redirect_method_specific_output.rb +31 -0
  163. data/lib/ingenico/direct/sdk/domain/refund_request.rb +31 -0
  164. data/lib/ingenico/direct/sdk/domain/refund_response.rb +47 -0
  165. data/lib/ingenico/direct/sdk/domain/refunds_response.rb +34 -0
  166. data/lib/ingenico/direct/sdk/domain/regular_expression_validator.rb +27 -0
  167. data/lib/ingenico/direct/sdk/domain/sepa_direct_debit_payment_method_specific_output.rb +43 -0
  168. data/lib/ingenico/direct/sdk/domain/session_request.rb +33 -0
  169. data/lib/ingenico/direct/sdk/domain/session_response.rb +49 -0
  170. data/lib/ingenico/direct/sdk/domain/shipping.rb +51 -0
  171. data/lib/ingenico/direct/sdk/domain/shopping_cart.rb +65 -0
  172. data/lib/ingenico/direct/sdk/domain/shopping_cart_extension.rb +52 -0
  173. data/lib/ingenico/direct/sdk/domain/test_connection.rb +27 -0
  174. data/lib/ingenico/direct/sdk/domain/three_d_secure.rb +63 -0
  175. data/lib/ingenico/direct/sdk/domain/three_d_secure_base.rb +47 -0
  176. data/lib/ingenico/direct/sdk/domain/three_d_secure_data.rb +35 -0
  177. data/lib/ingenico/direct/sdk/domain/three_d_secure_results.rb +31 -0
  178. data/lib/ingenico/direct/sdk/domain/token_card.rb +35 -0
  179. data/lib/ingenico/direct/sdk/domain/token_card_data.rb +31 -0
  180. data/lib/ingenico/direct/sdk/domain/token_card_specific_input.rb +31 -0
  181. data/lib/ingenico/direct/sdk/domain/token_data.rb +31 -0
  182. data/lib/ingenico/direct/sdk/domain/token_e_wallet.rb +35 -0
  183. data/lib/ingenico/direct/sdk/domain/token_response.rb +55 -0
  184. data/lib/ingenico/direct/sdk/domain/value_mapping_element.rb +38 -0
  185. data/lib/ingenico/direct/sdk/endpoint_configuration.rb +127 -0
  186. data/lib/ingenico/direct/sdk/exceptions.rb +8 -0
  187. data/lib/ingenico/direct/sdk/factory.rb +136 -0
  188. data/lib/ingenico/direct/sdk/idempotence_exception.rb +24 -0
  189. data/lib/ingenico/direct/sdk/logging.rb +10 -0
  190. data/lib/ingenico/direct/sdk/logging/communicator_logger.rb +22 -0
  191. data/lib/ingenico/direct/sdk/logging/log_message_builder.rb +56 -0
  192. data/lib/ingenico/direct/sdk/logging/logging_capable.rb +19 -0
  193. data/lib/ingenico/direct/sdk/logging/logging_util.rb +271 -0
  194. data/lib/ingenico/direct/sdk/logging/request_log_message_builder.rb +39 -0
  195. data/lib/ingenico/direct/sdk/logging/response_log_message_builder.rb +34 -0
  196. data/lib/ingenico/direct/sdk/logging/ruby_communicator_logger.rb +57 -0
  197. data/lib/ingenico/direct/sdk/logging/stdout_communicator_logger.rb +34 -0
  198. data/lib/ingenico/direct/sdk/marshaller.rb +24 -0
  199. data/lib/ingenico/direct/sdk/marshaller_syntax_exception.rb +6 -0
  200. data/lib/ingenico/direct/sdk/merchant/hostedcheckout/hosted_checkout_client.rb +87 -0
  201. data/lib/ingenico/direct/sdk/merchant/hostedtokenization/hosted_tokenization_client.rb +87 -0
  202. data/lib/ingenico/direct/sdk/merchant/merchant_client.rb +83 -0
  203. data/lib/ingenico/direct/sdk/merchant/payments/payments_client.rb +291 -0
  204. data/lib/ingenico/direct/sdk/merchant/payouts/payouts_client.rb +87 -0
  205. data/lib/ingenico/direct/sdk/merchant/productgroups/get_product_group_params.rb +58 -0
  206. data/lib/ingenico/direct/sdk/merchant/productgroups/get_product_groups_params.rb +58 -0
  207. data/lib/ingenico/direct/sdk/merchant/productgroups/product_groups_client.rb +88 -0
  208. data/lib/ingenico/direct/sdk/merchant/products/get_payment_product_networks_params.rb +39 -0
  209. data/lib/ingenico/direct/sdk/merchant/products/get_payment_product_params.rb +58 -0
  210. data/lib/ingenico/direct/sdk/merchant/products/get_payment_products_params.rb +58 -0
  211. data/lib/ingenico/direct/sdk/merchant/products/get_product_directory_params.rb +31 -0
  212. data/lib/ingenico/direct/sdk/merchant/products/products_client.rb +156 -0
  213. data/lib/ingenico/direct/sdk/merchant/services/services_client.rb +52 -0
  214. data/lib/ingenico/direct/sdk/merchant/sessions/sessions_client.rb +55 -0
  215. data/lib/ingenico/direct/sdk/merchant/tokens/tokens_client.rb +117 -0
  216. data/lib/ingenico/direct/sdk/meta_data_provider.rb +150 -0
  217. data/lib/ingenico/direct/sdk/modules.rb +71 -0
  218. data/lib/ingenico/direct/sdk/not_found_exception.rb +16 -0
  219. data/lib/ingenico/direct/sdk/param_request.rb +11 -0
  220. data/lib/ingenico/direct/sdk/pooled_connection.rb +21 -0
  221. data/lib/ingenico/direct/sdk/proxy_configuration.rb +74 -0
  222. data/lib/ingenico/direct/sdk/reference_exception.rb +14 -0
  223. data/lib/ingenico/direct/sdk/request_header.rb +50 -0
  224. data/lib/ingenico/direct/sdk/request_param.rb +23 -0
  225. data/lib/ingenico/direct/sdk/response_exception.rb +47 -0
  226. data/lib/ingenico/direct/sdk/response_header.rb +42 -0
  227. data/lib/ingenico/direct/sdk/validation_exception.rb +14 -0
  228. data/lib/ingenico/direct/sdk/webhooks.rb +11 -0
  229. data/lib/ingenico/direct/sdk/webhooks/api_version_mismatch_exception.rb +20 -0
  230. data/lib/ingenico/direct/sdk/webhooks/in_memory_secret_key_store.rb +56 -0
  231. data/lib/ingenico/direct/sdk/webhooks/secret_key_not_available_exception.rb +17 -0
  232. data/lib/ingenico/direct/sdk/webhooks/secret_key_store.rb +16 -0
  233. data/lib/ingenico/direct/sdk/webhooks/signature_validation_exception.rb +19 -0
  234. data/lib/ingenico/direct/sdk/webhooks/webhooks.rb +22 -0
  235. data/lib/ingenico/direct/sdk/webhooks/webhooks_event.rb +58 -0
  236. data/lib/ingenico/direct/sdk/webhooks/webhooks_helper.rb +99 -0
  237. data/lib/ingenico/direct/sdk/webhooks/webhooks_helper_builder.rb +25 -0
  238. metadata +385 -0
@@ -0,0 +1,41 @@
1
+ module Ingenico::Direct::SDK
2
+
3
+ # Class used to communicate using the HTTP (or HTTPS) protocol.
4
+ # Performs GET, DELETE, POST and PUT requests given a target uri and request headers.
5
+ # @see Ingenico::Direct::SDK::DefaultImpl::DefaultConnection
6
+ class Connection
7
+ include Ingenico::Direct::SDK::Logging::LoggingCapable
8
+
9
+ # Performs a GET request to _uri_ using _request_headers_,
10
+ # and yields the response as the status code, headers and body.
11
+ #
12
+ # @yield (Integer, Array<Ingenico::Direct::SDK::ResponseHeader>, IO) The status code, headers and body of the response.
13
+ def get(uri, request_headers)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ # Performs a DELETE request to _uri_ using _request_headers_,
18
+ # and yields the response as the status code, headers and body.
19
+ #
20
+ # @yield (Integer, Array<Ingenico::Direct::SDK::ResponseHeader>, IO) The status code, headers and body of the response.
21
+ def delete(uri, request_headers)
22
+ raise NotImplementedError
23
+ end
24
+
25
+ # Performs a POST request to _uri_ using _request_headers_ and _body_,
26
+ # and yields the response as the status code, headers and body.
27
+ #
28
+ # @yield (Integer, Array<Ingenico::Direct::SDK::ResponseHeader>, IO) The status code, headers and body of the response.
29
+ def post(uri, request_headers, body)
30
+ raise NotImplementedError
31
+ end
32
+
33
+ # Performs a PUT request to _uri_ using _request_headers_ and _body_,
34
+ # and yields the response as the status code, headers and body.
35
+ #
36
+ # @yield (Integer, Array<Ingenico::Direct::SDK::ResponseHeader>, IO) The status code, headers and body of the response.
37
+ def put(uri, request_headers, body)
38
+ raise NotImplementedError
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+
3
+ module Ingenico::Direct::SDK
4
+
5
+ # Base class for all SDK data objects, supports marshalling and unmarshalling the data object to and from JSON.
6
+ class DataObject
7
+
8
+ # Returns a hash representation of the DataObject.
9
+ # The hash contains camelCase representations of the variables, and their values.
10
+ # Should be overridden to add all instance variables of the object.
11
+ #
12
+ # @return [Hash]
13
+ def to_h
14
+ {}
15
+ end
16
+
17
+ # Create a new instance of this object (DataObject or descendant)
18
+ # from a hash containing attribute values in camelCase.
19
+ # Note that the hash contains Strings as keys instead of more commonly used tokens.
20
+ def self.new_from_hash(hash)
21
+ obj = self.new
22
+ obj.from_hash(hash)
23
+ obj
24
+ end
25
+
26
+ # Set attributes from values in parameter hash.
27
+ # Should be overridden by descendants in order to properly restore their attributes from the hash.
28
+ # Note that the hash contains Strings as keys instead of more commonly used tokens.
29
+ def from_hash(hash)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ module Ingenico::Direct::SDK
2
+
3
+ # Indicates that a payment is declined by the Ingenico ePayments platform or one of its downstream partners/acquirers.
4
+ class DeclinedPaymentException < DeclinedTransactionException
5
+
6
+ # Create a new DeclinedPaymentException.
7
+ # @see ApiException#initialize
8
+ def initialize(status_code, response_body, errors)
9
+ super(status_code, response_body, errors&.error_id, errors&.errors, build_message(errors))
10
+ @errors = errors
11
+ end
12
+
13
+ # The declined payment result returned by the Ingenico ePayments platform.
14
+ # @return [Ingenico::Direct::SDK::Domain::CreatePaymentResult, nil]
15
+ def payment_result
16
+ @errors&.payment_result
17
+ end
18
+
19
+ private
20
+
21
+ def build_message(errors)
22
+ payment = errors&.payment_result&.payment
23
+ if payment
24
+ "declined payment '#{payment.id}' with status '#{payment.status}'"
25
+ else
26
+ 'the Ingenico ePayments platform returned a declined payment response'
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require 'ingenico/direct/sdk/declined_transaction_exception'
2
+
3
+ module Ingenico::Direct::SDK
4
+
5
+ # Indicates that a payout is declined by the Ingenico ePayments platform or one of its downstream partners/acquirers.
6
+ class DeclinedPayoutException < DeclinedTransactionException
7
+
8
+ # Create a new DeclinedPayoutException
9
+ # @see ApiException#initialize
10
+ def initialize(status_code, response_body, errors)
11
+ super(status_code, response_body, errors&.error_id, errors&.errors, build_message(errors))
12
+ @errors = errors
13
+ end
14
+
15
+ # The declined payout result as returned by the Ingenico ePayments platform.
16
+ # @return [Ingenico::Direct::SDK::Domain::PayoutResult, nil]
17
+ def payout_result
18
+ @errors&.payout_result
19
+ end
20
+
21
+ private
22
+
23
+ def build_message(errors)
24
+ payout = errors&.payout_result
25
+ if payout
26
+ "declined payout '#{payout.id}' with status '#{payout.status}'"
27
+ else
28
+ 'the Ingenico ePayments platform returned a declined payout response'
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ require 'ingenico/direct/sdk/declined_transaction_exception'
2
+
3
+ module Ingenico::Direct::SDK
4
+
5
+ # Indicates that a refund is declined by the Ingenico ePayments platform or one of its downstream partners/acquirers.
6
+ class DeclinedRefundException < DeclinedTransactionException
7
+
8
+ # Create a new DeclinedRefundException
9
+ # @see ApiException#initialize
10
+ def initialize(status_code, response_body, errors)
11
+ super(status_code, response_body, errors&.error_id, errors&.errors, build_message(errors))
12
+ @errors = errors
13
+ end
14
+
15
+ # The declined refund result as returned by the Ingenico ePayments platform.
16
+ # @return [Ingenico::Direct::SDK::Domain::RefundResult, nil]
17
+ def refund_result
18
+ @errors&.refund_result
19
+ end
20
+
21
+ private
22
+
23
+ def build_message(errors)
24
+ refund = errors&.refund_result
25
+ if refund
26
+ "declined refund '#{refund.id}' with status '#{refund.status}'"
27
+ else
28
+ 'the Ingenico ePayments platform returned a declined refund response'
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module Ingenico::Direct::SDK
2
+
3
+ # Indicates that a transaction is declined by the Ingenico ePayments platform or one of its downstream partners/acquirers.
4
+ class DeclinedTransactionException < ApiException
5
+
6
+ # Create a new DeclinedTransactionException.
7
+ # @see ApiException#initialize
8
+ def initialize(status_code, response_body, error_id, errors, message = nil)
9
+ if message
10
+ super(status_code, response_body, error_id, errors, message)
11
+ else
12
+ super(status_code, response_body, error_id, errors)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ prefix = 'ingenico/direct/sdk/defaultimpl'
2
+
3
+ require "#{prefix}/authorization_type"
4
+ require "#{prefix}/default_marshaller"
5
+ require "#{prefix}/default_connection"
6
+ require "#{prefix}/default_authenticator"
@@ -0,0 +1,24 @@
1
+ module Ingenico::Direct::SDK
2
+ module DefaultImpl
3
+
4
+ # Contains all authentication schemes supported by the GlobabCollect platform.
5
+ class AuthorizationType
6
+ V1HMAC = 'v1HMAC'
7
+
8
+ # @return [String] the authorization string that belongs to the parameter _authorization_, or _nil_ if not found.
9
+ def self.get_authorization(authorization)
10
+ case authorization.downcase
11
+ when V1HMAC.downcase
12
+ return V1HMAC
13
+ else
14
+ raise ArgumentError "Unknown authorization type '#{authorization}'"
15
+ end
16
+ end
17
+
18
+ # @return [String]
19
+ def self.get_signature_string
20
+ V1HMAC
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,108 @@
1
+ require 'openssl' # for HMAC-SHA256
2
+ require 'base64'
3
+
4
+ module Ingenico::Direct::SDK
5
+ module DefaultImpl
6
+
7
+ # Authenticates requests made to the Ingenico ePayments platform using the HMAC algorithm.
8
+ class DefaultAuthenticator < Authenticator
9
+
10
+ # HMAC algorithm used to generate the signature
11
+ HMAC_ALGOR = 'SHA256'.freeze
12
+ CONTENT_TYPE = 'Content-Type'.freeze
13
+ DATE = 'Date'.freeze
14
+ XGCS = 'x-gcs'.freeze
15
+
16
+ # Construct a new DefaultAuthenticator instance that can sign requests
17
+ # with the provided _api_key_id_ and _secret_api_key_.
18
+ #
19
+ # @param api_key_id [String] identifier for the secret key used in authentication.
20
+ # @param secret_api_key [String] the secret key that is used to generate the authentication signature.
21
+ # @param authorization_type [String] the authorization protocol to use for authentication.
22
+ def initialize(api_key_id, secret_api_key, authorization_type = AuthorizationType::V1HMAC)
23
+ raise ArgumentError unless api_key_id && !api_key_id.strip.empty?
24
+ raise ArgumentError unless secret_api_key && !secret_api_key.strip.empty?
25
+ raise ArgumentError unless authorization_type && !authorization_type.strip.empty?
26
+
27
+ @api_key_id = api_key_id
28
+ @secret_api_key = secret_api_key
29
+ @authorization_type = authorization_type
30
+ end
31
+
32
+ # Creates a signature to authenticate a request.
33
+ #
34
+ # @param http_method [String] 'GET', 'PUT', 'POST' or 'DELETE' indicating which HTTP method will be used with the request
35
+ # @param resource_uri [URI::HTTP] URI object that includes #path and #query of the URL that will be used, #query may be *nil*
36
+ # @param http_headers [Array<Ingenico::Direct::SDK::RequestHeader>] list that contains all headers used by the request
37
+ # @return [String] the created signature
38
+ def create_simple_authentication_signature(http_method, resource_uri, http_headers)
39
+ raise ArgumentError unless http_method && !http_method.strip.empty?
40
+ raise ArgumentError unless resource_uri
41
+
42
+ data_to_sign = to_data_to_sign(http_method, resource_uri, http_headers)
43
+ "GCS #{@authorization_type}:#{@api_key_id}:#{create_auth_signature(data_to_sign)}"
44
+ end
45
+
46
+ protected
47
+
48
+ # Canonizes the _http_method_, _resource_uri_ and _http_headers_ so a unique signature can be generated.
49
+ # Canonical form is as follows:
50
+ # * _http_method_ in upper case
51
+ # * Content-Type
52
+ # * Date header
53
+ # * X-GCS headers sorted alphabetically. Names are in lowercase and values are stripped of excess whitespace
54
+ # * path and query portion of the uri, separated by a question mark
55
+ def to_data_to_sign(http_method, resource_uri, http_headers)
56
+ content_type = ''
57
+ date = ''
58
+ canonical_resource = to_canonical_resource(resource_uri)
59
+ xgc_http_headers = []
60
+
61
+ http_headers&.each do |header|
62
+ name = header.name
63
+ value = header.value
64
+ case
65
+ when name.casecmp(CONTENT_TYPE).zero?
66
+ content_type = value
67
+ when name.casecmp(DATE).zero?
68
+ date = value
69
+ when to_canonical_header_name(name).start_with?("x-gcs")
70
+ xgc_http_headers << [to_canonical_header_name(name), to_canonical_header_value(value)]
71
+ end
72
+ end
73
+
74
+ xgc_http_headers.sort! { |(h1, v1), (h2, v2)| h1 <=> h2 } unless xgc_http_headers.empty?
75
+
76
+ data = "#{http_method.upcase}\n#{content_type}\n#{date}\n"
77
+ data << xgc_http_headers.inject('') { |s, (k, v)| "#{s}#{k}:#{v}\n" } unless xgc_http_headers.empty?
78
+ data << "#{canonical_resource}\n" if canonical_resource
79
+ end
80
+
81
+ # Applies the HMAC algorithm to the canonicalized data to obtain an HMAC digest.
82
+ # Afterwards the HMAC digest is encoded using base64 encoding.
83
+ def create_auth_signature(data_to_sign)
84
+ digest = OpenSSL::Digest.new(HMAC_ALGOR)
85
+ hmac = OpenSSL::HMAC.digest(digest, @secret_api_key, data_to_sign)
86
+ Base64.strict_encode64(hmac).strip
87
+ end
88
+
89
+ private
90
+
91
+ # Returns the encoded URI path without the HTTP method and including all decoded query parameters.
92
+ def to_canonical_resource(resource_uri)
93
+ return "#{resource_uri.path}?#{resource_uri.query}" if resource_uri.query
94
+ resource_uri.path
95
+ end
96
+
97
+ def to_canonical_header_name(original_name)
98
+ original_name ? original_name.downcase : original_name
99
+ end
100
+
101
+ # Strips a header value of excess whitespace to produce a canonical value
102
+ def to_canonical_header_value(original_value)
103
+ return '' unless original_value
104
+ original_value.gsub(/\r?\n[\s&&[^\r\n]]*/, ' ').strip
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,293 @@
1
+ require 'securerandom'
2
+ require 'uri'
3
+ require 'httpclient'
4
+
5
+ # @private :nodoc: this is not our class
6
+ module RefineHTTPClient
7
+ refine HTTPClient do
8
+ # (monkey) patch to gain access to the session pool size in HTTPClient
9
+ def session_count
10
+ sess_pool = @session_manager.instance_variable_get(:@sess_pool)
11
+ sess_pool.size
12
+ end
13
+ end
14
+ end
15
+
16
+ module Ingenico::Direct::SDK
17
+ module DefaultImpl
18
+ class DefaultConnection < PooledConnection
19
+ using RefineHTTPClient
20
+
21
+ CONTENT_TYPE = 'Content-Type'.freeze
22
+ JSON_CONTENT_TYPE = 'application/json'.freeze
23
+
24
+ # @param args [Hash] the parameters to initialize the connection with
25
+ # @option args [Integer] :connect_timeout connection timeout in seconds.
26
+ # Uses {CommunicatorConfiguration.default_connect_timeout} if not given.
27
+ # @option args [Integer] :socket_timeout socket timeout in seconds.
28
+ # Uses {CommunicatorConfiguration.default_socket_timeout} if not given.
29
+ # @option args [Integer] :max_connections number of connections kept alive in the thread pool.
30
+ # Uses {CommunicatorConfiguration.default_max_connections} if not given.
31
+ # @option args [Hash] :proxy_configuration object that stores the proxy to use.
32
+ # If not given the system default proxy is used;
33
+ # if there is no system default proxy set either, no proxy is used.
34
+ def initialize(args)
35
+ raise ArgumentError unless args.is_a? Hash
36
+
37
+ super()
38
+
39
+ # Set timeouts to nil if they are negative
40
+ @connect_timeout = args[:connect_timeout] || CommunicatorConfiguration.default_connect_timeout
41
+ @connect_timeout = nil unless @connect_timeout&.positive?
42
+ @socket_timeout = args[:socket_timeout] || CommunicatorConfiguration.default_socket_timeout
43
+ @socket_timeout = nil unless @socket_timeout&.positive?
44
+ @max_connections = args[:max_connections] || CommunicatorConfiguration.default_max_connections
45
+ @proxy_configuration = args[:proxy_configuration]
46
+
47
+ # HTTPClient provides the following features:
48
+ # 1) thread safe, an instance can be used by multiple threads without
49
+ # explicit synchronization
50
+ # 2) use persistent connection if HTTP 1.1 is supported. The connection
51
+ # will be left open until explicitly closed or keep_alive_timeout
52
+ # 3) a built-in connection pool with no limit for max connections
53
+ @http_client = create_http_client
54
+ @http_client.connect_timeout = @connect_timeout
55
+ @http_client.send_timeout = @socket_timeout
56
+ @http_client.receive_timeout = @socket_timeout
57
+ end
58
+
59
+ private
60
+
61
+ # Create a HTTPClient instance that uses @proxy_configuration or the system proxy if @proxy_configuration is not set
62
+ def create_http_client
63
+ if @proxy_configuration
64
+ httpclient = HTTPClient.new(@proxy_configuration.proxy_uri)
65
+ httpclient.set_proxy_auth(@proxy_configuration.username, @proxy_configuration.password)
66
+ httpclient.force_basic_auth = true if @proxy_configuration.username && @proxy_configuration.password
67
+ else # use system settings
68
+ proxy_string = ENV['https_proxy'] || ENV['http_proxy']
69
+ # proxy string format = 'http://username:password@hostname:port'
70
+ proxy_string =~ %r{https?//(?<username>[^:]):(?<password>[^@])@.*}
71
+ username = Regexp.last_match(1)
72
+ password = Regexp.last_match(2)
73
+ httpclient = HTTPClient.new(proxy_string)
74
+ httpclient.set_proxy_auth(username, password) if username && password
75
+ httpclient.force_basic_auth = true if username && password
76
+ end
77
+ httpclient
78
+ end
79
+
80
+ public
81
+
82
+ # Closes all connections idle for longer than _idle_time_ seconds.
83
+ # In addition, the keep_alive_timeout is set to _idle_time_
84
+ # so any future connections idle for longer than _idle_time_ seconds will also be closed.
85
+ def close_idle_connections(idle_time) # in sec
86
+ @http_client.keep_alive_timeout = idle_time # set timeout value
87
+ close_expired_connections
88
+ end
89
+
90
+ # HTTPClient automatically closes expired connections so _close_expired_connections_ is a no-operation.
91
+ def close_expired_connections
92
+ # By default the keep alive timeout is 15 sec, which is the HTTP 1.1
93
+ # standard. To change the value, use keep_alive_timeout= method
94
+ # do nothing, handled by HTTPClient
95
+ end
96
+
97
+ # Frees all networking resources used.
98
+ def close
99
+ @http_client.reset_all
100
+ end
101
+
102
+ # Returns the number of open connections
103
+ def session_count
104
+ @http_client.session_count
105
+ end
106
+
107
+ # Performs a GET request to the Ingenico ePayments platform
108
+ # @see request
109
+ def get(uri, request_headers)
110
+ request('get', uri, request_headers) do |response_status_code, response_headers, response_body|
111
+ yield response_status_code, response_headers, response_body
112
+ end
113
+ end
114
+
115
+ # Performs a DELETE request to the Ingenico ePayments platform
116
+ # @see request
117
+ def delete(uri, request_headers)
118
+ request('delete', uri, request_headers) do |response_status_code, response_headers, response_body|
119
+ yield response_status_code, response_headers, response_body
120
+ end
121
+ end
122
+
123
+ # Performs a POST request to the Ingenico ePayments platform
124
+ # @see request
125
+ def post(uri, request_headers, body)
126
+ request('post', uri, request_headers, body) do |response_status_code, response_headers, response_body|
127
+ yield response_status_code, response_headers, response_body
128
+ end
129
+ end
130
+
131
+ # Performs a PUT request to the Ingenico ePayments platform
132
+ # @see request
133
+ def put(uri, request_headers, body)
134
+ request('put', uri, request_headers, body) do |response_status_code, response_headers, response_body|
135
+ yield response_status_code, response_headers, response_body
136
+ end
137
+ end
138
+
139
+ # Performs a HTTP request and yields the response as the status code, headers and body.
140
+ # Also ensures the request is logged when sent and its response is logged when received.
141
+ #
142
+ # @param method [String] 'GET', 'DELETE', 'POST' or 'PUT' depending on the HTTP method being used.
143
+ # @param uri [URI::HTTP] full URI of the location the request is targeted at, including query parameters.
144
+ # @param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>] list of headers that should be used as HTTP headers in the request.
145
+ # @param body [String] request body.
146
+ # @yield (Integer, Array<Ingenico::Direct::SDK::ResponseHeader>, IO) The status code, headers and body of the response.
147
+ # @raise [Ingenico::Direct::SDK::CommunicationException] when communication with the Ingenico ePayments platform was not successful.
148
+ def request(method, uri, request_headers, body = nil)
149
+ request_headers = convert_from_headers(request_headers)
150
+ request_id = SecureRandom.uuid
151
+ content_type = request_headers[CONTENT_TYPE]
152
+
153
+ info = { headers: request_headers, content_type: content_type }
154
+ info[:body] = body if body
155
+
156
+ log_request(request_id, method.upcase, uri, info)
157
+
158
+ start_time = Time.now
159
+ begin
160
+ response_headers = nil
161
+ response_status_code = nil
162
+ response_content_type = nil
163
+ response_body = ''
164
+ raw_request(method, uri, request_headers, body) do |status_code, headers, r_content_type, r_body|
165
+ response_headers = headers
166
+ response_status_code = status_code
167
+ response_content_type = r_content_type
168
+ response_body = r_body.read.force_encoding('UTF-8')
169
+ r_body = StringIO.new(response_body)
170
+
171
+ yield status_code, headers, r_body
172
+ end
173
+
174
+ log_response(request_id, response_status_code, start_time,
175
+ headers: response_headers, body: response_body,
176
+ content_type: response_content_type)
177
+ rescue HTTPClient::TimeoutError => e
178
+ log_error(request_id, start_time, e)
179
+ raise Ingenico::Direct::SDK::CommunicationException, e
180
+ rescue HTTPClient::KeepAliveDisconnected, HTTPClient::RetryableResponse => e # retry these?
181
+ log_error(request_id, start_time, e)
182
+ raise Ingenico::Direct::SDK::CommunicationException, e
183
+ rescue StandardError => e
184
+ log_error(request_id, start_time, e)
185
+ raise Ingenico::Direct::SDK::CommunicationException, e
186
+ end
187
+ end
188
+
189
+ # logging code
190
+
191
+ # Enables logging outgoing requests and incoming responses by registering the _communicator_logger_.
192
+ # Note that only one logger can be registered at a time and calling _enable_logging_
193
+ # a second time will override the old logger instance with the new one.
194
+ #
195
+ # @param communicator_logger [Ingenico::Direct::SDK::Logging::CommunicatorLogger] the communicator logger the requests and responses are logged to
196
+ def enable_logging(communicator_logger)
197
+ raise ArgumentError, 'communicatorLogger is required' unless communicator_logger
198
+
199
+ @communicator_logger = communicator_logger
200
+ end
201
+
202
+ # Disables logging by unregistering any previous logger that might be registered.
203
+ def disable_logging
204
+ @communicator_logger = nil
205
+ end
206
+
207
+ private
208
+
209
+ # Converts a {Ingenico::Direct::SDK::RequestHeader} list headers to a hash
210
+ def convert_from_headers(headers)
211
+ headers.each_with_object({}) { |h, hash| hash[h.name] = h.value }
212
+ end
213
+
214
+ # Converts a hash to a {Ingenico::Direct::SDK::ResponseHeader} list
215
+ def convert_to_response_headers(headers)
216
+ arr ||= []
217
+ headers.each { |k, v| arr << Ingenico::Direct::SDK::ResponseHeader.new(k, v) }
218
+ arr
219
+ end
220
+
221
+ def log_request(request_id, method, uri, args = {})
222
+ return unless @communicator_logger
223
+
224
+ headers = args[:headers]
225
+ body = args[:body]
226
+ content_type = args[:content_type]
227
+ log_msg_builder = Ingenico::Direct::SDK::Logging::RequestLogMessageBuilder.new(request_id, method, uri)
228
+ headers.each { |k, v| log_msg_builder.add_headers(k, v) } if headers
229
+
230
+ log_msg_builder.set_body(body, content_type)
231
+
232
+ begin
233
+ @communicator_logger.log(log_msg_builder.get_message)
234
+ rescue StandardError => e
235
+ @communicator_logger.log("An error occurred trying to log request #{request_id}", e)
236
+ end
237
+ end
238
+
239
+ # Creates the log_response stream
240
+ def log_response(request_id, status_code, start_time, args = {})
241
+ return unless @communicator_logger
242
+
243
+ duration = (Time.now - start_time) * 1000 # in milliseconds
244
+ headers = args[:headers]
245
+ body = args[:body] if args[:body]
246
+ content_type = args[:content_type]
247
+
248
+ log_msg_builder = Ingenico::Direct::SDK::Logging::ResponseLogMessageBuilder.new(request_id, status_code, duration)
249
+ if headers
250
+ convert_from_headers(headers)
251
+ .each do |key, value|
252
+ log_msg_builder.add_headers(key, value)
253
+ end
254
+ end
255
+
256
+ log_msg_builder.set_body(body, content_type)
257
+
258
+ begin
259
+ @communicator_logger.log(log_msg_builder.get_message)
260
+ rescue StandardError => e
261
+ @communicator_logger.log("An error occurred trying to log response #{request_id}", e)
262
+ end
263
+ end
264
+
265
+ def log_error(request_id, start_time, thrown)
266
+ return unless @communicator_logger
267
+
268
+ duration = (Time.now - start_time) * 1000 # in millisecs
269
+ @communicator_logger.log("Error occurred for outgoing request (requestId='#{request_id}', #{duration} ms)", thrown)
270
+ end
271
+
272
+ # Makes a request using the specified method
273
+ #
274
+ # Yields a status code, an array of {Ingenico::Direct::SDK::ResponseHeader},
275
+ # the content_type and body
276
+ def raw_request(method, uri, headers, body = nil)
277
+ connection = body ?
278
+ @http_client.send("#{method}_async", uri, body: body, header: headers) :
279
+ @http_client.send("#{method}_async", uri, header: headers)
280
+
281
+ response = connection.pop
282
+ pipe = response.content
283
+ response_headers = convert_to_response_headers(response.headers)
284
+
285
+ begin
286
+ yield response.status_code, response_headers, response.content_type, pipe
287
+ ensure
288
+ pipe.close
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end