bitpay-client 2.0.0 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8c99b683ba6a20ac1e7a0739e29a654d1976cae
4
- data.tar.gz: ba0aeebf8fdbec667e0bf76500e194eb549ab25f
3
+ metadata.gz: 1d735bbff357cf079a5f5ea6c357e3375644cde5
4
+ data.tar.gz: 55b7d5cbbe130d8412e74db9798e1a7bad3ac827
5
5
  SHA512:
6
- metadata.gz: 3def8a32c76c98d4c43ece8785641cd8499d48bf5ce93525c67c1a6a48c0238ebc07964ae938e9144a671b28b13d3efc44c10c7cfded72dc5aa4dbf0564e7ba6
7
- data.tar.gz: 11e62b62bbe443fb1d8a7f8ffbcbda5218ec64263dec0605444f2490193a1346bccd756003a8c0cee7827edd3d699bba55e2833c4c634e446dcebe34a3865566
6
+ metadata.gz: 43df16582f56058a03896e433f62a8c4338dd40c7598192d0811f437e628ebe601e53d28aa54913fae88a5f89f48b3306255df4153825d136f65504d468de85e
7
+ data.tar.gz: 4b679cc6bdae90dbb028081457b8990cf2c33ccc75024e43378ad7a687c36bd94fcee09d3ff2f0ea300e3e679db459483edba53c1c3463ea51f48fe2ad2b98c8
data/README.md CHANGED
@@ -23,11 +23,11 @@ The client will generate a key when initialized if one does not already exist.
23
23
 
24
24
  ### Pairing with Bitpay.com
25
25
 
26
- To pair with bitpay.com you need to have an approved merchant account.
27
- 1. Login to your account
28
- 1. Navigate to bitpay.com/api-tokens (Dashboard > My Account > API Tokens)
29
- 1. Copy an existing pairing code or create a new token and copy the pairing code.
30
- 1. Use the bitpay command line tool to pair with bitpay.com `bitpay pair <pairing_code>`
26
+ To pair with bitpay.com you need to have an approved merchant account.
27
+ 1. Login to your account
28
+ 2. Navigate to bitpay.com/api-tokens (Dashboard > My Account > API Tokens)
29
+ 3. Copy an existing pairing code or create a new token and copy the pairing code.
30
+ 4. Use the bitpay command line tool to pair with bitpay.com `bitpay pair <pairing_code>`
31
31
 
32
32
  ### To create an invoice with a paired client:
33
33
 
@@ -1,5 +1,5 @@
1
1
  Capybara.javascript_driver = :poltergeist
2
2
  Capybara.default_driver = :poltergeist
3
3
  Capybara.register_driver :poltergeist do |app|
4
- Capybara::Poltergeist::Driver.new(app, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes'])
4
+ Capybara::Poltergeist::Driver.new(app, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1'] )
5
5
  end
@@ -29,6 +29,7 @@ module BitPay
29
29
  @https = Net::HTTP.new @uri.host, @uri.port
30
30
  @https.use_ssl = true
31
31
  @https.ca_file = CA_FILE
32
+ @tokens = {}
32
33
 
33
34
  # Option to disable certificate validation in extraordinary circumstance. NOT recommended for production use
34
35
  @https.verify_mode = opts[:insecure] == true ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
@@ -36,20 +37,11 @@ module BitPay
36
37
  # Option to enable http request debugging
37
38
  @https.set_debug_output($stdout) if opts[:debug] == true
38
39
 
39
- # Load all the available tokens into @tokens
40
- load_tokens
41
40
  end
42
41
 
43
42
  def pair_pos_client(claimCode)
44
43
  response = set_pos_token(claimCode)
45
- case response.code
46
- when "200"
47
- get_token 'pos'
48
- when "500"
49
- raise BitPayError, JSON.parse(response.body)["error"]
50
- else
51
- raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
52
- end
44
+ get_token 'pos'
53
45
  response
54
46
  end
55
47
 
@@ -61,13 +53,13 @@ module BitPay
61
53
 
62
54
  def get_public_invoice(id:)
63
55
  request = Net::HTTP::Get.new("/invoices/#{id}")
64
- response = @https.request request
65
- (JSON.parse response.body)["data"]
56
+ response = process_request(request)
57
+ response["data"]
66
58
  end
67
59
 
68
60
  ## Generates REST request to api endpoint
69
61
  def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
70
- token ||= @tokens[facade] || raise(BitPayError, "No token for specified facade: #{facade}")
62
+ token ||= get_token(facade)
71
63
 
72
64
  # Verb-specific logic
73
65
  case verb.upcase
@@ -95,18 +87,35 @@ module BitPay
95
87
  end
96
88
 
97
89
  # Build request headers and submit
98
- request['User-Agent'] = @user_agent
99
- request['Content-Type'] = 'application/json'
100
- request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
101
90
  request['X-Identity'] = @pub_key
102
91
 
103
- response = @https.request request
104
- JSON.parse response.body
92
+ response = process_request(request)
105
93
  end
106
94
 
107
95
  ##### PRIVATE METHODS #####
108
96
  private
109
97
 
98
+ ## Processes HTTP Request and returns parsed response
99
+ # Otherwise throws error
100
+ #
101
+ def process_request(request)
102
+
103
+ request['User-Agent'] = @user_agent
104
+ request['Content-Type'] = 'application/json'
105
+ request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
106
+
107
+ response = @https.request request
108
+
109
+ if response.kind_of? Net::HTTPSuccess
110
+ return JSON.parse(response.body)
111
+ elsif JSON.parse(response.body)["error"]
112
+ raise(BitPayError, "#{response.code}: #{JSON.parse(response.body)['error']}")
113
+ else
114
+ raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
115
+ end
116
+
117
+ end
118
+
110
119
  ## Requests token by appending nonce and signing URL
111
120
  # Returns a hash of available tokens
112
121
  #
@@ -115,15 +124,12 @@ module BitPay
115
124
  urlpath = '/tokens?nonce=' + KeyUtils.nonce
116
125
 
117
126
  request = Net::HTTP::Get.new(urlpath)
118
- request['content-type'] = "application/json"
119
- request['user-agent'] = @user_agent
120
127
  request['x-identity'] = @pub_key
121
128
  request['x-signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
122
129
 
123
- response = @https.request request
130
+ response = process_request(request)
124
131
 
125
- # /tokens returns an array of hashes. Let's turn it into a more useful single hash
126
- token_array = JSON.parse(response.body)["data"] || {}
132
+ token_array = response["data"] || {}
127
133
 
128
134
  tokens = {}
129
135
  token_array.each do |t|
@@ -143,10 +149,7 @@ module BitPay
143
149
  params[:guid] = SecureRandom.uuid
144
150
  params[:id] = @client_id
145
151
  request.body = params.to_json
146
- request['User-Agent'] = @user_agent
147
- request['Content-Type'] = 'application/json'
148
- request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
149
- @https.request request
152
+ process_request(request)
150
153
  end
151
154
 
152
155
  def get_token(facade)
@@ -85,7 +85,7 @@ module BitPay
85
85
  # hence the requirement to use [].pack("H*") to convert to binary for each step
86
86
 
87
87
  #Generate Private Key
88
- key = pem.nil? ? get_local_pem_file : OpenSSL::PKey::EC.new(pem)
88
+ key = OpenSSL::PKey::EC.new(pem ||= get_local_pem_file)
89
89
  key.public_key.group.point_conversion_form = :compressed
90
90
  public_key = key.public_key.to_bn.to_s(2)
91
91
  step_one = Digest::SHA256.hexdigest(public_key)
@@ -3,5 +3,5 @@
3
3
  # or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
4
4
 
5
5
  module BitPay
6
- VERSION = '2.0.0'
6
+ VERSION = '2.0.1'
7
7
  end
@@ -53,13 +53,13 @@ describe BitPay::Client do
53
53
  it 'throws a BitPayError with the error message if the token setting fails' do
54
54
  stub_const('ENV', {'BITPAY_PEM' => PEM})
55
55
  stub_request(:any, /#{BitPay::TEST_API_URI}.*/).to_return(status: 500, body: "{\n \"error\": \"Unable to create token\"\n}")
56
- expect { bitpay_client.pair_pos_client(:claim_code) }.to raise_error(BitPay::BitPayError, 'Unable to create token')
56
+ expect { bitpay_client.pair_pos_client(:claim_code) }.to raise_error(BitPay::BitPayError, '500: Unable to create token')
57
57
  end
58
58
 
59
59
  it 'gracefully handles 4xx errors' do
60
60
  stub_const('ENV', {'BITPAY_PEM' => PEM})
61
61
  stub_request(:any, /#{BitPay::TEST_API_URI}.*/).to_return(status: 403, body: "{\n \"error\": \"this is a 403 error\"\n}")
62
- expect { bitpay_client.pair_pos_client(:claim_code) }.to raise_error(BitPay::BitPayError, '403: {"error"=>"this is a 403 error"}')
62
+ expect { bitpay_client.pair_pos_client(:claim_code) }.to raise_error(BitPay::BitPayError, '403: this is a 403 error')
63
63
  end
64
64
  end
65
65
 
@@ -73,6 +73,11 @@ describe BitPay::Client do
73
73
  bitpay_client.create_invoice(id: "addd", price: 20, currency: "USD")
74
74
  assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
75
75
  end
76
+
77
+ it 'should pass through the API error message from load_tokens' do
78
+ stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(status: 500, body: '{"error": "load_tokens_error"}')
79
+ expect { bitpay_client.create_invoice(id: "addd", price: 20, currency: "USD") }.to raise_error(BitPay::BitPayError, '500: load_tokens_error')
80
+ end
76
81
  end
77
82
  end
78
83
 
@@ -9,7 +9,9 @@ describe "pairing a token", javascript: true, type: :feature do
9
9
  click_button('loginButton')
10
10
  click_link "My Account"
11
11
  click_link "API Tokens", match: :first
12
- find(".token-access-new-button").find(".btn").click
12
+ find(".token-access-new-button").find(".btn").find(".icon-plus").click
13
+ sleep 0.25
14
+ click_button("Add Token")
13
15
  find(".token-claimcode", match: :first).text
14
16
  end
15
17
  let(:pem) { BitPay::KeyUtils.generate_pem }
@@ -12,10 +12,11 @@ describe "create an invoice", javascript: true, type: :feature do
12
12
  click_link "My Account"
13
13
  click_link "API Tokens", match: :first
14
14
  find(".token-access-new-button").find(".btn").click
15
+ sleep 0.25
16
+ click_button("Add Token")
15
17
  find(".token-claimcode", match: :first).text
16
18
  }
17
19
  set_client = -> {
18
- private_key = BitPay::KeyUtils.get_private_key_from_pem PEM
19
20
  client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: PEM, insecure: true)
20
21
  client.pair_pos_client(get_claim_code.call)
21
22
  client
@@ -20,8 +20,8 @@ describe BitPay::KeyUtils do
20
20
  describe '.generate_pem' do
21
21
  it 'should write a new key to ~/.bitpay/bitpay.pem' do
22
22
  file = class_double("File").as_stubbed_const
23
- double = double("Object").as_null_object
24
- allow(file).to receive(:path).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(double)
23
+ fileutils = class_double("FileUtils").as_stubbed_const
24
+ allow(fileutils).to receive(:mkdir_p).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(nil)
25
25
  expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
26
26
  key_utils.generate_pem
27
27
  end
@@ -31,17 +31,17 @@ describe BitPay::KeyUtils do
31
31
  describe '.retrieve_or_generate_pem' do
32
32
  it 'should write a new key to ~/.bitpay/bitpay.pem if there is no existing file' do
33
33
  file = class_double("File").as_stubbed_const
34
- double = double("Object").as_null_object
34
+ fileutils = class_double("FileUtils").as_stubbed_const
35
35
  allow(file).to receive(:read).with(BitPay::PRIVATE_KEY_PATH).and_throw(StandardError)
36
- allow(file).to receive(:path).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(double)
36
+ allow(fileutils).to receive(:mkdir_p).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(nil)
37
37
  expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
38
38
  key_utils.retrieve_or_generate_pem
39
39
  end
40
40
 
41
41
  it 'should retrieve the pem if there is an existing file' do
42
42
  file = class_double("File").as_stubbed_const
43
- double = double("Object").as_null_object
44
- allow(file).to receive(:path).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(double)
43
+ fileutils = class_double("FileUtils").as_stubbed_const
44
+ allow(fileutils).to receive(:mkdir_p).with(BitPay::BITPAY_CREDENTIALS_DIR).and_return(nil)
45
45
  expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
46
46
  key_utils.generate_pem
47
47
  end
@@ -60,11 +60,17 @@ describe BitPay::KeyUtils do
60
60
 
61
61
  describe '.generate_sin_from_pem' do
62
62
  let(:pem){PEM}
63
- let(:sin){"TeyN4LPrXiG5t2yuSamKqP3ynVk3F52iHrX"}
63
+ let(:sin){CLIENT_ID}
64
64
 
65
65
  it 'will return the right sin for the right pem' do
66
66
  expect(key_utils.generate_sin_from_pem(pem)).to eq sin
67
67
  end
68
+
69
+ it 'will retrieve the locally stored PEM if one is not provided' do
70
+ allow(File).to receive(:read).with(BitPay::PRIVATE_KEY_PATH) {PEM}
71
+ expect(key_utils.generate_sin_from_pem(nil)).to eq sin
72
+ end
73
+
68
74
  end
69
75
 
70
76
  context "errors when priv_key is not provided" do
@@ -15,7 +15,7 @@ require_relative '../config/capybara.rb'
15
15
  PEM = "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEICg7E4NN53YkaWuAwpoqjfAofjzKI7Jq1f532dX+0O6QoAcGBSuBBAAK\noUQDQgAEjZcNa6Kdz6GQwXcUD9iJ+t1tJZCx7hpqBuJV2/IrQBfue8jh8H7Q/4vX\nfAArmNMaGotTpjdnymWlMfszzXJhlw==\n-----END EC PRIVATE KEY-----\n"
16
16
 
17
17
  PUB_KEY = '038d970d6ba29dcfa190c177140fd889fadd6d2590b1ee1a6a06e255dbf22b4017'
18
- CLIENT_ID = "TfFVQhy2hQvchv4VVG4c7j4XPa2viJ9HrR8"
18
+ CLIENT_ID = "TeyN4LPrXiG5t2yuSamKqP3ynVk3F52iHrX"
19
19
 
20
20
 
21
21
  RSpec.configure do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitpay-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bitpay, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-08 00:00:00.000000000 Z
11
+ date: 2014-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json