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 +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
|