bitpay-client 2.0.1 → 2.2.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/README.md +1 -1
- data/Rakefile +38 -16
- data/bin/bitpay +1 -1
- data/bitpay-client.gemspec +15 -13
- data/config/constants.rb +2 -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 +73 -0
- data/lib/bitpay/cli.rb +1 -0
- data/lib/bitpay/cli_client.rb +24 -0
- data/lib/bitpay/cli_key_utils.rb +40 -0
- data/lib/bitpay/version.rb +1 -1
- data/lib/bitpay.rb +6 -19
- data/spec/client_spec.rb +48 -22
- data/spec/features/pair_spec.rb +11 -9
- data/spec/features/pos_spec.rb +1 -1
- data/spec/key_utils_spec.rb +0 -61
- data/spec/spec_helper.rb +14 -3
- metadata +90 -58
- data/lib/bitpay/client.rb +0 -160
- data/lib/bitpay/key_utils.rb +0 -143
- data/lib/harness.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4dc42cd2a385367410f051b9a7def43a3ff3021
|
4
|
+
data.tar.gz: c6bd1df8c6e5d47deb49afae0ca2caf0c376f6d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cb61d057cae19d839dc050028c196256c0837e0f64424985aef98df2dd5d3dd6563c3222b5dd7e0310b1931359916c9ce6c178cab0c30f692fdeac72d82ef6b
|
7
|
+
data.tar.gz: 0e326cd00defdeeb8bae777cc42c5189155683aac1be108dcf05801b84dc5f4bab47d8554da6103ecb35514ec51f2c6033c0bc6c06a15a8aadcc75dcbe410aaa
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# BitPay Library for Ruby [](http://travis-ci.org/bitpay/ruby-cli)
|
2
2
|
Powerful, flexible, lightweight interface to the BitPay Bitcoin Payment Gateway API.
|
3
3
|
|
4
4
|
## Installation
|
data/Rakefile
CHANGED
@@ -3,6 +3,8 @@ require 'rspec/core/rake_task'
|
|
3
3
|
require 'capybara'
|
4
4
|
require 'capybara/poltergeist'
|
5
5
|
require 'mongo'
|
6
|
+
require 'cucumber'
|
7
|
+
require 'cucumber/rake/task'
|
6
8
|
|
7
9
|
require_relative 'config/constants.rb'
|
8
10
|
require_relative 'config/capybara.rb'
|
@@ -11,32 +13,24 @@ RSpec::Core::RakeTask.new(:spec)
|
|
11
13
|
|
12
14
|
task :default => :spec
|
13
15
|
|
16
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
17
|
+
t.cucumber_opts = "features --format pretty"
|
18
|
+
end
|
19
|
+
|
14
20
|
desc "Bitpay Tasks"
|
15
21
|
namespace :bitpay do
|
16
22
|
|
17
23
|
desc "Clear all claim codes from the test server."
|
18
24
|
task :clear_claim_codes do
|
19
25
|
puts "clearing claim codes"
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
Capybara.click_button('loginButton')
|
25
|
-
Capybara.click_link "My Account"
|
26
|
-
Capybara.click_link "API Tokens", match: :first
|
27
|
-
while Capybara.page.has_selector?(".token-claimcode") || Capybara.page.has_selector?(".token-requiredsins-key") do
|
28
|
-
Capybara.page.find(".api-manager-actions-edit", match: :first).click
|
29
|
-
Capybara.page.find(".api-manager-actions-revoke", match: :first).click
|
30
|
-
Capybara.click_button("Confirm Revoke")
|
31
|
-
# this back and forth bit is here because no other reload mechanism worked, and without it the task errors out: either because it can't find the revoke button or it finds multiple elements at each click point
|
32
|
-
Capybara.page.go_back
|
33
|
-
Capybara.click_link "API Tokens", match: :first
|
34
|
-
end
|
26
|
+
client = Mongo::MongoClient.new
|
27
|
+
db = client['bitpay-dev']
|
28
|
+
coll = db['tokenaccesses']
|
29
|
+
coll.remove()
|
35
30
|
puts "claim codes cleared"
|
36
31
|
end
|
37
32
|
|
38
33
|
desc "Clear rate limiters from local mongo host"
|
39
|
-
|
40
34
|
task :clear_rate_limiters do
|
41
35
|
puts "clearing rate limiters"
|
42
36
|
client = Mongo::MongoClient.new
|
@@ -46,7 +40,35 @@ namespace :bitpay do
|
|
46
40
|
puts "rate limiters cleared"
|
47
41
|
end
|
48
42
|
|
43
|
+
desc "Clear local pem and token file"
|
44
|
+
task :clear_local_files do
|
45
|
+
puts "clearing local files"
|
46
|
+
HOME_DIR = File.join(Dir.home, '.bitpay')
|
47
|
+
KEY_FILE = File.join(HOME_DIR, 'bitpay.pem')
|
48
|
+
TOKEN_FILE = File.join(HOME_DIR, 'tokens.json')
|
49
|
+
File.delete(KEY_FILE) if File.file?(KEY_FILE)
|
50
|
+
File.delete(TOKEN_FILE) if File.file?(TOKEN_FILE)
|
51
|
+
puts "local files cleared"
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Clear tokens, rate limiters, and local files."
|
55
|
+
task :clear do
|
56
|
+
["bitpay:clear_local_files", "bitpay:clear_rate_limiters", "bitpay:clear_claim_codes"].each{|task| Rake::Task[task].reenable}
|
57
|
+
["bitpay:clear_local_files", "bitpay:clear_rate_limiters", "bitpay:clear_claim_codes"].each{|task| Rake::Task[task].invoke}
|
58
|
+
end
|
59
|
+
|
49
60
|
desc "Run specs and clear claim codes and rate_limiters."
|
50
61
|
task :spec_clear => ['spec', 'clear_claim_codes', 'clear_rate_limiters']
|
51
62
|
|
63
|
+
desc "Run specs, clear data, run cukes, clear data"
|
64
|
+
task :tests_clear do
|
65
|
+
Rake::Task["bitpay:clear"].invoke
|
66
|
+
Rake::Task["spec"].invoke
|
67
|
+
Rake::Task["bitpay:clear"].reenable
|
68
|
+
Rake::Task["bitpay:clear"].invoke
|
69
|
+
Rake::Task["features"].invoke
|
70
|
+
Rake::Task["bitpay:clear"].reenable
|
71
|
+
Rake::Task["bitpay:clear"].invoke
|
72
|
+
end
|
73
|
+
|
52
74
|
end
|
data/bin/bitpay
CHANGED
data/bitpay-client.gemspec
CHANGED
@@ -17,19 +17,21 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.bindir = 'bin'
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
|
20
|
-
s.add_dependency '
|
21
|
-
s.add_dependency '
|
22
|
-
s.add_dependency '
|
20
|
+
s.add_dependency 'bitpay-sdk', '~>2.1'
|
21
|
+
s.add_dependency 'json', '~> 1.8.1'
|
22
|
+
s.add_dependency 'rack', '~> 1.5.2'
|
23
|
+
s.add_dependency 'ecdsa', '~> 1.2.0'
|
23
24
|
s.add_dependency 'commander'
|
24
25
|
|
25
|
-
s.add_development_dependency 'rake'
|
26
|
-
s.add_development_dependency 'webmock'
|
27
|
-
s.add_development_dependency 'pry'
|
28
|
-
s.add_development_dependency 'pry-byebug'
|
29
|
-
s.add_development_dependency 'pry-rescue'
|
30
|
-
s.add_development_dependency 'capybara'
|
31
|
-
s.add_development_dependency '
|
32
|
-
s.add_development_dependency '
|
33
|
-
s.add_development_dependency '
|
34
|
-
s.add_development_dependency '
|
26
|
+
s.add_development_dependency 'rake', '~> 10.3.2'
|
27
|
+
s.add_development_dependency 'webmock', '~> 1.18.0'
|
28
|
+
s.add_development_dependency 'pry', '~> 0.10.1'
|
29
|
+
s.add_development_dependency 'pry-byebug', '~> 2.0.0'
|
30
|
+
s.add_development_dependency 'pry-rescue', '~> 1.4.1'
|
31
|
+
s.add_development_dependency 'capybara', '~> 2.4.3'
|
32
|
+
s.add_development_dependency 'cucumber', '~> 1.3.17'
|
33
|
+
s.add_development_dependency 'poltergeist', '~> 1.5.1'
|
34
|
+
s.add_development_dependency 'airborne', '~> 0.0.20'
|
35
|
+
s.add_development_dependency 'rspec', '~> 3.1.0'
|
36
|
+
s.add_development_dependency 'mongo', '~> 1.11.1'
|
35
37
|
end
|
data/config/constants.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
Feature: creating an invoice
|
2
|
+
The user won't get any money
|
3
|
+
If they can't
|
4
|
+
Create Invoices
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given the user is authenticated with BitPay
|
8
|
+
|
9
|
+
Scenario Outline: The request is correct
|
10
|
+
When the user creates an invoice for <price> <currency>
|
11
|
+
Then they should recieve an invoice in response for <price> <currency>
|
12
|
+
Examples:
|
13
|
+
| price | currency |
|
14
|
+
| "500.23" | "USD" |
|
15
|
+
| "300.21" | "EUR" |
|
16
|
+
|
17
|
+
Scenario Outline: The invoice contains illegal characters
|
18
|
+
When the user creates an invoice for <price> <currency>
|
19
|
+
Then they will receive a BitPay::ArgumentError matching <message>
|
20
|
+
Examples:
|
21
|
+
| price | currency | message |
|
22
|
+
| "50,023" | "USD" | "Price must be formatted as a float" |
|
23
|
+
| "300.21" | "EaUR" | "Currency is invalid." |
|
24
|
+
| "" | "USD" | "Price must be formatted as a float" |
|
25
|
+
| "Ten" | "USD" | "Price must be formatted as a float" |
|
26
|
+
| "100" | "" | "Currency is invalid." |
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Feature: pairing with bitpay
|
2
|
+
In order to access bitpay
|
3
|
+
It is required that the library
|
4
|
+
Is able to pair successfully
|
5
|
+
|
6
|
+
Scenario: the client has a correct pairing code
|
7
|
+
Given the user pairs with BitPay with a valid pairing code
|
8
|
+
Then the user is paired with BitPay
|
9
|
+
|
10
|
+
Scenario Outline: the client has a bad pairing code
|
11
|
+
Given the user fails to pair with a semantically <valid> code <code>
|
12
|
+
Then they will receive a <error> matching <message>
|
13
|
+
Examples:
|
14
|
+
| valid | code | error | message |
|
15
|
+
| valid | "a1b2c3d" | BitPay::BitPayError | "500: Unable to create token" |
|
16
|
+
| invalid | "a1b2c3d4" | BitPay::ArgumentError | "pairing code is not legal" |
|
17
|
+
|
18
|
+
Scenario: the client has a bad port configuration to a closed port
|
19
|
+
When the fails to pair with BitPay because of an incorrect port
|
20
|
+
Then they will receive a BitPay::ConnectionError matching "Connection refused"
|
21
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
When(/^the user (?:tries to |)creates? an invoice (?:for|without) "(.*?)" (?:or |and |)"(.*?)"$/) do |price, currency|
|
2
|
+
begin
|
3
|
+
@response = @client.create_invoice(price: price, currency: currency)
|
4
|
+
rescue => error
|
5
|
+
@error = error
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Then(/^they should recieve an invoice in response for "(.*?)" "(.*?)"$/) do |price, currency|
|
10
|
+
raise "#{@response['price']} != #{price} or #{@response['currency']} != #{currency}" unless (price == @response['price'].to_s && currency == @response['currency'])
|
11
|
+
end
|
12
|
+
|
13
|
+
Given(/^there is an invalid token$/) do
|
14
|
+
pending # express the regexp above with the code you wish you had
|
15
|
+
end
|
16
|
+
|
17
|
+
Given(/^that a user knows an invoice id$/) do
|
18
|
+
client = new_paired_client
|
19
|
+
@id = (client.create_invoice(price: 100, currency: "USD" ))['id']
|
20
|
+
end
|
21
|
+
|
22
|
+
Then(/^they can retrieve that invoice$/) do
|
23
|
+
invoice = BitPay::Client.new(api_uri: ROOT_ADDRESS, insecure: true).get_public_invoice(id: @id)
|
24
|
+
raise "That's the wrong invoice" unless invoice['id'] == @id
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
@token = nil
|
2
|
+
@error = nil
|
3
|
+
|
4
|
+
When(/^the user pairs with BitPay(?: with a valid pairing code|)$/) do
|
5
|
+
claim_code = get_claim_code_from_server
|
6
|
+
pem = BitPay::KeyUtils.generate_pem
|
7
|
+
@client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
|
8
|
+
@token = @client.pair_pos_client(claim_code)
|
9
|
+
end
|
10
|
+
|
11
|
+
When(/^the fails to pair with BitPay because of an incorrect port$/) do
|
12
|
+
pem = BitPay::KeyUtils.generate_pem
|
13
|
+
address = ROOT_ADDRESS.split(':').slice(0,2).join(':') + ":999"
|
14
|
+
client = BitPay::Client.new(api_uri: address, pem: pem, insecure: true)
|
15
|
+
begin
|
16
|
+
client.pair_pos_client("1ab2c34")
|
17
|
+
raise "pairing unexpectedly worked"
|
18
|
+
rescue => error
|
19
|
+
@error = error
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Given(/^the user is authenticated with BitPay$/) do
|
25
|
+
@client = new_client_from_stored_values
|
26
|
+
end
|
27
|
+
|
28
|
+
Given(/^the user is paired with BitPay$/) do
|
29
|
+
raise "Client is not paired" unless @client.verify_token
|
30
|
+
end
|
31
|
+
|
32
|
+
Given(/^the user has a bad pairing_code "(.*?)"$/) do |arg1|
|
33
|
+
# This is a no-op, pairing codes are transient and never actually saved
|
34
|
+
end
|
35
|
+
|
36
|
+
Then(/^the user fails to pair with a semantically (?:in|)valid code "(.*?)"$/) do |code|
|
37
|
+
pem = BitPay::KeyUtils.generate_pem
|
38
|
+
client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
|
39
|
+
begin
|
40
|
+
client.pair_pos_client(code)
|
41
|
+
raise "pairing unexpectedly worked"
|
42
|
+
rescue => error
|
43
|
+
@error = error
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Then(/^they will receive an? (.*?) matching "(.*?)"$/) do |error_class, error_message|
|
49
|
+
raise "Error: #{@error.class}, message: #{@error.message}" unless Object.const_get(error_class) == @error.class && @error.message.include?(error_message)
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'capybara/poltergeist'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
require File.join File.dirname(__FILE__), '..', '..', 'lib', 'bitpay.rb'
|
5
|
+
require_relative '../../config/constants.rb'
|
6
|
+
require_relative '../../config/capybara.rb'
|
7
|
+
|
8
|
+
#
|
9
|
+
## Test Variables
|
10
|
+
#
|
11
|
+
#PEM = "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEICg7E4NN53YkaWuAwpoqjfAofjzKI7Jq1f532dX+0O6QoAcGBSuBBAAK\noUQDQgAEjZcNa6Kdz6GQwXcUD9iJ+t1tJZCx7hpqBuJV2/IrQBfue8jh8H7Q/4vX\nfAArmNMaGotTpjdnymWlMfszzXJhlw==\n-----END EC PRIVATE KEY-----\n"
|
12
|
+
#
|
13
|
+
#PUB_KEY = '038d970d6ba29dcfa190c177140fd889fadd6d2590b1ee1a6a06e255dbf22b4017'
|
14
|
+
#CLIENT_ID = "TeyN4LPrXiG5t2yuSamKqP3ynVk3F52iHrX"
|
15
|
+
module BitPay
|
16
|
+
# Location for API Credentials
|
17
|
+
BITPAY_CREDENTIALS_DIR = File.join(Dir.home, ".bitpay")
|
18
|
+
PRIVATE_KEY_FILE = 'bitpay.pem'
|
19
|
+
PRIVATE_KEY_PATH = File.join(BITPAY_CREDENTIALS_DIR, PRIVATE_KEY_FILE)
|
20
|
+
TOKEN_FILE = 'tokens.json'
|
21
|
+
TOKEN_FILE_PATH = File.join(BITPAY_CREDENTIALS_DIR, TOKEN_FILE)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_claim_code_from_server
|
25
|
+
Capybara::visit ROOT_ADDRESS
|
26
|
+
if logged_in
|
27
|
+
Capybara::visit "#{ROOT_ADDRESS}/home"
|
28
|
+
else
|
29
|
+
log_in
|
30
|
+
end
|
31
|
+
Capybara::click_link "My Account"
|
32
|
+
Capybara::click_link "API Tokens", match: :first
|
33
|
+
Capybara::find(".token-access-new-button").find(".btn").find(".icon-plus").click
|
34
|
+
sleep 0.25
|
35
|
+
Capybara::find_button("Add Token", match: :first).click
|
36
|
+
Capybara::find(".token-claimcode", match: :first).text
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_in
|
40
|
+
Capybara::click_link('Login')
|
41
|
+
Capybara::fill_in 'email', :with => TEST_USER
|
42
|
+
Capybara::fill_in 'password', :with => TEST_PASS
|
43
|
+
Capybara::click_button('loginButton')
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_paired_client
|
47
|
+
claim_code = get_claim_code_from_server
|
48
|
+
pem = BitPay::KeyUtils.generate_pem
|
49
|
+
client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
|
50
|
+
client.pair_pos_client(claim_code)
|
51
|
+
client
|
52
|
+
end
|
53
|
+
|
54
|
+
def new_client_from_stored_values
|
55
|
+
if File.file?(BitPay::PRIVATE_KEY_PATH) && File.file?(BitPay::TOKEN_FILE_PATH)
|
56
|
+
token = get_token_from_file
|
57
|
+
pem = File.read(BitPay::PRIVATE_KEY_PATH)
|
58
|
+
BitPay::Client.new(pem: pem, tokens: token, insecure: true, api_uri: ROOT_ADDRESS )
|
59
|
+
else
|
60
|
+
claim_code = get_claim_code_from_server
|
61
|
+
client = BitPay::Client.new(api_uri: ROOT_ADDRESS, insecure: true)
|
62
|
+
client.pair_pos_client(claim_code)
|
63
|
+
client
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_token_from_file
|
68
|
+
token = JSON.parse(File.read(BitPay::TOKEN_FILE_PATH))
|
69
|
+
end
|
70
|
+
|
71
|
+
def logged_in
|
72
|
+
Capybara::has_link?('Dashboard')
|
73
|
+
end
|
data/lib/bitpay/cli.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
module BitPay
|
2
|
+
class Client < BitPay::SDK::Client
|
3
|
+
def initialize opts={}
|
4
|
+
pem = File.read(PRIVATE_KEY_PATH) if File.exists?(PRIVATE_KEY_PATH)
|
5
|
+
pem = BitPay::KeyUtils.generate_pem unless File.exists?(PRIVATE_KEY_PATH)
|
6
|
+
pem = opts[:pem] if opts[:pem]
|
7
|
+
File.write(PRIVATE_KEY_PATH, pem)
|
8
|
+
opts[:pem] = pem
|
9
|
+
super opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def pair_pos_client claim_code
|
13
|
+
response = super
|
14
|
+
token = get_token_from_response response
|
15
|
+
File.write(TOKEN_FILE_PATH, token)
|
16
|
+
return response
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def get_token_from_response response
|
21
|
+
({response["data"][0]["facade"] => response["data"][0]["token"]}).to_json
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -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 '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
|
+
## Generates a new private key and writes to local FS
|
18
|
+
#
|
19
|
+
def retrieve_or_generate_pem
|
20
|
+
begin
|
21
|
+
pem = get_local_pem_file
|
22
|
+
rescue
|
23
|
+
pem = generate_pem
|
24
|
+
write_pem_file pem
|
25
|
+
end
|
26
|
+
pem
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_pem_file pem
|
30
|
+
FileUtils.mkdir_p(BITPAY_CREDENTIALS_DIR)
|
31
|
+
File.open(PRIVATE_KEY_PATH, 'w') { |file| file.write(pem) }
|
32
|
+
end
|
33
|
+
## Gets private key from ENV variable or local FS
|
34
|
+
#
|
35
|
+
def get_local_pem_file
|
36
|
+
File.read(PRIVATE_KEY_PATH) || (raise BitPayError, MISSING_KEY)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/bitpay/version.rb
CHANGED
data/lib/bitpay.rb
CHANGED
@@ -4,31 +4,18 @@
|
|
4
4
|
|
5
5
|
libdir = File.dirname(__FILE__)
|
6
6
|
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
7
|
-
require '
|
7
|
+
require 'bitpay_sdk'
|
8
|
+
require 'bitpay/cli_client'
|
9
|
+
require 'bitpay/cli_key_utils'
|
8
10
|
require 'bitpay/version'
|
9
11
|
|
10
12
|
module BitPay
|
11
13
|
|
12
|
-
|
13
|
-
# As sourced from http://curl.haxx.se/ca/cacert.pem
|
14
|
-
CA_FILE = File.join File.dirname(__FILE__), 'bitpay','cacert.pem'
|
15
|
-
|
16
|
-
# Location of API
|
17
|
-
API_URI = 'https://bitpay.com'
|
18
|
-
TEST_API_URI = 'https://test.bitpay.com'
|
19
|
-
CLIENT_REGISTRATION_PATH = '/api-access-request'
|
20
|
-
|
21
|
-
# Location for API Credentials
|
22
|
-
BITPAY_CREDENTIALS_DIR = File.join(Dir.home, ".bitpay")
|
14
|
+
BITPAY_CREDENTIALS_DIR = ENV['RCBITPAYROOT'] || File.expand_path("~") + "/.bitpay/"
|
23
15
|
PRIVATE_KEY_FILE = 'bitpay.pem'
|
24
16
|
PRIVATE_KEY_PATH = File.join(BITPAY_CREDENTIALS_DIR, PRIVATE_KEY_FILE)
|
17
|
+
TOKEN_FILE = 'tokens.json'
|
18
|
+
TOKEN_FILE_PATH = File.join(BITPAY_CREDENTIALS_DIR, TOKEN_FILE)
|
25
19
|
|
26
|
-
# User agent reported to API
|
27
|
-
USER_AGENT = 'ruby-bitpay-client '+VERSION
|
28
|
-
|
29
20
|
MISSING_KEY = 'No Private Key specified. Pass priv_key or set ENV variable PRIV_KEY'
|
30
|
-
MISSING_PEM = 'No pem file specified. Pass pem or set ENV variable BITPAY_PEM'
|
31
|
-
|
32
|
-
class BitPayError < StandardError; end
|
33
|
-
|
34
21
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -11,25 +11,15 @@ end
|
|
11
11
|
|
12
12
|
describe BitPay::Client do
|
13
13
|
let(:bitpay_client) { BitPay::Client.new({api_uri: BitPay::TEST_API_URI}) }
|
14
|
+
let(:claim_code) { "a12bc3d" }
|
14
15
|
|
15
16
|
before do
|
16
17
|
allow(BitPay::KeyUtils).to receive(:nonce).and_return('1')
|
17
18
|
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(:status => 200, :body => tokens.to_json, :headers => {})
|
18
19
|
end
|
19
20
|
|
20
|
-
describe "#initialize" do
|
21
|
-
|
22
|
-
it 'should be able to get pem file from the env' do
|
23
|
-
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
24
|
-
expect {bitpay_client}.to_not raise_error
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
21
|
|
29
22
|
describe "#send_request" do
|
30
|
-
before do
|
31
|
-
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
32
|
-
end
|
33
23
|
|
34
24
|
context "GET" do
|
35
25
|
it 'should generate a get request' do
|
@@ -50,34 +40,70 @@ describe BitPay::Client do
|
|
50
40
|
end
|
51
41
|
|
52
42
|
describe "#pair_pos_client" do
|
53
|
-
|
43
|
+
before do
|
54
44
|
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'throws a BitPayError with the error message if the token setting fails' do
|
55
48
|
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(
|
49
|
+
expect { bitpay_client.pair_pos_client(claim_code) }.to raise_error(BitPay::BitPayError, '500: Unable to create token')
|
57
50
|
end
|
58
51
|
|
59
52
|
it 'gracefully handles 4xx errors' do
|
60
|
-
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
61
53
|
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(
|
54
|
+
expect { bitpay_client.pair_pos_client(claim_code) }.to raise_error(BitPay::BitPayError, '403: this is a 403 error')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'short circuits on invalid pairing codes' do
|
58
|
+
100.times do
|
59
|
+
claim_code = an_illegal_claim_code
|
60
|
+
expect{bitpay_client.pair_pos_client(claim_code)}.to raise_error BitPay::ArgumentError, "pairing code is not legal"
|
61
|
+
end
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
66
65
|
describe "#create_invoice" do
|
67
66
|
subject { bitpay_client }
|
68
|
-
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
69
67
|
it { is_expected.to respond_to(:create_invoice) }
|
70
68
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
describe "should make the call to the server to create an invoice" do
|
70
|
+
it 'allows numeric input for the price' do
|
71
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
72
|
+
bitpay_client.create_invoice(price: 20.00, currency: "USD")
|
73
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'allows string input for the price' do
|
77
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
78
|
+
bitpay_client.create_invoice(price: "20.00", currency: "USD")
|
79
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
80
|
+
end
|
75
81
|
end
|
76
82
|
|
77
83
|
it 'should pass through the API error message from load_tokens' do
|
78
84
|
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(status: 500, body: '{"error": "load_tokens_error"}')
|
79
|
-
expect { bitpay_client.create_invoice(
|
85
|
+
expect { bitpay_client.create_invoice(price: 20, currency: "USD") }.to raise_error(BitPay::BitPayError, '500: load_tokens_error')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'verifies the validity of the price argument' do
|
89
|
+
expect { bitpay_client.create_invoice(price: "3,999", currency: "USD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Price must be formatted as a float')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'verifies the validity of the currency argument' do
|
93
|
+
expect { bitpay_client.create_invoice(price: "3999", currency: "UASD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Currency is invalid.')
|
80
94
|
end
|
81
95
|
end
|
82
|
-
end
|
83
96
|
|
97
|
+
describe '#set_token' do
|
98
|
+
subject { bitpay_client }
|
99
|
+
it { is_expected.to respond_to(:set_token) }
|
100
|
+
it 'sets a token in the client' do
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#verify_token" do
|
106
|
+
subject { bitpay_client }
|
107
|
+
it { is_expected.to respond_to(:verify_token) }
|
108
|
+
end
|
109
|
+
end
|
data/spec/features/pair_spec.rb
CHANGED
@@ -14,17 +14,19 @@ describe "pairing a token", javascript: true, type: :feature do
|
|
14
14
|
click_button("Add Token")
|
15
15
|
find(".token-claimcode", match: :first).text
|
16
16
|
end
|
17
|
-
|
18
|
-
|
17
|
+
context "when no pem file exists" do
|
18
|
+
before do
|
19
|
+
File.delete(BitPay::PRIVATE_KEY_PATH) if File.exists?(BitPay::PRIVATE_KEY_PATH)
|
20
|
+
File.delete(BitPay::TOKEN_FILE) if File.exists?(BitPay::TOKEN_FILE)
|
21
|
+
`./bin/bitpay pair #{claimCode} --insecure #{ROOT_ADDRESS}`
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
expect(client.instance_variable_get(:@tokens)).to be_empty
|
24
|
+
it "should save a pem file when pairing" do
|
25
|
+
expect(File.exists?(BitPay::PRIVATE_KEY_PATH)).to eq true
|
23
26
|
end
|
24
|
-
|
25
|
-
|
26
|
-
expect(
|
27
|
+
|
28
|
+
it "should save a token when pairing" do
|
29
|
+
expect(JSON.parse(File.read(BitPay::TOKEN_FILE_PATH))["pos"]).to_not be_nil
|
27
30
|
end
|
28
31
|
end
|
29
|
-
|
30
32
|
end
|
data/spec/features/pos_spec.rb
CHANGED
@@ -24,7 +24,7 @@ describe "create an invoice", javascript: true, type: :feature do
|
|
24
24
|
@client ||= set_client.call
|
25
25
|
@invoice_id ||= SecureRandom.uuid
|
26
26
|
@price ||= (100..150).to_a.sample
|
27
|
-
@invoice = @client.create_invoice(
|
27
|
+
@invoice = @client.create_invoice(currency: "USD", price: @price)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should create an invoice" do
|