straight-server 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.
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StraightServer::Gateway do
4
+
5
+ before(:each) do
6
+ @gateway = StraightServer::GatewayOnConfig.find_by_id(1)
7
+ @order_mock = double("order mock")
8
+ [:id, :gateway=, :save, :to_h, :id=].each { |m| allow(@order_mock).to receive(m) }
9
+ @order_for_keychain_id_args = { amount: 1, keychain_id: 1, currency: nil, btc_denomination: nil }
10
+ end
11
+
12
+ it "checks for signature when creating a new order" do
13
+ @gateway.last_keychain_id = 0
14
+ expect( -> { @gateway.create_order(amount: 1, signature: 'invalid', id: 1) }).to raise_exception(StraightServer::GatewayModule::InvalidSignature)
15
+ expect(@gateway).to receive(:order_for_keychain_id).with(@order_for_keychain_id_args).once.and_return(@order_mock)
16
+ @gateway.create_order(amount: 1, signature: hmac_sha1(1, 'secret'), id: 1)
17
+ end
18
+
19
+ it "checks md5 signature only if that setting is set ON for a particular gateway" do
20
+ gateway1 = StraightServer::GatewayOnConfig.find_by_id(1)
21
+ gateway2 = StraightServer::GatewayOnConfig.find_by_id(2)
22
+ expect(gateway2).to receive(:order_for_keychain_id).with(@order_for_keychain_id_args).once.and_return(@order_mock)
23
+ expect( -> { gateway1.create_order(amount: 1, signature: 'invalid') }).to raise_exception
24
+ expect( -> { gateway2.create_order(amount: 1, signature: 'invalid') }).not_to raise_exception()
25
+ end
26
+
27
+ it "doesn't allow nil or empty order id if signature checks are enabled" do
28
+ expect( -> { @gateway.create_order(amount: 1, signature: 'invalid', id: nil) }).to raise_exception(StraightServer::GatewayModule::InvalidOrderId)
29
+ expect( -> { @gateway.create_order(amount: 1, signature: 'invalid', id: '') }).to raise_exception(StraightServer::GatewayModule::InvalidOrderId)
30
+ end
31
+
32
+ it "sets order amount in satoshis calculated from another currency" do
33
+ @gateway = StraightServer::GatewayOnConfig.find_by_id(2)
34
+ allow(@gateway).to receive(:address_for_keychain_id).and_return('address')
35
+ allow(@gateway.exchange_rate_adapters.first).to receive(:rate_for).and_return(450.5412)
36
+ expect(@gateway.create_order(amount: 2252.706, currency: 'USD').amount).to eq(500000000)
37
+ end
38
+
39
+ context "callback url" do
40
+
41
+ before(:each) do
42
+ @gateway = StraightServer::GatewayOnConfig.find_by_id(2) # Gateway 2 doesn't require signatures
43
+ @response_mock = double("http response mock")
44
+ expect(@response_mock).to receive(:body).once.and_return('body')
45
+ @order = create(:order)
46
+ allow(@order).to receive(:status).and_return(1)
47
+ allow(@order).to receive(:tid).and_return('tid1')
48
+ end
49
+
50
+ it "sends a request to the callback_url" do
51
+ expect(@response_mock).to receive(:code).twice.and_return("200")
52
+ expect(Net::HTTP).to receive(:get_response).and_return(@response_mock)
53
+ @gateway.order_status_changed(@order)
54
+ end
55
+
56
+ it "keeps sending request according to the callback schedule if there's an error" do
57
+ expect(@response_mock).to receive(:code).twice.and_return("404")
58
+ expect(@gateway).to receive(:sleep).exactly(10).times
59
+ expect(Net::HTTP).to receive(:get_response).exactly(11).times.and_return(@response_mock)
60
+ expect(URI).to receive(:parse).with('http://localhost:3001/payment-callback?' + @order.to_http_params).exactly(11).times
61
+ @gateway.order_status_changed(@order)
62
+ end
63
+
64
+ it "signs the callback if gateway has a secret" do
65
+ @gateway = StraightServer::GatewayOnConfig.find_by_id(1) # Gateway 1 requires signatures
66
+ expect(@response_mock).to receive(:code).twice.and_return("200")
67
+ expect(URI).to receive(:parse).with('http://localhost:3000/payment-callback?' + @order.to_http_params + "&signature=#{hmac_sha1(hmac_sha1(@order.id, 'secret'), 'secret')}")
68
+ expect(Net::HTTP).to receive(:get_response).and_return(@response_mock)
69
+ @gateway.order_status_changed(@order)
70
+ end
71
+
72
+ it "receives random data in :data params and sends it back in a callback request" do
73
+ @order.data = 'some random data'
74
+ expect(@gateway).to receive(:order_for_keychain_id).with(@order_for_keychain_id_args).once.and_return(@order)
75
+ @gateway.create_order(amount: 1, data: 'some random data')
76
+ expect(@response_mock).to receive(:code).twice.and_return("200")
77
+ expect(Net::HTTP).to receive(:get_response).and_return(@response_mock)
78
+ expect(URI).to receive(:parse).with('http://localhost:3001/payment-callback?' + @order.to_http_params + "&data=#{@order.data}")
79
+ @gateway.order_status_changed(@order)
80
+ end
81
+
82
+ it "saves callback url response in the order's record in DB" do
83
+ allow(@response_mock).to receive(:code).and_return("200")
84
+ allow(Net::HTTP).to receive(:get_response).and_return(@response_mock)
85
+ @gateway.order_status_changed(@order)
86
+ expect(@order.callback_response).to eq({code: "200", body: "body"})
87
+ end
88
+
89
+ end
90
+
91
+ describe "config based gateway" do
92
+
93
+ it "loads all the gateways from the config file and assigns correct attributes" do
94
+ gateway1 = StraightServer::GatewayOnConfig.find_by_id(1)
95
+ gateway2 = StraightServer::GatewayOnConfig.find_by_id(2)
96
+ expect(gateway1).to be_kind_of(StraightServer::GatewayOnConfig)
97
+ expect(gateway2).to be_kind_of(StraightServer::GatewayOnConfig)
98
+
99
+ expect(gateway1.pubkey).to eq('xpub-000')
100
+ expect(gateway1.confirmations_required).to eq(0)
101
+ expect(gateway1.order_class).to eq("StraightServer::Order")
102
+ expect(gateway1.name).to eq("default")
103
+
104
+ expect(gateway2.pubkey).to eq('xpub-001')
105
+ expect(gateway2.confirmations_required).to eq(0)
106
+ expect(gateway2.order_class).to eq("StraightServer::Order")
107
+ expect(gateway2.name).to eq("second_gateway")
108
+ end
109
+
110
+ it "saves and retrieves last_keychain_id from the file in the .straight dir" do
111
+ expect(File.read("#{ENV['HOME']}/.straight/default_last_keychain_id").to_i).to eq(0)
112
+ @gateway.increment_last_keychain_id!
113
+ expect(File.read("#{ENV['HOME']}/.straight/default_last_keychain_id").to_i).to eq(1)
114
+
115
+ expect(@gateway).to receive(:order_for_keychain_id).with(@order_for_keychain_id_args.merge({ keychain_id: 2})).once.and_return(@order_mock)
116
+ @gateway.create_order(amount: 1, signature: hmac_sha1(1, 'secret'), id: 1)
117
+ expect(File.read("#{ENV['HOME']}/.straight/default_last_keychain_id").to_i).to eq(2)
118
+ end
119
+
120
+ end
121
+
122
+ describe "db based gateway" do
123
+
124
+ before(:each) do
125
+ @gateway = StraightServer::GatewayOnDB.create(
126
+ confirmations_required: 0,
127
+ pubkey: 'xpub-000',
128
+ order_class: 'StraightServer::Order',
129
+ secret: 'secret',
130
+ name: 'default',
131
+ check_signature: true,
132
+ exchange_rate_adapter_names: ['Bitpay', 'Coinbase', 'Bitstamp']
133
+ )
134
+ end
135
+
136
+ it "saves and retrieves last_keychain_id from the db" do
137
+ expect(DB[:gateways][:name => 'default'][:last_keychain_id]).to eq(0)
138
+ @gateway.increment_last_keychain_id!
139
+ expect(DB[:gateways][:name => 'default'][:last_keychain_id]).to eq(1)
140
+
141
+ expect(@gateway).to receive(:order_for_keychain_id).with(@order_for_keychain_id_args.merge({ keychain_id: 2})).once.and_return(@order_mock)
142
+ @gateway.create_order(amount: 1, signature: hmac_sha1(1, 'secret'), id: 1)
143
+ expect(DB[:gateways][:name => 'default'][:last_keychain_id]).to eq(2)
144
+ end
145
+
146
+ end
147
+
148
+ describe "handling websockets" do
149
+
150
+ before(:each) do
151
+ @gateway.instance_variable_set(:@websockets, {})
152
+ @ws = double("websocket mock")
153
+ allow(@ws).to receive(:on).with(:close)
154
+ allow(@order_mock).to receive(:id).and_return(1)
155
+ allow(@order_mock).to receive(:status).and_return(0)
156
+ end
157
+
158
+ it "adds a new websocket for the order" do
159
+ @gateway.add_websocket_for_order(@ws, @order_mock)
160
+ expect(@gateway.instance_variable_get(:@websockets)).to eq({ 1 => @ws})
161
+ end
162
+
163
+ it "sends a message to the websocket when status of the order is changed and closes the connection" do
164
+ allow(@gateway).to receive(:send_callback_http_request) # ignoring the callback which sends an callback_url request
165
+ expect(@order_mock).to receive(:to_json).and_return("order json info")
166
+ expect(@ws).to receive(:send).with("order json info")
167
+ expect(@ws).to receive(:close)
168
+ @gateway.add_websocket_for_order(@ws, @order_mock)
169
+ @gateway.order_status_changed(@order_mock)
170
+ end
171
+
172
+ it "doesn't allow to listen to orders with statuses other than 0 or 1" do
173
+ allow(@order_mock).to receive(:status).and_return(2)
174
+ expect( -> { @gateway.add_websocket_for_order(@ws, @order_mock) }).to raise_exception(StraightServer::Gateway::WebsocketForCompletedOrder)
175
+ end
176
+
177
+ it "doesn't allow to create a second websocket for the same order" do
178
+ allow(@order_mock).to receive(:status).and_return(0)
179
+ @gateway.add_websocket_for_order(@ws, @order_mock)
180
+ expect( -> { @gateway.add_websocket_for_order(@ws, @order_mock) }).to raise_exception(StraightServer::Gateway::WebsocketExists)
181
+ end
182
+
183
+ end
184
+
185
+ def hmac_sha1(key, secret)
186
+ h = HMAC::SHA1.new('secret')
187
+ h << key.to_s
188
+ h.hexdigest
189
+ end
190
+
191
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StraightServer::Order do
4
+
5
+ before(:each) do
6
+ # clean the database
7
+ DB.run("DELETE FROM orders")
8
+ @gateway = double("Straight Gateway mock")
9
+ allow(@gateway).to receive(:id).and_return(1)
10
+ @order = create(:order, gateway_id: @gateway.id)
11
+ allow(@gateway).to receive(:fetch_transactions_for).with(anything).and_return([])
12
+ allow(@gateway).to receive(:order_status_changed).with(anything)
13
+ allow(StraightServer::Gateway).to receive(:find_by_id).and_return(@gateway)
14
+ end
15
+
16
+ it "prepares data as http params" do
17
+ allow(@order).to receive(:tid).and_return("tid1")
18
+ expect(@order.to_http_params).to eq("order_id=#{@order.id}&amount=10&status=#{@order.status}&address=#{@order.address}&tid=tid1")
19
+ end
20
+
21
+ describe "DB interaction" do
22
+
23
+ it "saves a new order into the database" do
24
+ expect(DB[:orders][:keychain_id => @order.id]).not_to be_nil
25
+ end
26
+
27
+ it "updates an existing order" do
28
+ expect(DB[:orders][:keychain_id => @order.id][:status]).to eq(0)
29
+ @order.status = 1
30
+ @order.save
31
+ expect(DB[:orders][:keychain_id => @order.id][:status]).to eq(1)
32
+ end
33
+
34
+ it "finds first order in the database by id" do
35
+ expect(StraightServer::Order.find(id: @order.id)).to equal_order(@order)
36
+ end
37
+
38
+ it "finds first order in the database by keychain_id" do
39
+ expect(StraightServer::Order.find(keychain_id: @order.keychain_id)).to equal_order(@order)
40
+ end
41
+
42
+ it "finds orders in the database by any conditions" do
43
+ order1 = create(:order, gateway_id: @gateway.id)
44
+ order2 = create(:order, gateway_id: @gateway.id)
45
+
46
+ expect(StraightServer::Order.where(keychain_id: order1.keychain_id).first).to equal_order(order1)
47
+ expect(StraightServer::Order.where(keychain_id: order2.keychain_id).first).to equal_order(order2)
48
+ expect(StraightServer::Order.where(keychain_id: order2.keychain_id+1).first).to be_nil
49
+
50
+ end
51
+
52
+ describe "with validations" do
53
+
54
+ it "doesn't save order if the order with the same id exists" do
55
+ order = create(:order, gateway_id: @gateway.id)
56
+ expect( -> { create(:order, id: order.id, gateway_id: @gateway.id) }).to raise_error()
57
+ end
58
+
59
+ it "doesn't save order if the order with the same address exists" do
60
+ order = create(:order, gateway_id: @gateway.id)
61
+ expect( -> { create(:order, address: order.address) }).to raise_error()
62
+ end
63
+
64
+ it "doesn't save order if the order with the same keychain_id and gateway_id exists" do
65
+ order = create(:order, gateway_id: @gateway.id)
66
+ expect( -> { create(:order, keychain_id: order.id, gateway_id: order.gateway_id+1) }).not_to raise_error()
67
+ expect( -> { create(:order, keychain_id: order.id, gateway_id: order.gateway_id) }).to raise_error()
68
+ end
69
+
70
+ it "doesn't save order if the amount is invalid" do
71
+ expect( -> { create(:order, amount: 0) }).to raise_error()
72
+ end
73
+
74
+ it "doesn't save order if gateway_id is invalid" do
75
+ expect( -> { create(:order, gateway_id: 0) }).to raise_error()
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StraightServer::OrdersController do
4
+
5
+ before(:each) do
6
+ DB.run("DELETE FROM orders")
7
+ @gateway = gateway = StraightServer::Gateway.find_by_id(2)
8
+ allow(gateway).to receive(:address_for_keychain_id).and_return("address#{gateway.last_keychain_id+1}")
9
+ allow(gateway).to receive(:fetch_transactions_for).with(anything).and_return([])
10
+ allow(gateway).to receive(:send_callback_http_request)
11
+ end
12
+
13
+ describe "create action" do
14
+
15
+ it "creates an order and renders its attrs in json" do
16
+ allow(StraightServer::Thread).to receive(:new) # ignore periodic status checks, we're not testing it here
17
+ send_request "POST", '/gateways/2/orders', amount: 10
18
+ expect(response).to render_json_with(status: 0, amount: 10, address: "address1", tid: nil, id: :anything)
19
+ end
20
+
21
+ it "renders 409 error when an order cannot be created due to some validation errors" do
22
+ send_request "POST", '/gateways/2/orders', amount: 0
23
+ expect(response[0]).to eq(409)
24
+ expect(response[2]).to eq("Invalid order: amount is invalid")
25
+ end
26
+
27
+ it "starts tracking the order status in a separate thread" do
28
+ order_mock = double("order mock")
29
+ expect(order_mock).to receive(:start_periodic_status_check)
30
+ allow(order_mock).to receive(:to_h).and_return({})
31
+ expect(@gateway).to receive(:create_order).and_return(order_mock)
32
+ send_request "POST", '/gateways/2/orders', amount: 10
33
+ end
34
+
35
+ end
36
+
37
+ describe "show action" do
38
+
39
+ before(:each) do
40
+ @order_mock = double('order mock')
41
+ allow(@order_mock).to receive(:status).and_return(2)
42
+ allow(@order_mock).to receive(:to_json).and_return("order json mock")
43
+ end
44
+
45
+ it "renders json info about an order if it is found" do
46
+ allow(@order_mock).to receive(:status_changed?).and_return(false)
47
+ expect(StraightServer::Order).to receive(:[]).with(1).and_return(@order_mock)
48
+ send_request "GET", '/gateways/2/orders/1'
49
+ expect(response).to eq([200, {}, "order json mock"])
50
+ end
51
+
52
+ it "saves an order if status is updated" do
53
+ allow(@order_mock).to receive(:status_changed?).and_return(true)
54
+ expect(@order_mock).to receive(:save)
55
+ expect(StraightServer::Order).to receive(:[]).with(1).and_return(@order_mock)
56
+ send_request "GET", '/gateways/2/orders/1'
57
+ expect(response).to eq([200, {}, "order json mock"])
58
+ end
59
+
60
+ it "renders 404 if order is not found" do
61
+ expect(StraightServer::Order).to receive(:[]).with(1).and_return(nil)
62
+ send_request "GET", '/gateways/2/orders/1'
63
+ expect(response).to eq([404, {}, "GET /gateways/2/orders/1 Not found"])
64
+ end
65
+
66
+ end
67
+
68
+ describe "websocket action" do
69
+
70
+ before(:each) do
71
+ @gateway.instance_variable_set(:@websockets, {})
72
+ @ws_mock = double("websocket mock")
73
+ @order_mock = double("order mock")
74
+ allow(@ws_mock).to receive(:rack_response).and_return("ws rack response")
75
+ [:id, :gateway=, :save, :to_h, :id=].each { |m| allow(@order_mock).to receive(m) }
76
+ allow(@ws_mock).to receive(:on)
77
+ allow(Faye::WebSocket).to receive(:new).and_return(@ws_mock)
78
+ end
79
+
80
+ it "returns a websocket connection" do
81
+ allow(@order_mock).to receive(:status).and_return(0)
82
+ allow(StraightServer::Order).to receive(:[]).with(1).and_return(@order_mock)
83
+ send_request "GET", '/gateways/2/orders/1/websocket'
84
+ expect(response).to eq("ws rack response")
85
+ end
86
+
87
+ it "returns 403 when socket already exists" do
88
+ allow(@order_mock).to receive(:status).and_return(0)
89
+ allow(StraightServer::Order).to receive(:[]).with(1).twice.and_return(@order_mock)
90
+ send_request "GET", '/gateways/2/orders/1/websocket'
91
+ send_request "GET", '/gateways/2/orders/1/websocket'
92
+ expect(response).to eq([403, {}, "Someone is already listening to that order"])
93
+ end
94
+
95
+ it "returns 403 when order has is completed (status > 1 )" do
96
+ allow(@order_mock).to receive(:status).and_return(2)
97
+ allow(StraightServer::Order).to receive(:[]).with(1).and_return(@order_mock)
98
+ send_request "GET", '/gateways/2/orders/1/websocket'
99
+ expect(response).to eq([403, {}, "You cannot listen to this order because it is completed (status > 1)"])
100
+ end
101
+
102
+ end
103
+
104
+ def send_request(method, path, params={})
105
+ env = Hashie::Mash.new({ 'REQUEST_METHOD' => method, 'REQUEST_PATH' => path, 'params' => params })
106
+ @controller = StraightServer::OrdersController.new(env)
107
+ end
108
+
109
+ def response
110
+ @controller.response
111
+ end
112
+
113
+ end
@@ -0,0 +1,77 @@
1
+ # !!! The order in which we require files here is very important.
2
+
3
+ # 1. First, load dependencies and connect to the Database
4
+ require 'sequel'
5
+ require 'straight'
6
+ require 'fileutils' # This is required to cleanup the test .straight dir
7
+ require 'hashie'
8
+
9
+ Sequel.extension :migration
10
+ DB = Sequel.sqlite
11
+
12
+ # 2. Then we can run migrations BEFORE we load actual models
13
+ Sequel::Migrator.run(DB, File.expand_path('../', File.dirname(__FILE__)) + '/db/migrations/')
14
+
15
+ # 3. Load config and initializer so that we can read our test config file located in
16
+ # spec/.straight/config.yml
17
+
18
+ # 3.1 This tells initializer where to read the config file from
19
+ ENV['HOME'] = File.expand_path(File.dirname(__FILE__))
20
+
21
+ # 3.2 Actually load the initializer
22
+ require_relative "../lib/straight-server/config"
23
+ require_relative "../lib/straight-server/initializer"
24
+ include StraightServer::Initializer
25
+
26
+ read_config_file
27
+
28
+ # 4. Load the rest of the files, including models, which are now ready
29
+ # to be used as intended and will follow all the previous configuration.
30
+ require_relative '../lib/straight-server/order'
31
+ require_relative '../lib/straight-server/gateway'
32
+ require_relative '../lib/straight-server/orders_controller'
33
+ require_relative '../lib/straight-server'
34
+
35
+ require_relative 'support/custom_matchers'
36
+
37
+ require "factory_girl"
38
+ require_relative "factories"
39
+
40
+ class StraightServer::Order
41
+ alias :save! :save
42
+ end
43
+
44
+ class StraightServer::Thread
45
+ def self.new(&block)
46
+ block.call
47
+ end
48
+ end
49
+
50
+ RSpec.configure do |config|
51
+
52
+ config.include FactoryGirl::Syntax::Methods
53
+
54
+ config.before(:suite) do
55
+ StraightServer.db_connection = DB #use a memory DB
56
+ end
57
+
58
+ config.before(:each) do
59
+ DB[:orders].delete
60
+ logger_mock = double("logger mock")
61
+ [:debug, :info, :warn, :fatal, :unknown, :blank_lines].each do |e|
62
+ allow(logger_mock).to receive(e)
63
+ end
64
+ StraightServer.logger = logger_mock
65
+ StraightServer::GatewayOnConfig.class_variable_get(:@@gateways).each do |g|
66
+ g.last_keychain_id = 0
67
+ g.save
68
+ end
69
+ end
70
+
71
+ config.after(:all) do
72
+ ["default_last_keychain_id", "second_gateway_last_keychain_id"].each do |f|
73
+ FileUtils.rm "#{ENV['HOME']}/.straight/#{f}" if File.exists?("#{ENV['HOME']}/.straight/#{f}")
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,44 @@
1
+ RSpec::Matchers.define :equal_order do |expected|
2
+ match do |actual|
3
+ true
4
+ actual.address == expected.address &&
5
+ actual.status == expected.status &&
6
+ actual.keychain_id == expected.keychain_id &&
7
+ actual.amount == expected.amount &&
8
+ actual.gateway_id == expected.gateway_id &&
9
+ actual.id == expected.id
10
+ end
11
+
12
+ diffable
13
+ end
14
+
15
+ RSpec::Matchers.define :render_json_with do |hash|
16
+
17
+ match do |r|
18
+ json_response = JSON.parse(r[2])
19
+ check_one_dimensional_hash(hash, json_response)
20
+ end
21
+
22
+ def check_one_dimensional_hash(hash, json_response)
23
+ hash.each do |k,v|
24
+ if v == :anything
25
+ expect(json_response[k.to_s]).to_not be_nil
26
+ elsif v == nil
27
+ expect(json_response[k.to_s]).to be_nil
28
+ elsif v.kind_of?(Hash)
29
+ expect(json_response[k.to_s].kind_of?(Hash)).to be_truthy
30
+ check_one_dimensional_hash(v, json_response[k.to_s])
31
+ else
32
+ expect(json_response[k.to_s]).to eq(v)
33
+ end
34
+ end
35
+ end
36
+
37
+ failure_message do |actual|
38
+ "expected that it had:\n\n\t\t#{hash},\n\nbut instead it had:\n\n\t\t#{JSON.parse(actual[2])}"
39
+ end
40
+ failure_message_when_negated do |actual|
41
+ "expected that it wouldn't render #{hash.inspect} but it did!"
42
+ end
43
+
44
+ end
@@ -0,0 +1,46 @@
1
+ # If set to db, then use DB table to store gateways,
2
+ # useful when your run many gateways on the same server.
3
+ gateways_source: config
4
+
5
+ gateways:
6
+ default:
7
+ pubkey: xpub-xxx # <- TODO: change this to your BIP32 pubkey
8
+ confirmations_required: 0
9
+ order_class: "StraightServer::Order"
10
+ secret: 'secret'
11
+ check_signature: false
12
+ callback_url: 'http://localhost:3000/my_app/payment_callback'
13
+ default_currency: 'BTC'
14
+
15
+ # The order matters here, we check for prices with the first adapter,
16
+ # if it fails, move on to the next
17
+ exchange_rate_adapters:
18
+ - Bitpay
19
+ - Coinbase
20
+ - Bitstamp
21
+
22
+ logmaster:
23
+ log_level: INFO # Wise to change to WARN for production
24
+ file: straight.log
25
+ raise_exception: false
26
+ name: Straight server logger
27
+
28
+ # These options bellow send you email whenever a FATAL error occurs.
29
+ # You probably want to uncomment them for production. See https://github.com/snitko/logmaste
30
+ # for various email options.
31
+ #
32
+ #email_config:
33
+ #to: 'me@email.foo',
34
+ #from: "logmaster@yourapp.com"
35
+
36
+ db:
37
+ adapter: sqlite
38
+ name: straight.db # file is always located in ~/.straight
39
+
40
+ # No need to set these options for sqlite,
41
+ # but other DBs may require them.
42
+ #
43
+ #user: username
44
+ #password: password
45
+ #host: hostname
46
+ #port: 1234