forked from Shopify/hosted-payment-sim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.rb
141 lines (115 loc) · 3.55 KB
/
app.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
require 'httparty'
require 'json'
require 'addressable/uri'
require 'byebug' if development?
class OffsiteGatewaySim < Sinatra::Base
enable :logging
before do
logger.level = Logger::DEBUG
end
def initialize(base_path: '')
@base_path = base_path
@key = 'iU44RWxeik'
super
end
def fields
@fields ||= if request.content_type == 'application/json'
JSON.load(request.body.read)
else
request.params.select { |k, v| k.start_with?('x_') }
end
end
def request_fields
YAML.load_file('request_fields.yml')
end
def response_fields
YAML.load_file('response_fields.yml')
end
def sign(fields, key=@key)
OpenSSL::HMAC.hexdigest("SHA256", key, fields.sort.join)
end
def signature_valid?
provided_signature = fields['x_signature']
expected_signature = sign(fields.reject{|k,_| k == 'x_signature'})
provided_signature && provided_signature.casecmp(expected_signature) == 0
end
get '/' do
erb :get, :locals => { key: @key }
end
post '/' do
erb :post, :locals => { signature_ok: signature_valid? }
end
post '/incontext' do
erb :incontext, :locals => { signature_ok: signature_valid? }
end
get '/calculator' do
erb :calculator, :locals => {
request_fields: request_fields,
response_fields: response_fields,
signature: sign(fields.delete_if { |_, v| v.empty? }, params['secret_key'] || @key)
}
end
post %r{/(capture|refund|void)} do |action|
content_type :json
logger.debug "XXXX: LOGGING REQUEST"
logger.debug fields
if signature_valid?
[200, {}, fields.merge(x_result: 'pending',
x_gateway_reference: SecureRandom.hex,
x_timestamp: Time.now.utc.iso8601).to_json]
else
[401, {}, { x_status: 'failed', x_error_message: 'Invalid signature' }.to_json]
end
end
get '/notification' do
erb :notification
end
post '/execute/?:action?' do |action|
ts = Time.now.utc.iso8601
payload = {
'x_account_id' => fields['x_account_id'],
'x_reference' => fields['x_reference'],
'x_currency' => fields['x_currency'],
'x_test' => fields['x_test'],
'x_amount' => fields['x_amount'],
'x_result' => action,
'x_gateway_reference' => SecureRandom.hex,
'x_timestamp' => ts
}
%w(x_transaction_type x_message x_result).each do |field|
payload[field] = fields[field] if fields[field]
end
logger.debug "XXXX: LOGGING REQUEST"
logger.debug fields
if action == "failed"
payload['x_message'] = "This is a custom error message."
end
payload['x_signature'] = sign(payload)
result = {timestamp: ts}
redirect_url = if fields['x_url_complete']
uri = Addressable::URI.parse(fields['x_url_complete'])
uri.query_values = payload
uri
end
logger.debug "XXXX: LOGGING PAYLOAD"
logger.debug payload
if request.params['fire_callback'] == 'true'
callback_url = fields['x_url_callback']
response = HTTParty.post(callback_url, body: payload, logger: logger, log_level: :debug, log_format: :curl)
logger.debug "XXXX: LOGGING CALLBACK RESPONSE"
logger.debug response
if response.code == 200
result[:redirect] = redirect_url if redirect_url
else
result[:error] = response
end
else
result[:redirect] = redirect_url if redirect_url
end
result.to_json
end
run! if app_file == $0
end