omnipay 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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