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 +4 -4
- data/lib/omnipay.rb +18 -11
- data/lib/omnipay/adapters/mangopay.rb +5 -6
- data/lib/omnipay/adapters/oneclicpay.rb +7 -11
- data/lib/omnipay/adapters/sample_adapter.rb +3 -5
- data/lib/omnipay/configuration.rb +15 -0
- data/lib/omnipay/gateway.rb +31 -78
- data/lib/omnipay/gateways.rb +46 -0
- data/lib/omnipay/middleware.rb +68 -0
- data/lib/omnipay/railtie.rb +37 -0
- data/lib/omnipay/version.rb +1 -1
- metadata +6 -6
- data/lib/omnipay/adapter.rb +0 -76
- data/lib/omnipay/callback_phase.rb +0 -73
- data/lib/omnipay/request_phase.rb +0 -81
- data/lib/omnipay/signer.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd4376a27e44aa8518b5ffa2ac3d68b10b2bcc10
|
4
|
+
data.tar.gz: 2ce839a8fb9322596f5b99c3bc9de877c9794583
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ebf71355c1f7bece7ee9b172a64d0d3266b93b8e6d2d99099d0a06849ed212b26e7795bd34a2c583635f57978fa4125f85e4dc55b74e796cc54605936c25667
|
7
|
+
data.tar.gz: 27a788697beb58f2ab9243cbb1ff5f6a05298c9d1e78d19940be08495364ccb174d02bf01f6659ae7642a5e0bc65c59e01dfef57459e2e900c32ea4159f453b5
|
data/lib/omnipay.rb
CHANGED
@@ -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 :
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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(
|
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 =>
|
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(
|
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 =>
|
95
|
-
:urlRetourNOK =>
|
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
|
-
|
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(
|
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
|
|
data/lib/omnipay/gateway.rb
CHANGED
@@ -1,102 +1,55 @@
|
|
1
|
-
require 'rack'
|
2
|
-
|
3
1
|
module Omnipay
|
4
2
|
|
5
|
-
#
|
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
|
-
|
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(
|
27
|
-
@
|
8
|
+
def initialize(opts = {})
|
9
|
+
@uid = opts[:uid]
|
10
|
+
@adapter_class = opts[:adapter]
|
11
|
+
@config = opts[:config] || {}
|
28
12
|
|
29
|
-
|
30
|
-
|
13
|
+
raise ArgumentError.new("missing parameter :uid") unless @uid
|
14
|
+
raise ArgumentError.new("missing parameter :adapter") unless @adapter_class
|
31
15
|
|
32
|
-
|
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
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
63
|
-
|
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
|
-
|
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
|
97
|
-
def
|
98
|
-
|
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
|
-
|
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
|
data/lib/omnipay/version.rb
CHANGED
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
|
+
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-
|
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/
|
55
|
+
- lib/omnipay/configuration.rb
|
57
56
|
- lib/omnipay/gateway.rb
|
58
|
-
- lib/omnipay/
|
59
|
-
- lib/omnipay/
|
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: []
|
data/lib/omnipay/adapter.rb
DELETED
@@ -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
|
data/lib/omnipay/signer.rb
DELETED
@@ -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
|