rails-gp-webpay 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +41 -0
  3. data/Rakefile +6 -0
  4. data/app/controllers/gp_webpay/cards_controller.rb +11 -0
  5. data/app/controllers/gp_webpay/orders_controller.rb +11 -0
  6. data/app/controllers/gp_webpay_controller.rb +18 -0
  7. data/changelog.md +4 -0
  8. data/config/keys/cert.pem +8 -0
  9. data/config/keys/pkey.pem +13 -0
  10. data/config/routes.rb +4 -0
  11. data/config/wsdl/GPwebpayAdditionalInfoResponse_v1.xsd +194 -0
  12. data/config/wsdl/cws_v1.wsdl +2355 -0
  13. data/config/wsdl/swaref.xsd +59 -0
  14. data/lib/gp_webpay.rb +55 -0
  15. data/lib/gp_webpay/configuration.rb +65 -0
  16. data/lib/gp_webpay/engine.rb +7 -0
  17. data/lib/gp_webpay/error.rb +4 -0
  18. data/lib/gp_webpay/http/base_signed_request.rb +72 -0
  19. data/lib/gp_webpay/http/create_order.rb +24 -0
  20. data/lib/gp_webpay/http/external_url.rb +13 -0
  21. data/lib/gp_webpay/http/http_request.rb +63 -0
  22. data/lib/gp_webpay/http/http_response.rb +40 -0
  23. data/lib/gp_webpay/http/validate_result.rb +63 -0
  24. data/lib/gp_webpay/http/verify_card.rb +18 -0
  25. data/lib/gp_webpay/openssl_security.rb +16 -0
  26. data/lib/gp_webpay/response.rb +34 -0
  27. data/lib/gp_webpay/service.rb +15 -0
  28. data/lib/gp_webpay/version.rb +3 -0
  29. data/lib/gp_webpay/ws/base_signed_request.rb +69 -0
  30. data/lib/gp_webpay/ws/echo.rb +35 -0
  31. data/lib/gp_webpay/ws/services/get_master_payment_status.rb +32 -0
  32. data/lib/gp_webpay/ws/services/get_payment_status.rb +19 -0
  33. data/lib/gp_webpay/ws/services/get_token_status.rb +21 -0
  34. data/lib/gp_webpay/ws/services/process_cancel_capture.rb +20 -0
  35. data/lib/gp_webpay/ws/services/process_capture_reverse.rb +20 -0
  36. data/lib/gp_webpay/ws/services/process_card_on_file_payment.rb +40 -0
  37. data/lib/gp_webpay/ws/services/process_master_payment_revoke.rb +20 -0
  38. data/lib/gp_webpay/ws/services/process_recurring_payment.rb +20 -0
  39. data/lib/gp_webpay/ws/services/process_refund_payment.rb +20 -0
  40. data/lib/gp_webpay/ws/services/process_token_payment.rb +26 -0
  41. data/lib/gp_webpay/ws/services/process_token_revoke.rb +20 -0
  42. data/lib/gp_webpay/ws/services/process_usage_based_payment.rb +21 -0
  43. data/lib/gp_webpay/ws/validate_result.rb +48 -0
  44. data/lib/gp_webpay/ws/ws_request.rb +39 -0
  45. data/lib/gp_webpay/ws/ws_response.rb +54 -0
  46. metadata +135 -0
@@ -0,0 +1,18 @@
1
+ ##
2
+ # Service object creates request data for GP Webpay CARD_VERIFICATION operation.
3
+
4
+ module GpWebpay
5
+ module Http
6
+ class VerifyCard < BaseSignedRequest
7
+ def initialize(attributes, locale, merchant_number: nil, url_attributes: {})
8
+ super(attributes, locale, 'CARD_VERIFICATION', merchant_number: merchant_number, url_attributes: url_attributes)
9
+ end
10
+
11
+ protected
12
+
13
+ def callback_url
14
+ GpWebpay::Engine.routes.url_helpers.gp_webpay_cards_path({ merchant_number: config.merchant_number, locale: locale }.merge(url_attributes))
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module GpWebpay
2
+ module OpensslSecurity
3
+ def self.generate_digest(configuration, digest_text)
4
+ private_pem = OpenSSL::PKey::RSA.new(configuration.merchant_pem, configuration.merchant_password)
5
+ sign = private_pem.sign(OpenSSL::Digest.new('SHA1'), digest_text)
6
+ Base64.encode64(sign).gsub("\n", '')
7
+ end
8
+
9
+ def self.validate_digests(configuration, data)
10
+ public_pem = OpenSSL::X509::Certificate.new(configuration.gpe_pem).public_key
11
+ data.all? do |received, expected|
12
+ public_pem.verify(OpenSSL::Digest.new('SHA1'), Base64.decode64(received), expected)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ module GpWebpay
2
+ class Response
3
+ attr_accessor :original_response,
4
+ :result_text,
5
+ :token,
6
+ :status,
7
+ :pr_code,
8
+ :sr_code,
9
+ :config,
10
+ :params
11
+
12
+ # rubocop:disable Metrics/ParameterLists
13
+ def initialize(original_response:, result_text:, status:, pr_code:, sr_code:, params:, token: nil, merchant_number: nil)
14
+ @original_response = original_response
15
+ @result_text = result_text
16
+ @token = token
17
+ @status = status
18
+ @pr_code = pr_code
19
+ @sr_code = sr_code
20
+ @params = params
21
+ @merchant_number = merchant_number
22
+ @config = GpWebpay.config[merchant_number] || GpWebpay.config.default
23
+ end
24
+
25
+ # rubocop:enable Metrics/ParameterLists
26
+
27
+ def valid?
28
+ end
29
+
30
+ def success?
31
+ pr_code == '0' && sr_code == '0'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ module GpWebpay
2
+ class Service
3
+ def initialize(*)
4
+ end
5
+
6
+ class << self
7
+ ruby2_keywords def call(*args)
8
+ new(*args).call
9
+ end
10
+ end
11
+
12
+ def call
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module GpWebpay
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,69 @@
1
+ ##
2
+ # Service object signs request which can be send to GP Webpay payment gateway.
3
+ #
4
+ # 1. Use request value object to translate attributes to correct GP Webpay format and order.
5
+ # 2. Append generated signature to attributes. We expect that XML types are prefixed with 'ins0:' by default.
6
+ # 3. send XML WS SOAP API request.
7
+ # 4. generate response object:
8
+ # - success containing response.
9
+ # - http error when client-side request fails.
10
+ # - fail error when external server returns fault.
11
+ #
12
+ # @param [Hash] attributes for GP Webpay
13
+ #
14
+ # @return [GpwebpayWsResponse] response value object
15
+
16
+ module GpWebpay
17
+ module Ws
18
+ class BaseSignedRequest < Service
19
+ attr_reader :attributes, :config
20
+
21
+ OPERATION_NAME = 'override_me'.freeze
22
+ REQUEST_NAME = 'override_me'.freeze
23
+ RESPONSE_NAME = 'override_me'.freeze
24
+ RESPONSE_ENTITY_NAME = 'override_me'.freeze
25
+ SERVICE_EXCEPTION = :service_exception
26
+
27
+ def initialize(attributes, merchant_number: :default)
28
+ @attributes = attributes
29
+ @merchant_number = merchant_number
30
+ @config = GpWebpay.config[@merchant_number] || GpWebpay.config.default
31
+ super()
32
+ end
33
+
34
+ def call
35
+ attrs = WsRequest.new(attributes.merge(provider: config.provider, merchant_number: config.merchant_number)).to_gpwebpay
36
+
37
+ res = client.call(self.class::OPERATION_NAME, message: { self.class::REQUEST_NAME => attributes_with_signature(attrs) })
38
+ WsResponse.from_success(res.body, self.class::RESPONSE_NAME, self.class::RESPONSE_ENTITY_NAME, config.merchant_number)
39
+ rescue Savon::HTTPError => e
40
+ rescue_from_http(e)
41
+ rescue Savon::SOAPFault => e
42
+ rescue_from_soap(e)
43
+ end
44
+
45
+ protected
46
+
47
+ def digest_text(attrs)
48
+ attrs.values.join('|')
49
+ end
50
+
51
+ def attributes_with_signature(attrs)
52
+ digest = OpensslSecurity.generate_digest(config, digest_text(attrs))
53
+ attrs.merge('ins0:signature' => digest)
54
+ end
55
+
56
+ def client
57
+ @client ||= Savon.client(wsdl: config.wsdl_file, endpoint: config.ws_url, pretty_print_xml: true)
58
+ end
59
+
60
+ def rescue_from_http(error)
61
+ WsResponse.from_http_error(error.to_hash, config.merchant_number)
62
+ end
63
+
64
+ def rescue_from_soap(error)
65
+ WsResponse.from_fault_error(error.to_hash, self.class::SERVICE_EXCEPTION, config.merchant_number)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,35 @@
1
+ ##
2
+ # Service object checks if GP Webpay WS service is available.
3
+ #
4
+ # 1. Send request :echo operation to SOUP API.
5
+ # 2. Receive answer, return true if response is present in desired format.
6
+ # 3. Return false if
7
+ # - response is not in valid format.
8
+ # - request fails client-side.
9
+ # - request returns failure from server.
10
+ #
11
+ # @return [Boolean] GP Webpay is available
12
+
13
+ module GpWebpay
14
+ module Ws
15
+ class Echo < Service
16
+ attr_reader :config
17
+
18
+ def initialize
19
+ super
20
+ @config = GpWebpay.config.default
21
+ end
22
+
23
+ def call
24
+ res = client.call(:echo)
25
+ res.body && res.body[:echo_response].present?
26
+ rescue Savon::HTTPError, Savon::SOAPFault
27
+ false
28
+ end
29
+
30
+ def client
31
+ @client ||= Savon.client(wsdl: config.wsdl_file, endpoint: config.ws_url, pretty_print_xml: true)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ ##
2
+ # Service object returns current status of credit card token.
3
+ # Should be used to keep credit card status up-to date,
4
+ # should be called before process_token_payment to ensure card is still VERIFIED.
5
+ #
6
+ # @param [Hash] attributes for GP Webpay
7
+ #
8
+ # @return [GpwebpayWsResponse] response value object
9
+
10
+ module GpWebpay
11
+ module Ws
12
+ module Services
13
+ class GetMasterPaymentStatus < BaseSignedRequest
14
+ OPERATION_NAME = :get_master_payment_status
15
+ REQUEST_NAME = :master_payment_status_request
16
+ RESPONSE_NAME = :get_master_payment_status_response
17
+ RESPONSE_ENTITY_NAME = :master_payment_status_response
18
+
19
+ SHORTCUT_TRANSFORMATION = {
20
+ CR: 'CREATED',
21
+ PS: 'ISSUED',
22
+ OK: 'VERIFIED',
23
+ CM: 'REVOKED',
24
+ CI: 'DECLINED',
25
+ CC: 'DECLINED',
26
+ EC: 'EXPIRED',
27
+ EP: 'EXPIRED'
28
+ }.freeze
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ ##
2
+ # Service object returns current status of payment.
3
+ #
4
+ # @param [Hash] attributes for GP Webpay
5
+ #
6
+ # @return [GpwebpayWsResponse] response value object
7
+
8
+ module GpWebpay
9
+ module Ws
10
+ module Services
11
+ class GetPaymentStatus < BaseSignedRequest
12
+ OPERATION_NAME = :get_payment_status
13
+ REQUEST_NAME = :payment_status_request
14
+ RESPONSE_NAME = :get_payment_status_response
15
+ RESPONSE_ENTITY_NAME = :payment_status_response
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ ##
2
+ # Service object returns current status of credit card token.
3
+ # Should be used to keep credit card status up-to date,
4
+ # should be called before process_token_payment to ensure card is still VERIFIED.
5
+ #
6
+ # @param [Hash] attributes for GP Webpay
7
+ #
8
+ # @return [GpwebpayWsResponse] response value object
9
+
10
+ module GpWebpay
11
+ module Ws
12
+ module Services
13
+ class GetTokenStatus < BaseSignedRequest
14
+ OPERATION_NAME = :get_token_status
15
+ REQUEST_NAME = :token_status_request
16
+ RESPONSE_NAME = :get_token_status_response
17
+ RESPONSE_ENTITY_NAME = :token_status_response
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessCancelCapture < BaseSignedRequest
13
+ OPERATION_NAME = :process_authorization_reverse
14
+ REQUEST_NAME = :authorization_reverse_request
15
+ RESPONSE_NAME = :process_authorization_reverse_response
16
+ RESPONSE_ENTITY_NAME = :authorization_reverse_response
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessCaptureReverse < BaseSignedRequest
13
+ OPERATION_NAME = :process_capture_reverse
14
+ REQUEST_NAME = :capture_reverse_request
15
+ RESPONSE_NAME = :process_capture_reverse_response
16
+ RESPONSE_ENTITY_NAME = :capture_reverse_response
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,40 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessCardOnFilePayment < BaseSignedRequest
13
+ OPERATION_NAME = :process_card_on_file_payment
14
+ REQUEST_NAME = :card_on_file_payment_request
15
+ RESPONSE_NAME = :process_card_on_file_payment_response
16
+ RESPONSE_ENTITY_NAME = :card_on_file_payment_response
17
+ SERVICE_EXCEPTION = :card_on_file_payment_service_exception
18
+
19
+ def rescue_from_soap(exception)
20
+ response = WsResponse.from_fault_error(exception.to_hash, self.class::SERVICE_EXCEPTION, config.merchant_number)
21
+
22
+ if response.valid? && response.params[:authentication_link].present?
23
+ raise GpWebpayConfirmationRequired.new('GP Webpay requires authentication', response.params[:authentication_link])
24
+ else
25
+ response
26
+ end
27
+ end
28
+
29
+ class GpWebpayConfirmationRequired < GpWebpay::Error
30
+ attr_reader :authentication_link
31
+
32
+ def initialize(msg = nil, authentication_link = nil)
33
+ super(msg)
34
+ @authentication_link = authentication_link
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,20 @@
1
+ ##
2
+ # Service object changes credit card token status to "REVOKED".
3
+ # Should be used when user decides to remove card from system.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessMasterPaymentRevoke < BaseSignedRequest
13
+ OPERATION_NAME = :process_master_payment_revoke
14
+ REQUEST_NAME = :master_payment_revoke_request
15
+ RESPONSE_NAME = :process_master_payment_revoke_response
16
+ RESPONSE_ENTITY_NAME = :master_payment_status_response
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessRecurringPayment < BaseSignedRequest
13
+ OPERATION_NAME = :process_recurring_payment
14
+ REQUEST_NAME = :recurring_payment_request
15
+ RESPONSE_NAME = :process_recurring_payment_response
16
+ RESPONSE_ENTITY_NAME = :recurring_payment_response
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessRefundPayment < BaseSignedRequest
13
+ OPERATION_NAME = :process_refund
14
+ REQUEST_NAME = :refund_request
15
+ RESPONSE_NAME = :process_refund_response
16
+ RESPONSE_ENTITY_NAME = :refund_request_response
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ ##
2
+ # Service object creates fast payment without need of leaving user from Wilio web / app.
3
+ # It uses VERIFIED credit card token to skip filling card again and 3D secure step.
4
+ #
5
+ # @param [Hash] attributes for GP Webpay
6
+ #
7
+ # @return [GpwebpayWsResponse] response value object
8
+
9
+ module GpWebpay
10
+ module Ws
11
+ module Services
12
+ class ProcessTokenPayment < BaseSignedRequest
13
+ OPERATION_NAME = :process_token_payment
14
+ REQUEST_NAME = :token_payment_request
15
+ RESPONSE_NAME = :process_token_payment_response
16
+ RESPONSE_ENTITY_NAME = :token_payment_response
17
+ SERVICE_EXCEPTION = :payment_service_exception
18
+
19
+ def initialize(attributes)
20
+ super
21
+ @attributes = attributes.except(:return_url)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end