bitpay-sdk 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +2 -0
- data/Gemfile +6 -0
- data/LICENSE.md +7 -0
- data/README.md +81 -0
- data/Rakefile +73 -0
- data/bitpay-sdk.gemspec +35 -0
- data/config/capybara.rb +6 -0
- data/config/constants.rb +3 -0
- data/features/creating_invoices.feature +26 -0
- data/features/pairing.feature +21 -0
- data/features/retrieving_invoices.feature +7 -0
- data/features/step_definitions/invoice_steps.rb +26 -0
- data/features/step_definitions/keygen_steps.rb +51 -0
- data/features/step_definitions/step_helpers.rb +79 -0
- data/lib/bitpay.rb +32 -0
- data/lib/bitpay/cacert.pem +3866 -0
- data/lib/bitpay/client.rb +181 -0
- data/lib/bitpay/key_utils.rb +130 -0
- data/lib/bitpay/version.rb +7 -0
- data/lib/harness.rb +40 -0
- data/spec/client_spec.rb +124 -0
- data/spec/features/pair_spec.rb +29 -0
- data/spec/features/pos_spec.rb +37 -0
- data/spec/features/setup_spec.rb +13 -0
- data/spec/features/verify_tokens_spec.rb +34 -0
- data/spec/key_utils_spec.rb +59 -0
- data/spec/set_constants.sh +10 -0
- data/spec/spec_helper.rb +34 -0
- metadata +269 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
# license Copyright 2011-2014 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'net/https'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
require_relative 'key_utils'
|
10
|
+
|
11
|
+
module BitPay
|
12
|
+
# This class is used to instantiate a BitPay Client object. It is expected to be thread safe.
|
13
|
+
#
|
14
|
+
class Client
|
15
|
+
|
16
|
+
|
17
|
+
# @return [Client]
|
18
|
+
# @example
|
19
|
+
# # Create a client with a pem file created by the bitpay client:
|
20
|
+
# client = BitPay::Client.new
|
21
|
+
def initialize(opts={})
|
22
|
+
@pem = opts[:pem] || ENV['BITPAY_PEM'] || KeyUtils.generate_pem
|
23
|
+
@key = KeyUtils.create_key @pem
|
24
|
+
@priv_key = KeyUtils.get_private_key @key
|
25
|
+
@pub_key = KeyUtils.get_public_key @key
|
26
|
+
@client_id = KeyUtils.generate_sin_from_pem @pem
|
27
|
+
@uri = URI.parse opts[:api_uri] || API_URI
|
28
|
+
@user_agent = opts[:user_agent] || USER_AGENT
|
29
|
+
@https = Net::HTTP.new @uri.host, @uri.port
|
30
|
+
@https.use_ssl = true
|
31
|
+
@https.ca_file = CA_FILE
|
32
|
+
@tokens = opts[:tokens] || {}
|
33
|
+
|
34
|
+
# Option to disable certificate validation in extraordinary circumstance. NOT recommended for production use
|
35
|
+
@https.verify_mode = opts[:insecure] == true ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
36
|
+
|
37
|
+
# Option to enable http request debugging
|
38
|
+
@https.set_debug_output($stdout) if opts[:debug] == true
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def pair_pos_client(claimCode)
|
43
|
+
raise BitPay::ArgumentError, "pairing code is not legal" unless verify_claim_code(claimCode)
|
44
|
+
response = set_pos_token(claimCode)
|
45
|
+
get_token 'pos'
|
46
|
+
response
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_invoice(price:, currency:, facade: 'pos', params:{})
|
50
|
+
raise BitPay::ArgumentError, "Illegal Argument: Price must be formatted as a float" unless ( price.is_a?(Numeric) || /^[[:digit:]]+(\.[[:digit:]]{2})?$/.match(price) )
|
51
|
+
raise BitPay::ArgumentError, "Illegal Argument: Currency is invalid." unless /^[[:upper:]]{3}$/.match(currency)
|
52
|
+
params.merge!({price: price, currency: currency})
|
53
|
+
response = send_request("POST", "invoices", facade: facade, params: params)
|
54
|
+
response["data"]
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_public_invoice(id:)
|
58
|
+
request = Net::HTTP::Get.new("/invoices/#{id}")
|
59
|
+
response = process_request(request)
|
60
|
+
response["data"]
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_token
|
64
|
+
end
|
65
|
+
|
66
|
+
def verify_token
|
67
|
+
server_tokens = load_tokens
|
68
|
+
@tokens.each{|key, value| return false if server_tokens[key] != value}
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
## Generates REST request to api endpoint
|
72
|
+
|
73
|
+
def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
|
74
|
+
token ||= get_token(facade)
|
75
|
+
|
76
|
+
# Verb-specific logic
|
77
|
+
case verb.upcase
|
78
|
+
when "GET"
|
79
|
+
urlpath = '/' + path + '?nonce=' + KeyUtils.nonce + '&token=' + token
|
80
|
+
request = Net::HTTP::Get.new urlpath
|
81
|
+
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
82
|
+
|
83
|
+
when "PUT"
|
84
|
+
|
85
|
+
when "POST" # Requires a GUID
|
86
|
+
|
87
|
+
urlpath = '/' + path
|
88
|
+
request = Net::HTTP::Post.new urlpath
|
89
|
+
params[:token] = token
|
90
|
+
params[:nonce] = KeyUtils.nonce
|
91
|
+
params[:guid] = SecureRandom.uuid
|
92
|
+
params[:id] = @client_id
|
93
|
+
request.body = params.to_json
|
94
|
+
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath + request.body, @priv_key)
|
95
|
+
|
96
|
+
when "DELETE"
|
97
|
+
|
98
|
+
raise(BitPayError, "Invalid HTTP verb: #{verb.upcase}")
|
99
|
+
end
|
100
|
+
|
101
|
+
# Build request headers and submit
|
102
|
+
request['X-Identity'] = @pub_key
|
103
|
+
|
104
|
+
response = process_request(request)
|
105
|
+
end
|
106
|
+
|
107
|
+
##### PRIVATE METHODS #####
|
108
|
+
private
|
109
|
+
|
110
|
+
## Processes HTTP Request and returns parsed response
|
111
|
+
# Otherwise throws error
|
112
|
+
#
|
113
|
+
def process_request(request)
|
114
|
+
|
115
|
+
request['User-Agent'] = @user_agent
|
116
|
+
request['Content-Type'] = 'application/json'
|
117
|
+
request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
|
118
|
+
|
119
|
+
begin
|
120
|
+
response = @https.request request
|
121
|
+
rescue => error
|
122
|
+
raise BitPay::ConnectionError, "#{error.message}"
|
123
|
+
end
|
124
|
+
|
125
|
+
if response.kind_of? Net::HTTPSuccess
|
126
|
+
return JSON.parse(response.body)
|
127
|
+
elsif JSON.parse(response.body)["error"]
|
128
|
+
raise(BitPayError, "#{response.code}: #{JSON.parse(response.body)['error']}")
|
129
|
+
else
|
130
|
+
raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
## Requests token by appending nonce and signing URL
|
136
|
+
# Returns a hash of available tokens
|
137
|
+
#
|
138
|
+
def load_tokens
|
139
|
+
|
140
|
+
urlpath = '/tokens?nonce=' + KeyUtils.nonce
|
141
|
+
|
142
|
+
request = Net::HTTP::Get.new(urlpath)
|
143
|
+
request['x-identity'] = @pub_key
|
144
|
+
request['x-signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
145
|
+
|
146
|
+
response = process_request(request)
|
147
|
+
|
148
|
+
token_array = response["data"] || {}
|
149
|
+
|
150
|
+
tokens = {}
|
151
|
+
token_array.each do |t|
|
152
|
+
tokens[t.keys.first] = t.values.first
|
153
|
+
end
|
154
|
+
|
155
|
+
@tokens = tokens
|
156
|
+
return tokens
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
## Retrieves specified token from hash, otherwise tries to refresh @tokens and retry
|
161
|
+
def set_pos_token(claim_code)
|
162
|
+
params = {pairingCode: claim_code}
|
163
|
+
urlpath = '/tokens'
|
164
|
+
request = Net::HTTP::Post.new urlpath
|
165
|
+
params[:guid] = SecureRandom.uuid
|
166
|
+
params[:id] = @client_id
|
167
|
+
request.body = params.to_json
|
168
|
+
process_request(request)
|
169
|
+
end
|
170
|
+
|
171
|
+
def get_token(facade)
|
172
|
+
token = @tokens[facade] || load_tokens[facade] || raise(BitPayError, "Not authorized for facade: #{facade}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def verify_claim_code(claim_code)
|
176
|
+
regex = /^[[:alnum:]]{7}$/
|
177
|
+
matches = regex.match(claim_code)
|
178
|
+
!(matches.nil?)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# license Copyright 2011-2014 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'net/https'
|
7
|
+
require 'json'
|
8
|
+
require 'openssl'
|
9
|
+
require 'ecdsa'
|
10
|
+
require 'securerandom'
|
11
|
+
require 'digest/sha2'
|
12
|
+
require 'cgi'
|
13
|
+
|
14
|
+
module BitPay
|
15
|
+
class KeyUtils
|
16
|
+
class << self
|
17
|
+
def nonce
|
18
|
+
Time.now.utc.strftime('%Y%m%d%H%M%S%L')
|
19
|
+
end
|
20
|
+
|
21
|
+
## Generates a new private key
|
22
|
+
#
|
23
|
+
|
24
|
+
def generate_pem
|
25
|
+
key = OpenSSL::PKey::EC.new("secp256k1")
|
26
|
+
key.generate_key
|
27
|
+
key.to_pem
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_key pem
|
31
|
+
OpenSSL::PKey::EC.new(pem)
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_new_key
|
35
|
+
key = OpenSSL::PKey::EC.new("secp256k1")
|
36
|
+
key.generate_key
|
37
|
+
key
|
38
|
+
end
|
39
|
+
|
40
|
+
## Gets private key from ENV variable or local FS
|
41
|
+
#
|
42
|
+
def get_local_pem_file
|
43
|
+
ENV['BITPAY_PEM'] || (raise BitPayError, MISSING_KEY)
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_private_key key
|
47
|
+
key.private_key.to_int.to_s(16)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_public_key key
|
51
|
+
key.public_key.group.point_conversion_form = :compressed
|
52
|
+
key.public_key.to_bn.to_s(16).downcase
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_private_key_from_pem pem
|
56
|
+
raise BitPayError, "Missing key" unless pem
|
57
|
+
key = OpenSSL::PKey::EC.new(pem)
|
58
|
+
get_private_key key
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_public_key_from_pem pem
|
62
|
+
raise BitPayError, MISSING_KEY unless pem
|
63
|
+
key = OpenSSL::PKey::EC.new(pem)
|
64
|
+
get_public_key key
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_sin_from_pem(pem = nil)
|
68
|
+
#http://blog.bitpay.com/2014/07/01/bitauth-for-decentralized-authentication.html
|
69
|
+
#https://en.bitcoin.it/wiki/Identity_protocol_v1
|
70
|
+
|
71
|
+
# NOTE: All Digests are calculated against the binary representation,
|
72
|
+
# hence the requirement to use [].pack("H*") to convert to binary for each step
|
73
|
+
|
74
|
+
#Generate Private Key
|
75
|
+
key = OpenSSL::PKey::EC.new(pem ||= get_local_pem_file)
|
76
|
+
key.public_key.group.point_conversion_form = :compressed
|
77
|
+
public_key = key.public_key.to_bn.to_s(2)
|
78
|
+
step_one = Digest::SHA256.hexdigest(public_key)
|
79
|
+
step_two = Digest::RMD160.hexdigest([step_one].pack("H*"))
|
80
|
+
step_three = "0F02" + step_two
|
81
|
+
step_four_a = Digest::SHA256.hexdigest([step_three].pack("H*"))
|
82
|
+
step_four = Digest::SHA256.hexdigest([step_four_a].pack("H*"))
|
83
|
+
step_five = step_four[0..7]
|
84
|
+
step_six = step_three + step_five
|
85
|
+
encode_base58(step_six)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
## Generate ECDSA signature
|
90
|
+
# This is the last method that requires the ecdsa gem, which we would like to replace
|
91
|
+
|
92
|
+
def sign(message, privkey)
|
93
|
+
group = ECDSA::Group::Secp256k1
|
94
|
+
digest = Digest::SHA256.digest(message)
|
95
|
+
signature = nil
|
96
|
+
while signature.nil?
|
97
|
+
temp_key = 1 + SecureRandom.random_number(group.order - 1)
|
98
|
+
signature = ECDSA.sign(group, privkey.to_i(16), digest, temp_key)
|
99
|
+
return ECDSA::Format::SignatureDerString.encode(signature).unpack("H*").first
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
########## Private Class Methods ################
|
104
|
+
|
105
|
+
## Base58 Encoding Method
|
106
|
+
#
|
107
|
+
private
|
108
|
+
def encode_base58 (data)
|
109
|
+
code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
110
|
+
base = 58
|
111
|
+
x = data.hex
|
112
|
+
output_string = ""
|
113
|
+
|
114
|
+
while x > 0 do
|
115
|
+
remainder = x % base
|
116
|
+
x = x / base
|
117
|
+
output_string << code_string[remainder]
|
118
|
+
end
|
119
|
+
|
120
|
+
pos = 0
|
121
|
+
while data[pos,2] == "00" do
|
122
|
+
output_string << code_string[0]
|
123
|
+
pos += 2
|
124
|
+
end
|
125
|
+
|
126
|
+
output_string.reverse()
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/harness.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# license Copyright 2011-2014 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
require_relative 'bitpay.rb'
|
6
|
+
require_relative 'bitpay/key_utils.rb'
|
7
|
+
|
8
|
+
# Test SIN Generation class methods
|
9
|
+
|
10
|
+
# Generate SIN
|
11
|
+
ENV["PRIV_KEY"] = "16d7c3508ec59773e71ae728d29f41fcf5d1f380c379b99d68fa9f552ce3ebc3"
|
12
|
+
puts "privkey: #{ENV['PRIV_KEY']}"
|
13
|
+
puts "target SIN: TfFVQhy2hQvchv4VVG4c7j4XPa2viJ9HrR8"
|
14
|
+
puts "Derived SIN: #{BitPay::KeyUtils.get_client_id}"
|
15
|
+
|
16
|
+
puts "\n\n------------------\n\n"
|
17
|
+
|
18
|
+
uri = "https://localhost:8088"
|
19
|
+
#name = "Ridonculous.label That shouldn't work really"
|
20
|
+
name = "somethinginnocuous"
|
21
|
+
facade = "pos"
|
22
|
+
client_id = BitPay::KeyUtils.get_client_id
|
23
|
+
|
24
|
+
BitPay::KeyUtils.generate_registration_url(uri,name,facade,client_id)
|
25
|
+
|
26
|
+
puts "\n\n------------------\n\n"
|
27
|
+
|
28
|
+
#### Test Invoice Creation using directly assigned keys
|
29
|
+
## (Ultimately pubkey and SIN should be derived)
|
30
|
+
|
31
|
+
ENV["PRIV_KEY"] = "16d7c3508ec59773e71ae728d29f41fcf5d1f380c379b99d68fa9f552ce3ebc3"
|
32
|
+
#ENV["pub_key"] = "0353a036fb495c5846f26a3727a28198da8336ae4f5aaa09e24c14a4126b5d969d"
|
33
|
+
#ENV['SIN'] = "TfFVQhy2hQvchv4VVG4c7j4XPa2viJ9HrR8"
|
34
|
+
|
35
|
+
client = BitPay::Client.new({insecure: true, debug: false})
|
36
|
+
|
37
|
+
invoice = client.post 'invoices', {:price => 10.00, :currency => 'USD'}
|
38
|
+
|
39
|
+
puts "Here's the invoice: \n" + JSON.pretty_generate(invoice)
|
40
|
+
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def tokens
|
4
|
+
{"data" =>
|
5
|
+
[{"merchant" => "MERCHANTTOKEN"},
|
6
|
+
{"pos" =>"POSTOKEN"},
|
7
|
+
{"merchant/invoice" => "9kv7gGqZLoQ2fxbKEgfgndLoxwjp5na6VtGSH3sN7buX"}
|
8
|
+
]
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
describe BitPay::Client do
|
13
|
+
let(:bitpay_client) { BitPay::Client.new({api_uri: BitPay::TEST_API_URI}) }
|
14
|
+
let(:claim_code) { "a12bc3d" }
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(BitPay::KeyUtils).to receive(:nonce).and_return('1')
|
18
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(:status => 200, :body => tokens.to_json, :headers => {})
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#initialize" do
|
22
|
+
|
23
|
+
it 'should be able to get pem file from the env' do
|
24
|
+
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
25
|
+
expect {bitpay_client}.to_not raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#send_request" do
|
31
|
+
before do
|
32
|
+
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
33
|
+
end
|
34
|
+
|
35
|
+
context "GET" do
|
36
|
+
it 'should generate a get request' do
|
37
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/whatever.*/).to_return(:body => '{"awesome": "json"}')
|
38
|
+
bitpay_client.send_request("GET", "whatever", facade: "merchant")
|
39
|
+
expect(WebMock).to have_requested(:get, "#{BitPay::TEST_API_URI}/whatever?nonce=1&token=MERCHANTTOKEN")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "POST" do
|
44
|
+
it 'should generate a post request' do
|
45
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}.*/).to_return(:body => '{"awesome": "json"}')
|
46
|
+
bitpay_client.send_request("POST", "whatever", facade: "merchant")
|
47
|
+
expect(WebMock).to have_requested(:post, "#{BitPay::TEST_API_URI}/whatever")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#pair_pos_client" do
|
54
|
+
before do
|
55
|
+
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'throws a BitPayError with the error message if the token setting fails' do
|
59
|
+
stub_request(:any, /#{BitPay::TEST_API_URI}.*/).to_return(status: 500, body: "{\n \"error\": \"Unable to create token\"\n}")
|
60
|
+
expect { bitpay_client.pair_pos_client(claim_code) }.to raise_error(BitPay::BitPayError, '500: Unable to create token')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'gracefully handles 4xx errors' do
|
64
|
+
stub_request(:any, /#{BitPay::TEST_API_URI}.*/).to_return(status: 403, body: "{\n \"error\": \"this is a 403 error\"\n}")
|
65
|
+
expect { bitpay_client.pair_pos_client(claim_code) }.to raise_error(BitPay::BitPayError, '403: this is a 403 error')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'short circuits on invalid pairing codes' do
|
69
|
+
100.times do
|
70
|
+
claim_code = an_illegal_claim_code
|
71
|
+
expect{bitpay_client.pair_pos_client(claim_code)}.to raise_error BitPay::ArgumentError, "pairing code is not legal"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#create_invoice" do
|
77
|
+
subject { bitpay_client }
|
78
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
79
|
+
it { is_expected.to respond_to(:create_invoice) }
|
80
|
+
|
81
|
+
describe "should make the call to the server to create an invoice" do
|
82
|
+
it 'allows numeric input for the price' do
|
83
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
84
|
+
bitpay_client.create_invoice(price: 20.00, currency: "USD")
|
85
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'allows string input for the price' do
|
89
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
90
|
+
bitpay_client.create_invoice(price: "20.00", currency: "USD")
|
91
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should pass through the API error message from load_tokens' do
|
96
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(status: 500, body: '{"error": "load_tokens_error"}')
|
97
|
+
expect { bitpay_client.create_invoice(price: 20, currency: "USD") }.to raise_error(BitPay::BitPayError, '500: load_tokens_error')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'verifies the validity of the price argument' do
|
101
|
+
expect { bitpay_client.create_invoice(price: "3,999", currency: "USD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Price must be formatted as a float')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'verifies the validity of the currency argument' do
|
105
|
+
expect { bitpay_client.create_invoice(price: "3999", currency: "UASD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Currency is invalid.')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#set_token' do
|
110
|
+
subject { bitpay_client }
|
111
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
112
|
+
it { is_expected.to respond_to(:set_token) }
|
113
|
+
it 'sets a token in the client' do
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#verify_token" do
|
119
|
+
subject { bitpay_client }
|
120
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
121
|
+
it { is_expected.to respond_to(:verify_token) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|