straight-server 0.2.3 → 1.0.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/.travis.yml +2 -2
- data/Gemfile +21 -16
- data/Gemfile.lock +44 -30
- data/Gemfile.travis +15 -16
- data/README.md +66 -47
- data/VERSION +1 -1
- data/db/migrations/011_add_callback_data_to_orders.rb +1 -1
- data/db/migrations/012_add_address_provider.rb +11 -0
- data/db/migrations/013_add_address_derivation_scheme.rb +11 -0
- data/db/migrations/014_pubkey_null_address_provider_not_null.rb +8 -0
- data/db/migrations/015_add_amount_paid_to_orders.rb +11 -0
- data/db/migrations/016_add_new_params_to_orders.rb +13 -0
- data/db/migrations/017_add_test_mode_to_gateways.rb +11 -0
- data/db/migrations/018_add_test_keychain_id_to_gateways.rb +11 -0
- data/db/migrations/019_add_test_pubkey_to_gateways.rb +11 -0
- data/db/migrations/020_add_test_mode_to_orders.rb +11 -0
- data/db/schema.rb +11 -1
- data/lib/straight-server.rb +11 -9
- data/lib/straight-server/config.rb +28 -18
- data/lib/straight-server/gateway.rb +167 -87
- data/lib/straight-server/initializer.rb +13 -7
- data/lib/straight-server/order.rb +39 -17
- data/lib/straight-server/orders_controller.rb +71 -21
- data/lib/straight-server/random_string.rb +3 -13
- data/lib/straight-server/server.rb +3 -4
- data/lib/straight-server/signature_validator.rb +69 -0
- data/lib/straight-server/thread.rb +19 -4
- data/lib/straight-server/throttler.rb +7 -13
- data/lib/tasks/db.rake +1 -1
- data/spec/.straight/config.yml +8 -3
- data/spec/.straight/default_test_last_keychain_id +1 -0
- data/spec/factories.rb +2 -1
- data/spec/lib/gateway_spec.rb +222 -94
- data/spec/lib/initializer_spec.rb +1 -1
- data/spec/lib/order_spec.rb +26 -7
- data/spec/lib/orders_controller_spec.rb +65 -6
- data/spec/lib/signature_validator_spec.rb +72 -0
- data/spec/lib/thread_spec.rb +16 -0
- data/spec/lib/throttle_spec.rb +2 -2
- data/spec/spec_helper.rb +17 -22
- data/straight-server.gemspec +31 -12
- data/templates/config.yml +19 -10
- metadata +52 -11
@@ -41,12 +41,12 @@ module StraightServer
|
|
41
41
|
create_logger
|
42
42
|
connect_to_db
|
43
43
|
run_migrations if migrations_pending?
|
44
|
-
setup_redis_connection
|
44
|
+
setup_redis_connection
|
45
45
|
initialize_routes
|
46
46
|
end
|
47
47
|
|
48
48
|
def add_route(path, &block)
|
49
|
-
@routes[path] = block
|
49
|
+
@routes[path] = block
|
50
50
|
end
|
51
51
|
|
52
52
|
def create_config_files
|
@@ -116,6 +116,7 @@ module StraightServer
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def create_logger
|
119
|
+
return unless Config.logmaster
|
119
120
|
require_relative 'logger'
|
120
121
|
StraightServer.logger = StraightServer::Logger.new(
|
121
122
|
log_level: ::Logger.const_get(Config.logmaster['log_level'].upcase),
|
@@ -128,7 +129,11 @@ module StraightServer
|
|
128
129
|
|
129
130
|
def initialize_routes
|
130
131
|
@routes = {}
|
131
|
-
add_route
|
132
|
+
add_route %r{\A/gateways/.+?/orders(/.+)?\Z} do |env|
|
133
|
+
controller = OrdersController.new(env)
|
134
|
+
controller.response
|
135
|
+
end
|
136
|
+
add_route %r{\A/gateways/.+?/last_keychain_id\Z} do |env|
|
132
137
|
controller = OrdersController.new(env)
|
133
138
|
controller.response
|
134
139
|
end
|
@@ -168,6 +173,7 @@ module StraightServer
|
|
168
173
|
# an unclean shutdown of the server. Let's check and update the status manually once.
|
169
174
|
if order.time_left_before_expiration < 1
|
170
175
|
StraightServer.logger.info "Order #{order.id} seems to be expired, but status remains #{order.status}. Will check for status update manually."
|
176
|
+
order.gateway.test_mode = true if order.test_mode
|
171
177
|
order.status(reload: true)
|
172
178
|
|
173
179
|
# if we still see no transactions to that address,
|
@@ -187,17 +193,17 @@ module StraightServer
|
|
187
193
|
end
|
188
194
|
|
189
195
|
# Loads redis gem and sets up key prefixes for order counters
|
190
|
-
# for the current straight environment.
|
196
|
+
# for the current straight environment.
|
191
197
|
def setup_redis_connection
|
192
|
-
|
198
|
+
raise "Redis not configured" unless Config.redis
|
193
199
|
Config.redis = Config.redis.keys_to_sym
|
194
|
-
Config.redis[:
|
200
|
+
Config.redis[:prefix] ||= "StraightServer:#{Config.environment}"
|
201
|
+
StraightServer.redis_connection = Redis.new(
|
195
202
|
host: Config.redis[:host],
|
196
203
|
port: Config.redis[:port],
|
197
204
|
db: Config.redis[:db],
|
198
205
|
password: Config.redis[:password]
|
199
206
|
)
|
200
|
-
Config.redis[:prefix] ||= "StraightServer:#{Config.environment}"
|
201
207
|
end
|
202
208
|
|
203
209
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module StraightServer
|
2
|
-
|
2
|
+
|
3
3
|
class Order < Sequel::Model
|
4
4
|
|
5
5
|
include Straight::OrderModule
|
@@ -10,12 +10,12 @@ module StraightServer
|
|
10
10
|
|
11
11
|
# Additional data that can be passed and stored with each order. Not returned with the callback.
|
12
12
|
serialize_attributes :marshal, :data
|
13
|
-
|
13
|
+
|
14
14
|
# data that was provided by the merchan upon order creation and is sent back with the callback
|
15
|
-
serialize_attributes :marshal, :callback_data
|
15
|
+
serialize_attributes :marshal, :callback_data
|
16
16
|
|
17
17
|
# stores the response of the server to which the callback is issued
|
18
|
-
serialize_attributes :marshal, :callback_response
|
18
|
+
serialize_attributes :marshal, :callback_response
|
19
19
|
|
20
20
|
plugin :after_initialize
|
21
21
|
def after_initialize
|
@@ -25,7 +25,7 @@ module StraightServer
|
|
25
25
|
def gateway
|
26
26
|
@gateway ||= Gateway.find_by_id(gateway_id)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def gateway=(g)
|
30
30
|
self.gateway_id = g.id
|
31
31
|
@gateway = g
|
@@ -60,13 +60,30 @@ module StraightServer
|
|
60
60
|
self[:status] = @status
|
61
61
|
end
|
62
62
|
|
63
|
+
def cancelable?
|
64
|
+
status == Straight::Order::STATUSES.fetch(:new)
|
65
|
+
end
|
66
|
+
|
67
|
+
def cancel
|
68
|
+
self.status = Straight::Order::STATUSES.fetch(:canceled)
|
69
|
+
save
|
70
|
+
StraightServer::Thread.interrupt(label: payment_id)
|
71
|
+
end
|
72
|
+
|
63
73
|
def save
|
64
74
|
super # calling Sequel::Model save
|
65
75
|
@status_changed = false
|
66
76
|
end
|
67
77
|
|
68
78
|
def to_h
|
69
|
-
super.merge({
|
79
|
+
super.merge({
|
80
|
+
id: id,
|
81
|
+
payment_id: payment_id,
|
82
|
+
amount_in_btc: amount_in_btc(as: :string),
|
83
|
+
amount_paid_in_btc: amount_in_btc(field: amount_paid,as: :string),
|
84
|
+
keychain_id: keychain_id,
|
85
|
+
last_keychain_id: (self.gateway.test_mode ? self.gateway.test_last_keychain_id : self.gateway.last_keychain_id)
|
86
|
+
})
|
70
87
|
end
|
71
88
|
|
72
89
|
def to_json
|
@@ -75,17 +92,18 @@ module StraightServer
|
|
75
92
|
|
76
93
|
def validate
|
77
94
|
super # calling Sequel::Model validator
|
78
|
-
errors.add(:amount,
|
79
|
-
errors.add(:amount,
|
80
|
-
errors.add(:
|
81
|
-
errors.add(:
|
82
|
-
errors.add(:
|
83
|
-
|
95
|
+
errors.add(:amount, "is not numeric") if !amount.kind_of?(Numeric)
|
96
|
+
errors.add(:amount, "should be more than 0") if amount && amount <= 0
|
97
|
+
errors.add(:amount_paid, "is not numeric") if !amount.kind_of?(Numeric)
|
98
|
+
errors.add(:gateway_id, "is invalid") if !gateway_id.kind_of?(Numeric) || gateway_id <= 0
|
99
|
+
errors.add(:description, "should be shorter than 256 characters") if description.kind_of?(String) && description.length > 255
|
100
|
+
errors.add(:gateway, "is inactive, cannot create order for inactive gateway") if !gateway.active && self.new?
|
101
|
+
validates_unique :id
|
84
102
|
validates_presence [:address, :keychain_id, :gateway_id, :amount]
|
85
103
|
end
|
86
104
|
|
87
105
|
def to_http_params
|
88
|
-
"order_id=#{id}&amount=#{amount}&amount_in_btc=#{amount_in_btc(as: :string)}&status=#{status}&address=#{address}&tid=#{tid}&keychain_id=#{keychain_id}&last_keychain_id=#{@gateway.last_keychain_id}"
|
106
|
+
"order_id=#{id}&amount=#{amount}&amount_in_btc=#{amount_in_btc(as: :string)}&amount_paid_in_btc=#{amount_in_btc(field: amount_paid, as: :string)}&status=#{status}&address=#{address}&tid=#{tid}&keychain_id=#{keychain_id}&last_keychain_id=#{@gateway.last_keychain_id}"
|
89
107
|
end
|
90
108
|
|
91
109
|
def before_create
|
@@ -96,13 +114,13 @@ module StraightServer
|
|
96
114
|
self.data = {} unless self.data
|
97
115
|
self.data[:exchange_rate] = { price: gateway.current_exchange_rate, currency: gateway.default_currency }
|
98
116
|
end
|
99
|
-
|
117
|
+
|
100
118
|
super
|
101
119
|
end
|
102
120
|
|
103
121
|
# Update Gateway's order_counters, incrementing the :new counter.
|
104
122
|
# All other increments/decrements happen in the the Gateway#order_status_changed callback,
|
105
|
-
# but the initial :new increment needs this code because the Gateway#order_status_changed
|
123
|
+
# but the initial :new increment needs this code because the Gateway#order_status_changed
|
106
124
|
# isn't called in this case.
|
107
125
|
def after_create
|
108
126
|
self.gateway.increment_order_counter!(:new) if StraightServer::Config.count_orders
|
@@ -112,15 +130,19 @@ module StraightServer
|
|
112
130
|
# Order#created_at into account now, so that we don't start checking on
|
113
131
|
# an order that is already expired. Or, if it's not expired yet,
|
114
132
|
# we make sure to stop all checks as soon as it expires, but not later.
|
115
|
-
def start_periodic_status_check
|
116
|
-
StraightServer.logger.info "Starting periodic status checks of order #{self.id} (expires in #{duration} seconds)"
|
133
|
+
def start_periodic_status_check
|
117
134
|
if (t = time_left_before_expiration) > 0
|
135
|
+
StraightServer.logger.info "Starting periodic status checks of order #{id} (expires in #{t} seconds)"
|
118
136
|
check_status_on_schedule(duration: t)
|
119
137
|
end
|
120
138
|
self.save if self.status_changed?
|
121
139
|
end
|
122
140
|
|
123
141
|
def check_status_on_schedule(period: 10, iteration_index: 0, duration: 600, time_passed: 0)
|
142
|
+
if StraightServer::Thread.interrupted?(thread: ::Thread.current)
|
143
|
+
StraightServer.logger.info "Checking status of order #{self.id} interrupted"
|
144
|
+
return
|
145
|
+
end
|
124
146
|
StraightServer.logger.info "Checking status of order #{self.id}"
|
125
147
|
super
|
126
148
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'throttler'
|
2
|
+
require_relative 'signature_validator'
|
2
3
|
|
3
4
|
module StraightServer
|
4
5
|
|
5
6
|
class OrdersController
|
7
|
+
include Goliath::Constants
|
6
8
|
|
7
9
|
attr_reader :response
|
8
10
|
|
@@ -21,7 +23,9 @@ module StraightServer
|
|
21
23
|
return [404, {}, "Gateway not found" ]
|
22
24
|
end
|
23
25
|
|
24
|
-
|
26
|
+
if @gateway.check_signature
|
27
|
+
StraightServer::SignatureValidator.new(@gateway, @env).validate!
|
28
|
+
else
|
25
29
|
ip = @env['HTTP_X_FORWARDED_FOR'].to_s
|
26
30
|
ip = @env['REMOTE_ADDR'] if ip.empty?
|
27
31
|
if StraightServer::Throttler.new(@gateway.id).deny?(ip)
|
@@ -43,20 +47,20 @@ module StraightServer
|
|
43
47
|
currency: @params['currency'],
|
44
48
|
btc_denomination: @params['btc_denomination'],
|
45
49
|
keychain_id: @params['keychain_id'],
|
46
|
-
signature: @params['signature'],
|
47
50
|
callback_data: @params['callback_data'],
|
48
|
-
data: @params['data']
|
51
|
+
data: @params['data'],
|
52
|
+
description: @params['description']
|
49
53
|
}
|
54
|
+
|
50
55
|
order = @gateway.create_order(order_data)
|
51
|
-
StraightServer::Thread.new do
|
56
|
+
StraightServer::Thread.new(label: order.payment_id) do
|
52
57
|
# Because this is a new thread, we have to wrap the code inside in #watch_exceptions
|
53
58
|
# once again. Otherwise, no watching is done. Oh, threads!
|
54
59
|
StraightServer.logger.watch_exceptions do
|
55
60
|
order.start_periodic_status_check
|
56
61
|
end
|
57
62
|
end
|
58
|
-
|
59
|
-
[200, {}, order.to_json ]
|
63
|
+
[200, {}, add_callback_data_warning(order).to_json]
|
60
64
|
rescue Sequel::ValidationFailed => e
|
61
65
|
StraightServer.logger.warn(
|
62
66
|
"VALIDATION ERRORS in order, cannot create it:\n" +
|
@@ -64,11 +68,8 @@ module StraightServer
|
|
64
68
|
"Order data: #{order_data.inspect}\n"
|
65
69
|
)
|
66
70
|
[409, {}, "Invalid order: #{e.message}" ]
|
67
|
-
rescue
|
68
|
-
[409, {}, "Invalid
|
69
|
-
rescue StraightServer::GatewayModule::InvalidOrderId
|
70
|
-
StraightServer.logger.warn message = "An invalid id for order supplied: #{@params['order_id']}"
|
71
|
-
[409, {}, message ]
|
71
|
+
rescue Straight::Gateway::OrderAmountInvalid => e
|
72
|
+
[409, {}, "Invalid order: #{e.message}" ]
|
72
73
|
rescue StraightServer::GatewayModule::GatewayInactive
|
73
74
|
StraightServer.logger.warn message = "The gateway is inactive, you cannot create order with it"
|
74
75
|
[503, {}, message ]
|
@@ -82,6 +83,10 @@ module StraightServer
|
|
82
83
|
return [404, {}, "Gateway not found" ]
|
83
84
|
end
|
84
85
|
|
86
|
+
if @gateway.check_signature
|
87
|
+
StraightServer::SignatureValidator.new(@gateway, @env).validate!
|
88
|
+
end
|
89
|
+
|
85
90
|
order = find_order
|
86
91
|
|
87
92
|
if order
|
@@ -106,8 +111,40 @@ module StraightServer
|
|
106
111
|
end
|
107
112
|
end
|
108
113
|
|
114
|
+
def cancel
|
115
|
+
unless @gateway
|
116
|
+
StraightServer.logger.warn "Gateway not found"
|
117
|
+
return [404, {}, "Gateway not found"]
|
118
|
+
end
|
119
|
+
|
120
|
+
if @gateway.check_signature
|
121
|
+
StraightServer::SignatureValidator.new(@gateway, @env).validate!
|
122
|
+
end
|
123
|
+
|
124
|
+
if (order = find_order)
|
125
|
+
order.status(reload: true)
|
126
|
+
order.save if order.status_changed?
|
127
|
+
if order.cancelable?
|
128
|
+
order.cancel
|
129
|
+
[200, {}, '']
|
130
|
+
else
|
131
|
+
[409, {}, "Order is not cancelable"]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def last_keychain_id
|
137
|
+
unless @gateway
|
138
|
+
StraightServer.logger.warn "Gateway not foun"
|
139
|
+
return [404, {}, "Gateway not found"]
|
140
|
+
end
|
141
|
+
|
142
|
+
[200, {}, {gateway_id: @gateway.id, last_keychain_id: @gateway.last_keychain_id}.to_json]
|
143
|
+
end
|
144
|
+
|
109
145
|
private
|
110
146
|
|
147
|
+
# Refactoring proposed: https://github.com/AlexanderPavlenko/straight-server/commit/49ea6e3732a9564c04d8dfecaee6d0ebaa462042
|
111
148
|
def dispatch
|
112
149
|
|
113
150
|
StraightServer.logger.blank_lines
|
@@ -115,17 +152,30 @@ module StraightServer
|
|
115
152
|
|
116
153
|
@gateway = StraightServer::Gateway.find_by_hashed_id(@request_path[1])
|
117
154
|
|
118
|
-
@response =
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
websocket
|
123
|
-
|
124
|
-
|
155
|
+
@response = begin
|
156
|
+
if @request_path[3] # if an order id is supplied
|
157
|
+
@params['id'] = @request_path[3]
|
158
|
+
@params['id'] = @params['id'].to_i if @params['id'] =~ /\A\d+\Z/
|
159
|
+
if @request_path[4] == 'websocket'
|
160
|
+
websocket
|
161
|
+
elsif @request_path[4] == 'cancel'&& @method == 'POST'
|
162
|
+
cancel
|
163
|
+
elsif @request_path[4].nil? && @method == 'GET'
|
164
|
+
show
|
165
|
+
end
|
166
|
+
elsif @request_path[2] == 'last_keychain_id'
|
167
|
+
last_keychain_id
|
168
|
+
elsif @request_path[3].nil?# && @method == 'POST'
|
169
|
+
create
|
125
170
|
end
|
126
|
-
|
127
|
-
|
171
|
+
rescue StraightServer::SignatureValidator::InvalidNonce
|
172
|
+
StraightServer.logger.warn message = "X-Nonce is invalid: #{@env["#{HTTP_PREFIX}X_NONCE"].inspect}"
|
173
|
+
[409, {}, message]
|
174
|
+
rescue StraightServer::SignatureValidator::InvalidSignature
|
175
|
+
StraightServer.logger.warn message = "X-Signature is invalid: #{@env["#{HTTP_PREFIX}X_SIGNATURE"].inspect}"
|
176
|
+
[409, {}, message]
|
128
177
|
end
|
178
|
+
|
129
179
|
@response = [404, {}, "#{@method} /#{@request_path.join('/')} Not found"] if @response.nil?
|
130
180
|
end
|
131
181
|
|
@@ -1,18 +1,8 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
class String
|
2
4
|
|
3
5
|
def self.random(len)
|
4
|
-
|
5
|
-
while s.length != len do
|
6
|
-
s = rand(36**len).to_s(36)
|
7
|
-
end
|
8
|
-
s
|
9
|
-
end
|
10
|
-
|
11
|
-
def repeat(times)
|
12
|
-
result = ""
|
13
|
-
times.times { result << self }
|
14
|
-
result
|
6
|
+
BTC::Base58.base58_from_data(SecureRandom.random_bytes(len))[0, len]
|
15
7
|
end
|
16
|
-
|
17
8
|
end
|
18
|
-
|
@@ -11,7 +11,6 @@ module StraightServer
|
|
11
11
|
StraightServer.logger.info "starting Straight Server v #{StraightServer::VERSION}"
|
12
12
|
require_relative 'order'
|
13
13
|
require_relative 'gateway'
|
14
|
-
require_relative 'orders_controller'
|
15
14
|
load_addons
|
16
15
|
resume_tracking_active_orders!
|
17
16
|
end
|
@@ -20,7 +19,7 @@ module StraightServer
|
|
20
19
|
# Even though we define that option here, it is purely for the purposes of compliance with
|
21
20
|
# Goliath server. If don't do that, there will be an exception saying "unrecognized argument".
|
22
21
|
# In reality, we make use of --config-dir value in the in StraightServer::Initializer and stored
|
23
|
-
# it in StraightServer::Initializer.config_dir property.
|
22
|
+
# it in StraightServer::Initializer.config_dir property.
|
24
23
|
opts.on('-c', '--config-dir STRING', "Directory where config files and addons are placed") do |val|
|
25
24
|
options[:config_dir] = File.expand_path(val || ENV['HOME'] + '/.straight' )
|
26
25
|
end
|
@@ -42,7 +41,7 @@ module StraightServer
|
|
42
41
|
# AFTER the process is daemonized, this shall remain as it is now.
|
43
42
|
begin
|
44
43
|
return process_request(env)
|
45
|
-
rescue Sequel::DatabaseDisconnectError
|
44
|
+
rescue Sequel::DatabaseDisconnectError
|
46
45
|
connect_to_db
|
47
46
|
return process_request(env)
|
48
47
|
end
|
@@ -74,6 +73,6 @@ module StraightServer
|
|
74
73
|
# no block was called, means no route matched. Let's render 404
|
75
74
|
return [404, {}, "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} Not found"]
|
76
75
|
end
|
77
|
-
|
76
|
+
|
78
77
|
end
|
79
78
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'goliath/constants'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module StraightServer
|
5
|
+
class SignatureValidator
|
6
|
+
include Goliath::Constants
|
7
|
+
|
8
|
+
SignatureValidatorError = Class.new(StandardError)
|
9
|
+
InvalidNonce = Class.new(SignatureValidatorError)
|
10
|
+
InvalidSignature = Class.new(SignatureValidatorError)
|
11
|
+
|
12
|
+
attr_reader :gateway, :env
|
13
|
+
|
14
|
+
def initialize(gateway, env)
|
15
|
+
@gateway = gateway
|
16
|
+
@env = env
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate!
|
20
|
+
raise InvalidNonce unless valid_nonce?
|
21
|
+
raise InvalidSignature unless valid_signature?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_nonce?
|
26
|
+
nonce = env["#{HTTP_PREFIX}X_NONCE"].to_i
|
27
|
+
redis = StraightServer.redis_connection
|
28
|
+
loop do
|
29
|
+
redis.watch last_nonce_key do
|
30
|
+
last_nonce = redis.get(last_nonce_key).to_i
|
31
|
+
if last_nonce < nonce
|
32
|
+
result = redis.multi do |multi|
|
33
|
+
multi.set last_nonce_key, nonce
|
34
|
+
end
|
35
|
+
return true if result[0] == 'OK'
|
36
|
+
else
|
37
|
+
redis.unwatch
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_signature?
|
45
|
+
signature == env["#{HTTP_PREFIX}X_SIGNATURE"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def last_nonce_key
|
49
|
+
"#{Config[:'redis.prefix']}:LastNonce:#{gateway.id}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def signature
|
53
|
+
self.class.signature(
|
54
|
+
nonce: env["#{HTTP_PREFIX}X_NONCE"],
|
55
|
+
body: env[RACK_INPUT].kind_of?(StringIO) ? env[RACK_INPUT].string : env[RACK_INPUT].to_s,
|
56
|
+
method: env[REQUEST_METHOD],
|
57
|
+
request_uri: env[REQUEST_URI],
|
58
|
+
secret: gateway.secret,
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Should mirror StraightServerKit.signature
|
63
|
+
def self.signature(nonce:, body:, method:, request_uri:, secret:)
|
64
|
+
sha512 = OpenSSL::Digest::SHA512.new
|
65
|
+
request = "#{method.to_s.upcase}#{request_uri}#{sha512.digest("#{nonce}#{body}")}"
|
66
|
+
Base64.strict_encode64 OpenSSL::HMAC.digest(sha512, secret.to_s, request)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|