omnipay 0.0.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe9720764c2301a4ac9f4093f7a007ae02a30218
4
- data.tar.gz: 767eb86e44f1c07be4cece815b0b17ccea205b57
3
+ metadata.gz: bd4376a27e44aa8518b5ffa2ac3d68b10b2bcc10
4
+ data.tar.gz: 2ce839a8fb9322596f5b99c3bc9de877c9794583
5
5
  SHA512:
6
- metadata.gz: d31dd12edd544e6a171e074d6094d170b868e464e513967955c6ef001902bf943886e086ab0e00a42eebbbd7e9481d76a8676368b3539fb106159dc184c8c90b
7
- data.tar.gz: ab2da0e7a7505776b020555ad979d555a81f81cde685ce015653398b84ca95f533240cd6444688fc46aaca10e4ede0f79def320f91e9b69be3cf5a6af9ab471e
6
+ metadata.gz: 0ebf71355c1f7bece7ee9b172a64d0d3266b93b8e6d2d99099d0a06849ed212b26e7795bd34a2c583635f57978fa4125f85e4dc55b74e796cc54605936c25667
7
+ data.tar.gz: 27a788697beb58f2ab9243cbb1ff5f6a05298c9d1e78d19940be08495364ccb174d02bf01f6659ae7642a5e0bc65c59e01dfef57459e2e900c32ea4159f453b5
@@ -1,14 +1,11 @@
1
- require 'singleton'
2
-
3
1
  # The root Omnipay module. Used for defining its global configuration
4
2
  module Omnipay
5
3
 
6
4
  autoload :Gateway, 'omnipay/gateway'
7
- autoload :Adapter, 'omnipay/adapter'
8
- autoload :RequestPhase, 'omnipay/request_phase'
9
- autoload :CallbackPhase, 'omnipay/callback_phase'
10
5
  autoload :AutosubmitForm, 'omnipay/autosubmit_form'
11
- autoload :Signer, 'omnipay/signer'
6
+ autoload :Configuration, 'omnipay/configuration'
7
+ autoload :Gateways, 'omnipay/gateways'
8
+ autoload :Middleware, 'omnipay/middleware'
12
9
 
13
10
  # Error code for an untreatable response
14
11
  INVALID_RESPONSE = :invalid_response
@@ -23,12 +20,19 @@ module Omnipay
23
20
  WRONG_SIGNATURE = :wrong_signature
24
21
 
25
22
 
26
- # The global Omnipay configuration singleton
27
- class Configuration
28
- include Singleton
29
- attr_accessor :secret_token
23
+
24
+ # Accessors to the configured gateways
25
+ def self.gateways
26
+ @gateways ||= Omnipay::Gateways.new
30
27
  end
31
28
 
29
+
30
+ # Syntaxic sugar for adding a new gateway
31
+ def self.use_gateway(opts = {}, &block)
32
+ self.gateways.push(opts, &block)
33
+ end
34
+
35
+
32
36
  # Accessor to the global configuration
33
37
  # @return [Configuration]
34
38
  def self.configuration
@@ -46,4 +50,7 @@ module Omnipay
46
50
  yield configuration
47
51
  end
48
52
 
49
- end
53
+ end
54
+
55
+ # Rails bindings
56
+ require 'omnipay/railtie' if defined?(Rails)
@@ -15,20 +15,19 @@ module Omnipay
15
15
 
16
16
  attr_reader :client
17
17
 
18
- def initialize(callback_url, config = {})
18
+ def initialize(config = {})
19
19
 
20
20
  raise ArgumentError.new("Missing client_id, client_passphrase, or wallet_id parameter") unless [config[:client_id], config[:client_passphrase], config[:wallet_id]].all?
21
21
 
22
22
  @client = Client.new(config[:client_id], config[:client_passphrase], :sandbox => !!config[:sandbox])
23
- @callback_url = callback_url
24
23
  @wallet_id = config[:wallet_id]
25
24
 
26
25
  end
27
26
 
28
27
 
29
- def request_phase(amount, params = {})
28
+ def request_phase(amount, callback_url, params = {})
30
29
 
31
- transaction_id, redirect_url = create_web_payin(amount, params)
30
+ transaction_id, redirect_url = create_web_payin(amount, callback_url, params)
32
31
 
33
32
  # Generate the path and query parameters from the returned redirect_url string
34
33
  uri = URI(redirect_url)
@@ -94,7 +93,7 @@ module Omnipay
94
93
 
95
94
  private
96
95
 
97
- def create_web_payin(amount, params)
96
+ def create_web_payin(amount, callback_url, params)
98
97
 
99
98
  # Create a user
100
99
  random_key = "#{Time.now.to_i}-#{(0...3).map { ('a'..'z').to_a[rand(26)] }.join}"
@@ -121,7 +120,7 @@ module Omnipay
121
120
  :Amount => 0
122
121
  },
123
122
  :CreditedWalletId => @wallet_id,
124
- :ReturnURL => @callback_url,
123
+ :ReturnURL => callback_url,
125
124
  :Culture => (params[:locale] || 'fr').upcase,
126
125
  :CardType => 'CB_VISA_MASTERCARD',
127
126
  :SecureMode => 'FORCE'
@@ -27,9 +27,7 @@ module Omnipay
27
27
  :production => 'https://secure.oneclicpay.com:60000'
28
28
  }
29
29
 
30
- def initialize(callback_url, config)
31
- @callback_url = callback_url
32
-
30
+ def initialize(config = {})
33
31
  @tpe_id = config[:tpe_id]
34
32
  @secret_key = config[:secret_key]
35
33
  @is_sandbox = config[:sandbox]
@@ -38,7 +36,7 @@ module Omnipay
38
36
  end
39
37
 
40
38
 
41
- def request_phase(amount, params={})
39
+ def request_phase(amount, callback_url, params={})
42
40
  product_name = params[:title] || ''
43
41
  transaction_id = params[:transaction_id] || random_transaction_id
44
42
  locale = params[:locale] || 'fr'
@@ -46,7 +44,7 @@ module Omnipay
46
44
  [
47
45
  HTTP_METHOD,
48
46
  redirect_url,
49
- redirect_params_for(amount, product_name, transaction_id, locale),
47
+ redirect_params_for(amount, product_name, transaction_id, locale, callback_url),
50
48
  transaction_id
51
49
  ]
52
50
  end
@@ -83,7 +81,7 @@ module Omnipay
83
81
 
84
82
  private
85
83
 
86
- def redirect_params_for(amount, product_name, transaction_id, locale)
84
+ def redirect_params_for(amount, product_name, transaction_id, locale, callback_url)
87
85
  {
88
86
  :montant => (amount.to_f/100).to_s,
89
87
  :idTPE => @tpe_id,
@@ -91,8 +89,8 @@ module Omnipay
91
89
  :devise => 'EUR',
92
90
  :lang => locale,
93
91
  :nom_produit => product_name,
94
- :urlRetourOK => @callback_url,
95
- :urlRetourNOK => @callback_url
92
+ :urlRetourOK => callback_url,
93
+ :urlRetourNOK => callback_url
96
94
  }.tap{|params|
97
95
  params[:sec] = signature(params)
98
96
  }
@@ -107,9 +105,7 @@ module Omnipay
107
105
  end
108
106
 
109
107
  def signature(params)
110
- # Params values sorted by key name
111
- values = params.sort_by{|k,v|k.to_s}.map(&:last)
112
- to_sign = (values + [@secret_key]).join('|')
108
+ to_sign = (params.values + [@secret_key]).join('|')
113
109
  Digest::SHA512.hexdigest(Base64.encode64(to_sign).gsub(/\n/, ''))
114
110
  end
115
111
 
@@ -23,9 +23,7 @@ module Omnipay
23
23
  # * *:api_key* [String] (mandatory) : the API key given for your fictive gateway's account
24
24
  # * *:sandbox* [Boolean] (optional) : whether to use a sandboxed payment page, or a real one. Defaults to true
25
25
  # @return [SampleAdapter]
26
- def initialize(callback_url, config = {})
27
- @callback_url = callback_url
28
-
26
+ def initialize(config = {})
29
27
  @api_key = config[:api_key]
30
28
  raise ArgumentError.new("Missing api_key") unless @api_key
31
29
 
@@ -46,11 +44,11 @@ module Omnipay
46
44
  # * +[Hash]+ the GET or POST parameters to send to the payment page
47
45
  # * +[String]+ the unique transaction_id given by the payment provider for the upcoming payment. Has to be accessible in the callback phase.
48
46
 
49
- def request_phase(amount, params={})
47
+ def request_phase(amount, calback_url, params={})
50
48
  amount_in_dollar = amount * 1.0 / 100
51
49
  locale = params[:locale] || 'en'
52
50
 
53
- transaction = build_new_transaction(amount_in_dollars, locale)
51
+ transaction = build_new_transaction(amount_in_dollars, callback_url, locale)
54
52
 
55
53
  uri = URI(transaction.payment_url)
56
54
 
@@ -0,0 +1,15 @@
1
+ require 'singleton'
2
+
3
+ module Omnipay
4
+
5
+ # The global Omnipay configuration singleton
6
+ class Configuration
7
+ include Singleton
8
+ attr_accessor :base_path
9
+
10
+ def initialize
11
+ @base_path = "/pay"
12
+ end
13
+ end
14
+
15
+ end
@@ -1,102 +1,55 @@
1
- require 'rack'
2
-
3
1
  module Omnipay
4
2
 
5
- # This is the actual Rack middleware
6
- #
7
- # It is associated with an adapter instance, and
8
- # responsible for monitoring the incoming request
9
- # and - depending on their path - forwarding them
10
- # for processing to a RequestPhase or CallbackPhase
11
- # instance for processing
3
+ # Instance of a gateway connection. Has an uid, and encapsulates an adapter strategy
12
4
  class Gateway
13
5
 
14
- BASE_PATH = '/pay'
15
-
16
- # @param app [Rack application] : The rack app it should forward to if the request doens't match a monitored path
17
- #
18
- # @param options [Hash] : must contains the following configuration options
19
- # * :uid : the subpath to monitor
20
- # * :adapter : the adapter class to use
21
- # * :config : the config hash which will be passed at the adapter for initialization
22
- #
23
- # The gateway may be initialized with a block returning a hash instead of a hash. In this case, the
24
- # block's only argument is the uid, and the returned hash must contain the adapter class and its configuration
6
+ attr_reader :uid, :adapter_class, :config, :adapter
25
7
 
26
- def initialize(app, options={}, &block)
27
- @app = app
8
+ def initialize(opts = {})
9
+ @uid = opts[:uid]
10
+ @adapter_class = opts[:adapter]
11
+ @config = opts[:config] || {}
28
12
 
29
- @adapter_options = options
30
- @adapter_config_block = block
13
+ raise ArgumentError.new("missing parameter :uid") unless @uid
14
+ raise ArgumentError.new("missing parameter :adapter") unless @adapter_class
31
15
 
32
- # Refreshed at each request
33
- @uid = nil
34
- @request = nil
16
+ @adapter = @adapter_class.new(@config)
35
17
  end
36
18
 
37
- # The standard rack middleware call. Will be processed by an instance of RequestPhase or CallbackPhase if the
38
- # path matches the adapter's uid. Will forward to the app otherwise
39
- def call(env)
40
19
 
41
- # Get the current request
42
- @request = Rack::Request.new(env)
20
+ # The Rack::Response corresponding to the redirection to the payment page
21
+ def payment_redirection(opts = {})
22
+ host = opts.delete :host
23
+ amount = opts.delete :amount
43
24
 
44
- # Check if the path is good, and extract the uid
45
- @uid = extract_uid_from_path(@request.path)
46
- return @app.call(env) unless @uid
25
+ raise ArgumentError.new('Missing parameter :host') unless host
26
+ raise ArgumentError.new('Missing parameter :amount') unless amount
47
27
 
48
- # Get the adapter config for this uid (to handle dynamic configuration)
49
- adapter = Adapter.new(@uid, callback_url, @adapter_options, @adapter_config_block)
50
- return @app.call(env) unless adapter.valid?
28
+ callback_url = "#{host}#{Omnipay.configuration.base_path}/#{uid}/callback"
51
29
 
52
- # Handle the request phase
53
- if request_phase?
54
- return RequestPhase.new(@request, adapter).response
55
- end
30
+ method, url, params = @adapter.request_phase(amount, callback_url, opts)
56
31
 
57
- # Handle the callback phase
58
- if callback_phase?
59
- CallbackPhase.new(@request, adapter).update_env!
60
- end
32
+ if method == 'GET'
33
+ redirect_url = url + '?' + Rack::Utils.build_query(params)
34
+ Rack::Response.new.tap{|response| response.redirect(redirect_url)}
61
35
 
62
- # Forward to the app
63
- @app.call(env)
36
+ elsif method == 'POST'
37
+ form = AutosubmitForm.new(url, params)
38
+ Rack::Response.new([form.html], 200, {'Content-Type' => 'text/html;charset=utf-8'})
64
39
 
65
- end
66
-
67
-
68
- private
69
-
70
- # Check if the current request matches the request or callback phase
71
- def request_phase?
72
- @request.path == "#{BASE_PATH}/#{@uid}" && @request.request_method == 'GET'
73
- end
40
+ else
41
+ raise ArgumentError.new('the returned method is neither GET nor POST')
74
42
 
75
- def callback_phase?
76
- @request.path == "#{BASE_PATH}/#{@uid}/callback"
77
- end
78
-
79
-
80
- # Extract the uid from the path
81
- # If uid already defined, check if it matches
82
- # "/pay/foobar/callback" => "foobar"
83
- def extract_uid_from_path(path)
84
- if path.start_with? BASE_PATH
85
- uid = path.gsub(/^#{BASE_PATH}/, '').split('/')[1]
86
- end
87
-
88
- if !@adapter_options.empty?
89
- uid = nil unless uid == @adapter_options[:uid]
90
43
  end
91
-
92
- uid
93
44
  end
94
45
 
95
46
 
96
- # The callback url for a uid in the current host
97
- def callback_url
98
- "#{@request.base_url}#{BASE_PATH}/#{@uid}/callback"
47
+ # The response hash
48
+ def formatted_response_for(params)
49
+ @adapter.callback_hash(params).merge(:raw => params)
99
50
  end
100
51
 
52
+
101
53
  end
102
- end
54
+
55
+ end
@@ -0,0 +1,46 @@
1
+ module Omnipay
2
+
3
+ # Structure responsible for storing and accessing the application's configured gateways
4
+ class Gateways
5
+
6
+
7
+ def initialize
8
+ @gateways = {}
9
+ @dynamic_configs = [] # Collection of procs which given a uid may or may not return a gateway config hash
10
+ end
11
+
12
+
13
+ # Add a new gateway, static or dynamic
14
+ def push(opts = {}, &block)
15
+ if block_given?
16
+ @dynamic_configs << Proc.new(&block)
17
+
18
+ elsif opts[:uid] && opts[:adapter]
19
+ @gateways[opts[:uid]] = Gateway.new(opts)
20
+
21
+ else
22
+ raise ArgumentError.new('An omnipay gateway must be given an uid and an adapter, or a dynamic block')
23
+ end
24
+ end
25
+
26
+
27
+ # Find and/or instanciate a gateway for the given uid
28
+ def find(uid)
29
+ gateway = @gateways[uid]
30
+ return gateway if gateway
31
+
32
+ # Tries to find a dynamic gateway config for this uid
33
+ config = @dynamic_configs.find do |dynamic_config|
34
+ gateway_config = dynamic_config.call(uid)
35
+ if gateway_config
36
+ return Gateway.new(gateway_config.merge(:uid => uid))
37
+ end
38
+ end
39
+
40
+ # Nothing found : return nil
41
+ nil
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,68 @@
1
+ require 'rack'
2
+
3
+ module Omnipay
4
+
5
+ # This is the actual Rack middleware
6
+ # It is responsible for formatting callback responses
7
+ # via a CallbackPhase instance
8
+ class Middleware
9
+
10
+ # @param app [Rack application] : The rack app it should forward to if the request doens't match a monitored path
11
+ #
12
+ # The gateway may be initialized with a block returning a hash instead of a hash. In this case, the
13
+ # block's only argument is the uid, and the returned hash must contain the adapter class and its configuration
14
+
15
+ def initialize(app)
16
+ @app = app
17
+ end
18
+
19
+ # The standard rack middleware call. Will be processed by an instance of RequestPhase or CallbackPhase if the
20
+ # path matches the adapter's uid. Will forward to the app otherwise
21
+ def call(env)
22
+
23
+ # Get the current request
24
+ request = Rack::Request.new(env)
25
+
26
+ # Check if the path is good, and extract the uid
27
+ uid = extract_uid_from_path(request.path)
28
+ return @app.call(env) unless uid
29
+
30
+ # Get the gateway for this uid
31
+ gateway = Omnipay.gateways.find(uid)
32
+ return @app.call(env) unless gateway
33
+
34
+ # Handle the callback phase
35
+ if callback_phase?(request, uid)
36
+ # Symbolize the params keys
37
+ params = Hash[request.params.map{|k,v|[k.to_sym,v]}]
38
+
39
+ # Set the formatted response
40
+ request.env['omnipay.response'] = gateway.formatted_response_for(params)
41
+
42
+ # Force a get request
43
+ request.env['REQUEST_METHOD'] = 'GET'
44
+ end
45
+
46
+ # Forward to the app
47
+ @app.call(env)
48
+
49
+ end
50
+
51
+
52
+ private
53
+
54
+ def callback_phase?(request, uid)
55
+ request.path == "#{Omnipay.configuration.base_path}/#{uid}/callback"
56
+ end
57
+
58
+
59
+ # Extract the uid from the path
60
+ # "/pay/foobar/callback" => "foobar"
61
+ def extract_uid_from_path(path)
62
+ if path.start_with? Omnipay.configuration.base_path
63
+ uid = path.gsub(/^#{Omnipay.configuration.base_path}/, '').split('/')[1]
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Omnipay
2
+
3
+ module ActionController
4
+ module Helpers
5
+
6
+ def redirect_to_payment(uid, opts = {})
7
+ app_host = "#{request.scheme}://#{request.host_with_port}"
8
+ gateway = Omnipay.gateways.find(uid)
9
+ if gateway
10
+ rack_response = gateway.payment_redirection(opts.merge(:host => app_host))
11
+
12
+ self.response_body = rack_response.body
13
+ self.status = rack_response.status
14
+ self.response.headers = rack_response.headers
15
+
16
+ return true
17
+ else
18
+ raise ArgumentError.new("Omnipay gateway '#{uid}' not found")
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+
26
+ class Railtie < Rails::Railtie
27
+
28
+ initializer "omnipay.configure_rails_initialization" do
29
+
30
+ ActiveSupport.on_load :action_controller do
31
+ include Omnipay::ActionController::Helpers
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module Omnipay
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnipay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ClicRDV
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-17 00:00:00.000000000 Z
11
+ date: 2014-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -47,16 +47,16 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - lib/omnipay.rb
50
- - lib/omnipay/adapter.rb
51
50
  - lib/omnipay/adapters/mangopay.rb
52
51
  - lib/omnipay/adapters/mangopay/client.rb
53
52
  - lib/omnipay/adapters/oneclicpay.rb
54
53
  - lib/omnipay/adapters/sample_adapter.rb
55
54
  - lib/omnipay/autosubmit_form.rb
56
- - lib/omnipay/callback_phase.rb
55
+ - lib/omnipay/configuration.rb
57
56
  - lib/omnipay/gateway.rb
58
- - lib/omnipay/request_phase.rb
59
- - lib/omnipay/signer.rb
57
+ - lib/omnipay/gateways.rb
58
+ - lib/omnipay/middleware.rb
59
+ - lib/omnipay/railtie.rb
60
60
  - lib/omnipay/version.rb
61
61
  homepage: https://github.com/clicrdv/omnipay
62
62
  licenses: []
@@ -1,76 +0,0 @@
1
- module Omnipay
2
-
3
- # Wrapper around an actual adapter implementation. Responsible mainly for handling its initialization with
4
- # a static or dynamic (block) configuration
5
- class Adapter
6
-
7
- # The adapter's unique identifier. Will be passed to the dynamic configuration block.
8
- attr_reader :uid
9
-
10
-
11
- # @param uid [String] The adapter's unique identifier
12
- # @param callback_url [String] The absolute URL to be used for the user redirection after the payment
13
- # @param config [Hash] A static adapter configuration
14
- # @param dynamic_config [String => Hash] A dynamic config block. Takes the uid as an input and returns the adapter's configuration
15
- # @return [Adapter]
16
- def initialize(uid, callback_url, config, dynamic_config)
17
- @uid = uid
18
- @callback_url = callback_url
19
- @config = config
20
- @dynamic_config = dynamic_config
21
-
22
- @strategy = build_strategy
23
- end
24
-
25
- # Is there a valid adapter configuration for the given parameters. Checks notably if the given uid is valid in case of a dyncamic configuration.
26
- # @return [Boolean]
27
- def valid?
28
- @strategy != nil
29
- end
30
-
31
- # Proxy to the adapter's implementation's request_phase method
32
- # @param amount [Integer] The amount to pay, in **cents**
33
- # @param opts [Hash] The custom GET parameters sent to the omnipay payment url
34
- # @return [Array] The array containing the redirection method (GET or POST), its url, its get or post params, and the unique associated transaction id
35
- def request_phase(amount, opts = {})
36
- @strategy.request_phase(amount, opts)
37
- end
38
-
39
- # Proxy to the adapter's implementation's callback_phase method
40
- # @param params [Hash] The GET/POST params sent by the payment gateway to the callback url
41
- # @return [Hash] The omnipay response environment. Contains the response success status, the amount payed, the error message if any, ...
42
- def callback_hash(params)
43
- @strategy.callback_hash(params)
44
- end
45
-
46
-
47
- private
48
-
49
- def build_strategy
50
- return nil unless strategy_class
51
-
52
- strategy_class.new(@callback_url, strategy_config)
53
- end
54
-
55
- def strategy_class
56
- params[:adapter]
57
- end
58
-
59
- def strategy_config
60
- params[:config] || {}
61
- end
62
-
63
- def params
64
- return @params if @params
65
-
66
- if @dynamic_config
67
- @params = @dynamic_config.call(@uid) || {}
68
- else
69
- @params = @config || {}
70
- end
71
-
72
- @params ||= {}
73
- end
74
-
75
- end
76
- end
@@ -1,73 +0,0 @@
1
- module Omnipay
2
-
3
- # Class responsible for the processing in a gateway's callback phase. It updates the request's environemnt with the formatted Omnipay response given by the apdater's implementation.
4
- class CallbackPhase
5
-
6
- # @param request [Rack::Request] The request corresponding to the redirection from the payment gateway to the application.
7
- # @param adapter [Adapter] The adapter instance of the gateway having catched this request
8
- # @return [CallbackPhase]
9
- def initialize(request, adapter)
10
- @request = request
11
- @adapter = adapter
12
- end
13
-
14
-
15
- # Actually set the request's environment variable 'omnipay.response' with the formatted summary of the payment transaction.
16
- # @note Should only be called once because of the signatures lifetime
17
- def update_env!
18
-
19
- # The request params, keys symbolized
20
- params = Hash[@request.params.map{|k,v|[k.to_sym,v]}]
21
-
22
- # Get the callback hash
23
- callback_hash = @adapter.callback_hash(params)
24
-
25
- # Check the signature
26
- if callback_hash[:success] && !valid_signature?(callback_hash)
27
- callback_hash = {
28
- :success => false,
29
- :error => Omnipay::WRONG_SIGNATURE,
30
- :error_message => "Signatures do not match."
31
- }
32
- end
33
-
34
- # If not successful response, add informations to the error message
35
- if !callback_hash[:success]
36
- callback_hash[:error_message] = (callback_hash[:error_message] || callback_hash[:error].to_s) +
37
- "\nAdapter : #{@adapter.uid}" +
38
- "\nContext : #{context.inspect}" +
39
- "\nStored signature : #{stored_signature}" +
40
- "\nRequest : #{@request.inspect}"
41
- end
42
-
43
- # Store the response in the environment
44
- @request.env['omnipay.response'] = callback_hash.merge(:raw => params, :context => context)
45
-
46
- # Force GET request
47
- @request.env['REQUEST_METHOD'] = 'GET'
48
- end
49
-
50
-
51
- private
52
-
53
- def valid_signature?(callback_hash)
54
- callback_signature = Signer.new(callback_hash[:transaction_id], callback_hash[:amount], context).signature
55
-
56
- callback_signature == stored_signature
57
- end
58
-
59
- def stored_signature
60
- @stored_signature ||= @request.session['omnipay.signature'] && @request.session['omnipay.signature'].delete(@adapter.uid)
61
- end
62
-
63
- def callback_signature
64
- @callback_signatureSigner.new(callback_hash[:transaction_id], callback_hash[:amount], context).signature
65
- end
66
-
67
- def context
68
- @context ||= @request.session['omnipay.context'] && @request.session['omnipay.context'].delete(@adapter.uid)
69
- @context ||= {}
70
- end
71
-
72
- end
73
- end
@@ -1,81 +0,0 @@
1
- module Omnipay
2
-
3
- # Class responsible for formatting the redirection in the request phase
4
- class RequestPhase
5
-
6
- # @param request [Rack::Request] The request corresponding to the redirection from the payment gateway to the application.
7
- # @param adapter [Adapter] The adapter instance of the gateway having catched this request
8
- # @return [RequestPhase]
9
- def initialize(request, adapter)
10
- @request = request
11
- @adapter = adapter
12
- end
13
-
14
- # Returns the rack response for redirecting the user to the payment page. Can be a 302 redirect if a GET redirection, or an AutosubmittedForm for POST redirections
15
- # @return [Rack::Response]
16
- def response
17
- method, url, params, transaction_id = @adapter.request_phase(amount, adapter_params)
18
-
19
- context = store_context!
20
-
21
- signature = Signer.new(transaction_id, amount, context).signature
22
- store_signature!(signature)
23
-
24
- if method == 'GET'
25
- get_redirect_response(url, params)
26
- elsif method == 'POST'
27
- post_redirect_response(url, params)
28
- else
29
- raise TypeError.new('request_phase returned http method must be \'GET\' or \'POST\'')
30
- end
31
- end
32
-
33
-
34
- private
35
-
36
- def amount
37
- @request.params['amount'].tap{ |amount|
38
- raise ArgumentError.new('No amount specified') unless amount
39
- }.to_i
40
- end
41
-
42
- def adapter_params
43
- params = @request.params.dup
44
-
45
- params.delete 'amount'
46
- params.delete 'context'
47
-
48
- # Symbolize the keys
49
- Hash[params.map{|k,v|[k.to_sym,v]}]
50
- end
51
-
52
- def get_redirect_response(url, params)
53
- redirect_url = url + '?' + Rack::Utils.build_query(params)
54
- Rack::Response.new.tap{|response| response.redirect(redirect_url)}
55
- end
56
-
57
- def post_redirect_response(url, params)
58
- form = AutosubmitForm.new(url, params)
59
- Rack::Response.new([form.html], 200, {'Content-Type' => 'text/html;charset=utf-8'})
60
- end
61
-
62
- # Store the request's context in session
63
- def store_context!
64
- context = @request.params.delete('context')
65
-
66
- if context
67
- @request.session['omnipay.context'] ||= {}
68
- @request.session['omnipay.context'][@adapter.uid] = context
69
- end
70
-
71
- return context
72
- end
73
-
74
- # Store the requests signature in the session
75
- def store_signature!(signature)
76
- @request.session['omnipay.signature'] ||= {}
77
- @request.session['omnipay.signature'][@adapter.uid] = signature
78
- end
79
-
80
- end
81
- end
@@ -1,37 +0,0 @@
1
- require 'openssl'
2
-
3
- module Omnipay
4
-
5
- # Class responsible for computing a signature of a payment.
6
- class Signer
7
-
8
- # @param transaction_id [String] the transactions's unique identifier
9
- # @param amount [Integer] the amount **in cents** of the transaction
10
- # @param context [Hash] the transaction's context hash
11
- # @return [Signer]
12
- def initialize(transaction_id, amount, context)
13
- @transaction_id = transaction_id
14
- @amount = amount
15
- @context = context || {}
16
- end
17
-
18
- # Actually computes the signature
19
- # @return [String] The computed signature
20
- def signature
21
- to_sign = "#{secret_token}:#{@transaction_id}:#{@amount}:#{self.class.hash_to_string @context}"
22
- CGI.escape(Base64.encode64(OpenSSL::HMAC.digest('sha1', secret_token, to_sign)))
23
- end
24
-
25
- private
26
-
27
- def secret_token
28
- Omnipay.configuration.secret_token
29
- end
30
-
31
- def self.hash_to_string(hash)
32
- # key/values appended by alphabetical key order
33
- hash.sort_by{|k,_|k}.flatten.join('')
34
- end
35
-
36
- end
37
- end