bitpay-client 0.1.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 439da2df3cd970909db7dc7adf7591f1a689935a
4
- data.tar.gz: 3d41a7739c173d85c865eadcd75d9516f168cfd0
3
+ metadata.gz: e8c99b683ba6a20ac1e7a0739e29a654d1976cae
4
+ data.tar.gz: ba0aeebf8fdbec667e0bf76500e194eb549ab25f
5
5
  SHA512:
6
- metadata.gz: d045eedd20a55ccca430e50554c838c317f19ad2213c92244836b9c905cbd94eb9cead436f4acf92f5bf0a82bdc0e25fa04415fdc4818a3072eb2cab44b484db
7
- data.tar.gz: c898022563684a77ff956fde35a3424aec50db41b59b63c3c5cdde3dd8280ba5e30dee21f43983c07b909c4f21ea6ed5c7996f782e690671a712e71c74f22c71
6
+ metadata.gz: 3def8a32c76c98d4c43ece8785641cd8499d48bf5ce93525c67c1a6a48c0238ebc07964ae938e9144a671b28b13d3efc44c10c7cfded72dc5aa4dbf0564e7ba6
7
+ data.tar.gz: 11e62b62bbe443fb1d8a7f8ffbcbda5218ec64263dec0605444f2490193a1346bccd756003a8c0cee7827edd3d699bba55e2833c4c634e446dcebe34a3865566
data/.gitignore CHANGED
@@ -2,3 +2,6 @@
2
2
  test.rb
3
3
  Gemfile.lock
4
4
  pkg
5
+ .c9
6
+ .ruby-version
7
+ .ruby-gemset
@@ -1,5 +1,2 @@
1
1
  rvm:
2
- - 1.9.2
3
- - 1.9.3
4
- - 2.0.0
5
2
  - 2.1.0
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2013 BitPay
1
+ Copyright (C) 2014 BitPay
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
data/README.md CHANGED
@@ -13,12 +13,26 @@ Or directly:
13
13
 
14
14
  require 'bitpay'
15
15
 
16
+ ## Configuration
17
+
18
+ The bitpay client creates a cryptographically secure connection to your server by pairing an API code with keys stored on your server. The library generates the keys as a .pem file, which is stored in `$HOME/.bitpay/bitpay.pem` or preferentially in an environment variable.
19
+
20
+ The client will generate a key when initialized if one does not already exist.
21
+
16
22
  ## Basic Usage
17
23
 
18
- To create an invoice:
24
+ ### Pairing with Bitpay.com
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>`
31
+
32
+ ### To create an invoice with a paired client:
19
33
 
20
- client = BitPay::Client.new 'YOUR_API_KEY'
21
- invoice = client.post 'invoice', {:price => 10.00, :currency => 'USD'}
34
+ client = BitPay::Client.new
35
+ invoice = client.create_invoice (id: <id>, price: <price>, currency: <currency>, facade: <facade>)
22
36
 
23
37
  With invoice creation, `price` and `currency` are the only required fields. If you are sending a customer from your website to make a purchase, setting `redirectURL` will redirect the customer to your website when the invoice is paid.
24
38
 
@@ -40,7 +54,7 @@ There are many options available when creating invoices, which are listed in the
40
54
 
41
55
  To get updated information on this invoice, make a get call with the id returned:
42
56
 
43
- invoice = client.get 'invoice/DGrAEmbsXe9bavBPMJ8kuk'
57
+ invoice = client.get_public_invoice(DGrAEmbsXe9bavBPMJ8kuk)'
44
58
 
45
59
  ## Testnet Usage
46
60
 
@@ -48,11 +62,11 @@ During development and testing, take advantage of the [Bitcoin TestNet](https://
48
62
 
49
63
  BitPay::Client.new("myAPIKey", {api_uri: "https://test.bitpay.com/api"})
50
64
 
51
- Note that you will need a separate API key for `test.bitpay.com` which can be obtained by registering for a test account at https://test.bitpay.com/start
65
+ Note that in order to pair with testnet, you will need a pairing code from test.bitpay.com and will need to use the bitpay client with the --test option.
52
66
 
53
67
  ## API Documentation
54
68
 
55
- API Documentation is available on the [BitPay site](https://bitpay.com/bitcoin-payment-gateway-api).
69
+ API Documentation is available on the [BitPay site](https://bitpay.com/api).
56
70
 
57
71
  ## RDoc/YARD Documentation
58
72
  The code has been fully code documented, and the latest version is always available at the [Rubydoc Site](http://rubydoc.info/gems/bitpay-client).
data/Rakefile CHANGED
@@ -1,11 +1,52 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require 'rspec/core/rake_task'
3
+ require 'capybara'
4
+ require 'capybara/poltergeist'
5
+ require 'mongo'
3
6
 
4
- desc "Run all tests"
5
- Rake::TestTask.new do |t|
6
- t.libs << "spec"
7
- t.test_files = FileList['test/*_test.rb','test/bitpay/*_test.rb']
8
- t.verbose = true
9
- end
7
+ require_relative 'config/constants.rb'
8
+ require_relative 'config/capybara.rb'
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task :default => :spec
13
+
14
+ desc "Bitpay Tasks"
15
+ namespace :bitpay do
16
+
17
+ desc "Clear all claim codes from the test server."
18
+ task :clear_claim_codes do
19
+ puts "clearing claim codes"
20
+ Capybara.visit ROOT_ADDRESS
21
+ Capybara.click_link('Login')
22
+ Capybara.fill_in 'email', :with => TEST_USER
23
+ Capybara.fill_in 'password', :with => TEST_PASS
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
35
+ puts "claim codes cleared"
36
+ end
10
37
 
11
- task :default => :test
38
+ desc "Clear rate limiters from local mongo host"
39
+
40
+ task :clear_rate_limiters do
41
+ puts "clearing rate limiters"
42
+ client = Mongo::MongoClient.new
43
+ db = client['bitpay-dev']
44
+ coll = db['ratelimiters']
45
+ coll.remove()
46
+ puts "rate limiters cleared"
47
+ end
48
+
49
+ desc "Run specs and clear claim codes and rate_limiters."
50
+ task :spec_clear => ['spec', 'clear_claim_codes', 'clear_rate_limiters']
51
+
52
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/bitpay'
3
+ require_relative '../lib/bitpay/cli'
@@ -2,6 +2,7 @@ require './lib/bitpay/version.rb'
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'bitpay-client'
4
4
  s.version = BitPay::VERSION
5
+ s.licenses = ['MIT']
5
6
  s.authors = 'Bitpay, Inc.'
6
7
  s.email = 'info@bitpay.com'
7
8
  s.homepage = 'https://github.com/bitpay/ruby-client'
@@ -9,15 +10,26 @@ Gem::Specification.new do |s|
9
10
  s.description = 'Powerful, flexible, lightweight, thread-safe interface to the BitPay developers API'
10
11
 
11
12
  s.files = `git ls-files`.split("\n")
12
- s.require_paths = %w[lib]
13
+ s.require_paths = ["lib"]
13
14
  s.rubyforge_project = s.name
14
15
  s.required_rubygems_version = '>= 1.3.4'
16
+ s.required_ruby_version = '~> 2.1'
17
+ s.bindir = 'bin'
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
19
 
16
20
  s.add_dependency 'json'
17
21
  s.add_dependency 'rack', '>= 0'
22
+ s.add_dependency 'ecdsa'
23
+ s.add_dependency 'commander'
18
24
 
19
25
  s.add_development_dependency 'rake'
20
- s.add_development_dependency 'minitest'
21
26
  s.add_development_dependency 'webmock'
22
- s.add_development_dependency 'yard'
23
- end
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 'poltergeist'
32
+ s.add_development_dependency 'airborne'
33
+ s.add_development_dependency 'rspec'
34
+ s.add_development_dependency 'mongo'
35
+ end
@@ -0,0 +1,5 @@
1
+ Capybara.javascript_driver = :poltergeist
2
+ Capybara.default_driver = :poltergeist
3
+ Capybara.register_driver :poltergeist do |app|
4
+ Capybara::Poltergeist::Driver.new(app, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes'])
5
+ end
@@ -0,0 +1,3 @@
1
+ ROOT_ADDRESS = ENV['RCROOTADDRESS']
2
+ TEST_USER = ENV['RCTESTUSER']
3
+ TEST_PASS = ENV['RCTESTPASSWORD']
@@ -1,3 +1,7 @@
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
+
1
5
  libdir = File.dirname(__FILE__)
2
6
  $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
7
  require 'bitpay/client'
@@ -10,8 +14,21 @@ module BitPay
10
14
  CA_FILE = File.join File.dirname(__FILE__), 'bitpay','cacert.pem'
11
15
 
12
16
  # Location of API
13
- API_URI = 'https://bitpay.com/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")
23
+ PRIVATE_KEY_FILE = 'bitpay.pem'
24
+ PRIVATE_KEY_PATH = File.join(BITPAY_CREDENTIALS_DIR, PRIVATE_KEY_FILE)
14
25
 
15
26
  # User agent reported to API
16
27
  USER_AGENT = 'ruby-bitpay-client '+VERSION
28
+
29
+ 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
+
17
34
  end
@@ -0,0 +1,63 @@
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 'rubygems'
6
+ require 'commander/import'
7
+
8
+ program :name, 'BitPay Ruby Library CLI'
9
+ program :version, BitPay::VERSION
10
+ program :description, 'Official BitPay Ruby API Client. Use to securely register your client with the BitPay API endpoint. '
11
+ program :help_formatter, :compact
12
+
13
+ command :pair do |c|
14
+ c.syntax = 'bitpay pair <code>'
15
+ c.summary = "Pair the local keys to a bitpay account."
16
+ c.option '--test', "Use the bitpay test server"
17
+ c.option '--custom <custom>', "Use a custom bitpay URI"
18
+ c.option '--insecure <insecure>', "Use an insecure custom bitpay URI"
19
+ c.action do |args, options|
20
+ raise ArgumentError, "Pairing failed, please call argument as 'bitpay pair <code> [options]'" unless args.first
21
+ case
22
+ when options.test
23
+ client = BitPay::Client.new(api_uri: "https://test.bitpay.com")
24
+ message = "Paired with test.bitpay.com"
25
+ when options.custom
26
+ client = BitPay::Client.new(api_uri: options.custom)
27
+ message = "Paired with #{options.custom}"
28
+ when options.insecure
29
+ client = BitPay::Client.new(insecure: true, api_uri: options.insecure)
30
+ message = "Paired with #{options.insecure}"
31
+ else
32
+ client = BitPay::Client.new
33
+ message = "Paired with bitpay.com"
34
+ end
35
+
36
+ begin
37
+ client.pair_pos_client args.first
38
+ puts message
39
+ rescue Exception => e
40
+ puts e.message
41
+ end
42
+ end
43
+ end
44
+
45
+ command :show_keys do |c|
46
+ c.syntax = 'bitpay show_keys'
47
+ c.summary = "Read current environment's key information to STDOUT"
48
+ c.description = ''
49
+ c.example 'description', 'command example'
50
+ c.action do |args, options|
51
+
52
+ pem = BitPay::KeyUtils.get_local_pem_file
53
+ private_key = BitPay::KeyUtils.get_private_key_from_pem pem
54
+ public_key = BitPay::KeyUtils.get_public_key_from_pem pem
55
+ client_id = BitPay::KeyUtils.generate_sin_from_pem pem
56
+
57
+ puts "Current BitPay Client Keys:\n"
58
+ puts "Private Key: #{private_key}"
59
+ puts "Public Key: #{public_key}"
60
+ puts "Client ID: #{client_id}"
61
+
62
+ end
63
+ end
@@ -1,73 +1,157 @@
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
+
1
5
  require 'uri'
2
6
  require 'net/https'
3
7
  require 'json'
4
8
 
9
+ require_relative 'key_utils'
10
+
5
11
  module BitPay
6
12
  # This class is used to instantiate a BitPay Client object. It is expected to be thread safe.
7
13
  #
8
- # @example
9
- # # Create a client with your BitPay API key (obtained from the BitPay API access page at BitPay.com):
10
- # client = BitPay::Client.new 'YOUR_API_KEY'
11
14
  class Client
12
- class BitPayError < StandardError; end
15
+
13
16
 
14
- # Creates a BitPay Client object. The second parameter is a hash for overriding defaults.
15
- #
16
17
  # @return [Client]
17
18
  # @example
18
- # # Create a client with your BitPay API key (obtained from the BitPay API access page at BitPay.com):
19
- # client = BitPay::Client.new 'YOUR_API_KEY'
20
- def initialize(api_key, opts={})
21
- @api_key = api_key
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.retrieve_or_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
22
27
  @uri = URI.parse opts[:api_uri] || API_URI
28
+ @user_agent = opts[:user_agent] || USER_AGENT
23
29
  @https = Net::HTTP.new @uri.host, @uri.port
24
30
  @https.use_ssl = true
25
31
  @https.ca_file = CA_FILE
26
32
 
27
-
28
33
  # Option to disable certificate validation in extraordinary circumstance. NOT recommended for production use
29
34
  @https.verify_mode = opts[:insecure] == true ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
35
+
36
+ # Option to enable http request debugging
37
+ @https.set_debug_output($stdout) if opts[:debug] == true
30
38
 
39
+ # Load all the available tokens into @tokens
40
+ load_tokens
31
41
  end
32
42
 
33
- # Makes a GET call to the BitPay API.
34
- # @return [Hash]
35
- # @see get_invoice
36
- # @example
37
- # # Get an invoice:
38
- # existing_invoice = client.get 'invoice/YOUR_INVOICE_ID'
39
- def get(path)
40
- request(Net::HTTP::Get, path)
43
+ def pair_pos_client(claimCode)
44
+ 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
53
+ response
41
54
  end
42
55
 
43
- # Makes a POST call to the BitPay API.
44
- # @return [Hash]
45
- # @see create_invoice
46
- # # Create an invoice:
47
- # created_invoice = client.post 'invoice', {:price => 1.45, :currency => 'BTC'}
48
- def post(path, params={})
49
- request(Net::HTTP::Post, path, params)
56
+ def create_invoice(id:, price:, currency:, facade: 'pos', params:{})
57
+ params.merge!({price: price, currency: currency})
58
+ response = send_request("POST", "invoices", facade: facade, params: params)
59
+ response["data"]
50
60
  end
51
61
 
52
- private
62
+ def get_public_invoice(id:)
63
+ request = Net::HTTP::Get.new("/invoices/#{id}")
64
+ response = @https.request request
65
+ (JSON.parse response.body)["data"]
66
+ end
67
+
68
+ ## Generates REST request to api endpoint
69
+ def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
70
+ token ||= @tokens[facade] || raise(BitPayError, "No token for specified facade: #{facade}")
53
71
 
54
- def request(request_klass, path, params=nil)
55
- request = make_request(request_klass, path, params)
56
- response = @https.request(request)
57
- raise BitPayError, "HTTP Status " + response.code + " with body: " + response.body unless response.kind_of?(Net::HTTPSuccess)
58
- return JSON.parse(response.body)
59
- rescue => e
60
- fail BitPayError, "Bitpay Request Error: #{e}"
72
+ # Verb-specific logic
73
+ case verb.upcase
74
+ when "GET"
75
+ urlpath = '/' + path + '?nonce=' + KeyUtils.nonce + '&token=' + token
76
+ request = Net::HTTP::Get.new urlpath
77
+ request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
78
+
79
+ when "PUT"
80
+
81
+ when "POST" # Requires a GUID
82
+
83
+ urlpath = '/' + path
84
+ request = Net::HTTP::Post.new urlpath
85
+ params[:token] = token
86
+ params[:nonce] = KeyUtils.nonce
87
+ params[:guid] = SecureRandom.uuid
88
+ params[:id] = @client_id
89
+ request.body = params.to_json
90
+ request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath + request.body, @priv_key)
91
+
92
+ when "DELETE"
93
+
94
+ raise(BitPayError, "Invalid HTTP verb: #{verb.upcase}")
95
+ end
96
+
97
+ # 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
+ request['X-Identity'] = @pub_key
102
+
103
+ response = @https.request request
104
+ JSON.parse response.body
61
105
  end
62
106
 
63
- def make_request(request_klass, path, params)
64
- request_klass.new(@uri.path + '/' + path).tap do |r|
65
- r.basic_auth @api_key, ''
66
- r['User-Agent'] = USER_AGENT
67
- r['Content-Type'] = 'application/json'
68
- r['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
69
- r.body = params.to_json if params
107
+ ##### PRIVATE METHODS #####
108
+ private
109
+
110
+ ## Requests token by appending nonce and signing URL
111
+ # Returns a hash of available tokens
112
+ #
113
+ def load_tokens
114
+
115
+ urlpath = '/tokens?nonce=' + KeyUtils.nonce
116
+
117
+ request = Net::HTTP::Get.new(urlpath)
118
+ request['content-type'] = "application/json"
119
+ request['user-agent'] = @user_agent
120
+ request['x-identity'] = @pub_key
121
+ request['x-signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
122
+
123
+ response = @https.request request
124
+
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"] || {}
127
+
128
+ tokens = {}
129
+ token_array.each do |t|
130
+ tokens[t.keys.first] = t.values.first
70
131
  end
132
+
133
+ @tokens = tokens
134
+ return tokens
135
+
136
+ end
137
+
138
+ ## Retrieves specified token from hash, otherwise tries to refresh @tokens and retry
139
+ def set_pos_token(claim_code)
140
+ params = {pairingCode: claim_code}
141
+ urlpath = '/tokens'
142
+ request = Net::HTTP::Post.new urlpath
143
+ params[:guid] = SecureRandom.uuid
144
+ params[:id] = @client_id
145
+ 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
71
150
  end
151
+
152
+ def get_token(facade)
153
+ token = @tokens[facade] || load_tokens[facade] || raise(BitPayError, "Not authorized for facade: #{facade}")
154
+ end
155
+
72
156
  end
73
157
  end
@@ -0,0 +1,143 @@
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 and writes to local FS
22
+ #
23
+ def retrieve_or_generate_pem
24
+ begin
25
+ pem = get_local_pem_file
26
+ rescue
27
+ pem = generate_pem
28
+ end
29
+ pem
30
+ end
31
+
32
+ def generate_pem
33
+ key = OpenSSL::PKey::EC.new("secp256k1")
34
+ key.generate_key
35
+ write_pem_file(key)
36
+ key.to_pem
37
+ end
38
+
39
+ def create_key pem
40
+ OpenSSL::PKey::EC.new(pem)
41
+ end
42
+
43
+ def create_new_key
44
+ key = OpenSSL::PKey::EC.new("secp256k1")
45
+ key.generate_key
46
+ key
47
+ end
48
+
49
+ def write_pem_file key
50
+ FileUtils.mkdir_p(BITPAY_CREDENTIALS_DIR)
51
+ File.open(PRIVATE_KEY_PATH, 'w') { |file| file.write(key.to_pem) }
52
+ end
53
+ ## Gets private key from ENV variable or local FS
54
+ #
55
+ def get_local_pem_file
56
+ ENV['BITPAY_PEM'] || File.read(PRIVATE_KEY_PATH) || (raise BitPayError, MISSING_KEY)
57
+ end
58
+
59
+ def get_private_key key
60
+ key.private_key.to_int.to_s(16)
61
+ end
62
+
63
+ def get_public_key key
64
+ key.public_key.group.point_conversion_form = :compressed
65
+ key.public_key.to_bn.to_s(16).downcase
66
+ end
67
+
68
+ def get_private_key_from_pem pem
69
+ raise BitPayError, MISSING_KEY unless pem
70
+ key = OpenSSL::PKey::EC.new(pem)
71
+ get_private_key key
72
+ end
73
+
74
+ def get_public_key_from_pem pem
75
+ raise BitPayError, MISSING_KEY unless pem
76
+ key = OpenSSL::PKey::EC.new(pem)
77
+ get_public_key key
78
+ end
79
+
80
+ def generate_sin_from_pem(pem = nil)
81
+ #http://blog.bitpay.com/2014/07/01/bitauth-for-decentralized-authentication.html
82
+ #https://en.bitcoin.it/wiki/Identity_protocol_v1
83
+
84
+ # NOTE: All Digests are calculated against the binary representation,
85
+ # hence the requirement to use [].pack("H*") to convert to binary for each step
86
+
87
+ #Generate Private Key
88
+ key = pem.nil? ? get_local_pem_file : OpenSSL::PKey::EC.new(pem)
89
+ key.public_key.group.point_conversion_form = :compressed
90
+ public_key = key.public_key.to_bn.to_s(2)
91
+ step_one = Digest::SHA256.hexdigest(public_key)
92
+ step_two = Digest::RMD160.hexdigest([step_one].pack("H*"))
93
+ step_three = "0F02" + step_two
94
+ step_four_a = Digest::SHA256.hexdigest([step_three].pack("H*"))
95
+ step_four = Digest::SHA256.hexdigest([step_four_a].pack("H*"))
96
+ step_five = step_four[0..7]
97
+ step_six = step_three + step_five
98
+ encode_base58(step_six)
99
+ end
100
+
101
+
102
+ ## Generate ECDSA signature
103
+ # This is the last method that requires the ecdsa gem, which we would like to replace
104
+
105
+ def sign(message, privkey)
106
+ group = ECDSA::Group::Secp256k1
107
+ digest = Digest::SHA256.digest(message)
108
+ signature = nil
109
+ while signature.nil?
110
+ temp_key = 1 + SecureRandom.random_number(group.order - 1)
111
+ signature = ECDSA.sign(group, privkey.to_i(16), digest, temp_key)
112
+ return ECDSA::Format::SignatureDerString.encode(signature).unpack("H*").first
113
+ end
114
+ end
115
+
116
+ ########## Private Class Methods ################
117
+
118
+ ## Base58 Encoding Method
119
+ #
120
+ private
121
+ def encode_base58 (data)
122
+ code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
123
+ base = 58
124
+ x = data.hex
125
+ output_string = ""
126
+
127
+ while x > 0 do
128
+ remainder = x % base
129
+ x = x / base
130
+ output_string << code_string[remainder]
131
+ end
132
+
133
+ pos = 0
134
+ while data[pos,2] == "00" do
135
+ output_string << code_string[0]
136
+ pos += 2
137
+ end
138
+
139
+ output_string.reverse()
140
+ end
141
+ end
142
+ end
143
+ end
@@ -1,3 +1,7 @@
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
+
1
5
  module BitPay
2
- VERSION = '0.1.5'
6
+ VERSION = '2.0.0'
3
7
  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_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
+
@@ -0,0 +1,78 @@
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
+
15
+ before do
16
+ allow(BitPay::KeyUtils).to receive(:nonce).and_return('1')
17
+ stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(:status => 200, :body => tokens.to_json, :headers => {})
18
+ end
19
+
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
+
29
+ describe "#send_request" do
30
+ before do
31
+ stub_const('ENV', {'BITPAY_PEM' => PEM})
32
+ end
33
+
34
+ context "GET" do
35
+ it 'should generate a get request' do
36
+ stub_request(:get, /#{BitPay::TEST_API_URI}\/whatever.*/).to_return(:body => '{"awesome": "json"}')
37
+ bitpay_client.send_request("GET", "whatever", facade: "merchant")
38
+ expect(WebMock).to have_requested(:get, "#{BitPay::TEST_API_URI}/whatever?nonce=1&token=MERCHANTTOKEN")
39
+ end
40
+ end
41
+
42
+ context "POST" do
43
+ it 'should generate a post request' do
44
+ stub_request(:post, /#{BitPay::TEST_API_URI}.*/).to_return(:body => '{"awesome": "json"}')
45
+ bitpay_client.send_request("POST", "whatever", facade: "merchant")
46
+ expect(WebMock).to have_requested(:post, "#{BitPay::TEST_API_URI}/whatever")
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ describe "#pair_pos_client" do
53
+ it 'throws a BitPayError with the error message if the token setting fails' do
54
+ stub_const('ENV', {'BITPAY_PEM' => PEM})
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')
57
+ end
58
+
59
+ it 'gracefully handles 4xx errors' do
60
+ stub_const('ENV', {'BITPAY_PEM' => PEM})
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"}')
63
+ end
64
+ end
65
+
66
+ describe "#create_invoice" do
67
+ subject { bitpay_client }
68
+ before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
69
+ it { is_expected.to respond_to(:create_invoice) }
70
+
71
+ it 'should make call to the server to create an invoice' do
72
+ stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
73
+ bitpay_client.create_invoice(id: "addd", price: 20, currency: "USD")
74
+ assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,28 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ describe "pairing a token", javascript: true, type: :feature do
4
+ let(:claimCode) do
5
+ visit ROOT_ADDRESS
6
+ click_link('Login')
7
+ fill_in 'email', :with => TEST_USER
8
+ fill_in 'password', :with => TEST_PASS
9
+ click_button('loginButton')
10
+ click_link "My Account"
11
+ click_link "API Tokens", match: :first
12
+ find(".token-access-new-button").find(".btn").click
13
+ find(".token-claimcode", match: :first).text
14
+ end
15
+ let(:pem) { BitPay::KeyUtils.generate_pem }
16
+ let(:client) { BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true) }
17
+
18
+ context "pairing an unpaired client" do
19
+ it "should have no tokens before pairing" do
20
+ expect(client.instance_variable_get(:@tokens)).to be_empty
21
+ end
22
+ it "should have a pos token after pairing" do
23
+ client.pair_pos_client(claimCode)
24
+ expect(client.instance_variable_get(:@tokens)['pos']).not_to be_empty
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,37 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ describe "create an invoice", javascript: true, type: :feature do
4
+ before :all do
5
+ WebMock.allow_net_connect!
6
+ get_claim_code = -> {
7
+ visit ROOT_ADDRESS
8
+ click_link('Login')
9
+ fill_in 'email', :with => TEST_USER
10
+ fill_in 'password', :with => TEST_PASS
11
+ click_button('loginButton')
12
+ click_link "My Account"
13
+ click_link "API Tokens", match: :first
14
+ find(".token-access-new-button").find(".btn").click
15
+ find(".token-claimcode", match: :first).text
16
+ }
17
+ set_client = -> {
18
+ private_key = BitPay::KeyUtils.get_private_key_from_pem PEM
19
+ client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: PEM, insecure: true)
20
+ client.pair_pos_client(get_claim_code.call)
21
+ client
22
+ }
23
+ @client ||= set_client.call
24
+ @invoice_id ||= SecureRandom.uuid
25
+ @price ||= (100..150).to_a.sample
26
+ @invoice = @client.create_invoice(id: @invoice_id, currency: "USD", price: @price)
27
+ end
28
+
29
+ it "should create an invoice" do
30
+ expect(@invoice["status"]).to eq "new"
31
+ end
32
+
33
+ it "should be able to retrieve an invoice" do
34
+ expect(@client.get_public_invoice(id: @invoice['id'])["price"]).to eq @price
35
+ end
36
+ end
37
+
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ context 'local variables' do
4
+ it "should find the root address" do
5
+ expect(ROOT_ADDRESS).not_to be_nil
6
+ end
7
+ it "should find the user" do
8
+ expect(TEST_USER).not_to be_nil
9
+ end
10
+ it "should find the user" do
11
+ expect(TEST_PASS).not_to be_nil
12
+ end
13
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe BitPay::KeyUtils do
4
+ let(:key_utils) {BitPay::KeyUtils}
5
+
6
+
7
+ describe '.get_local_private_key' do
8
+ it "should get the key from the ENV['PRIV_KEY'] variable" do
9
+ stub_const('ENV', {'BITPAY_PEM' => PEM})
10
+ expect(key_utils.get_local_pem_file).to eq(PEM)
11
+ end
12
+
13
+ it 'should get the key from ~/.bitpay/bitpay.pem if env variable is not set' do
14
+ allow(File).to receive(:read).with(BitPay::PRIVATE_KEY_PATH) {PEM}
15
+ expect(key_utils.get_local_pem_file).to eq(PEM)
16
+ end
17
+
18
+ end
19
+
20
+ describe '.generate_pem' do
21
+ it 'should write a new key to ~/.bitpay/bitpay.pem' do
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)
25
+ expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
26
+ key_utils.generate_pem
27
+ end
28
+
29
+ end
30
+
31
+ describe '.retrieve_or_generate_pem' do
32
+ it 'should write a new key to ~/.bitpay/bitpay.pem if there is no existing file' do
33
+ file = class_double("File").as_stubbed_const
34
+ double = double("Object").as_null_object
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)
37
+ expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
38
+ key_utils.retrieve_or_generate_pem
39
+ end
40
+
41
+ it 'should retrieve the pem if there is an existing file' do
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)
45
+ expect(file).to receive(:open).with(BitPay::PRIVATE_KEY_PATH, 'w')
46
+ key_utils.generate_pem
47
+ end
48
+ end
49
+
50
+ describe '.get_public_key_from_pem' do
51
+ it 'should generate the right public key' do
52
+ expect(key_utils.get_public_key_from_pem(PEM)).to eq(PUB_KEY)
53
+ end
54
+
55
+ it 'should get pem from the env if none is passed' do
56
+ expect(key_utils.get_public_key_from_pem(PEM)).to eq(PUB_KEY)
57
+ end
58
+
59
+ end
60
+
61
+ describe '.generate_sin_from_pem' do
62
+ let(:pem){PEM}
63
+ let(:sin){"TeyN4LPrXiG5t2yuSamKqP3ynVk3F52iHrX"}
64
+
65
+ it 'will return the right sin for the right pem' do
66
+ expect(key_utils.generate_sin_from_pem(pem)).to eq sin
67
+ end
68
+ end
69
+
70
+ context "errors when priv_key is not provided" do
71
+ before :each do
72
+ allow(File).to receive(:read).with(BitPay::PRIVATE_KEY_PATH) {nil}
73
+ end
74
+
75
+ it 'will not retrieve public key' do
76
+ expect{key_utils.get_public_key_from_pem(nil)}.to raise_error(BitPay::BitPayError)
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ export RCROOTADDRESS=$1
4
+ echo $RCROOTADDRESS
5
+ export RCTESTUSER=$2
6
+ echo $RCTESTUSER
7
+ export RCTESTPASSWORD=$3
8
+ echo $RCTESTPASSWORD
9
+ export PRIV_KEY=$4
10
+ echo $PRIV_KEY
@@ -0,0 +1,25 @@
1
+ require 'webmock/rspec'
2
+ require 'pry'
3
+ require 'capybara/rspec'
4
+ require 'capybara/poltergeist'
5
+
6
+ require File.join File.dirname(__FILE__), '..', 'lib', 'bitpay', 'client.rb'
7
+ require File.join File.dirname(__FILE__), '..', 'lib', 'bitpay', 'key_utils.rb'
8
+ require File.join File.dirname(__FILE__), '..', 'lib', 'bitpay.rb'
9
+ require_relative '../config/constants.rb'
10
+ require_relative '../config/capybara.rb'
11
+
12
+ #
13
+ ## Test Variables
14
+ #
15
+ PEM = "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEICg7E4NN53YkaWuAwpoqjfAofjzKI7Jq1f532dX+0O6QoAcGBSuBBAAK\noUQDQgAEjZcNa6Kdz6GQwXcUD9iJ+t1tJZCx7hpqBuJV2/IrQBfue8jh8H7Q/4vX\nfAArmNMaGotTpjdnymWlMfszzXJhlw==\n-----END EC PRIVATE KEY-----\n"
16
+
17
+ PUB_KEY = '038d970d6ba29dcfa190c177140fd889fadd6d2590b1ee1a6a06e255dbf22b4017'
18
+ CLIENT_ID = "TfFVQhy2hQvchv4VVG4c7j4XPa2viJ9HrR8"
19
+
20
+
21
+ RSpec.configure do |config|
22
+ config.before :each do |example|
23
+ WebMock.allow_net_connect! if example.metadata[:type] == :feature
24
+ end
25
+ end
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: 0.1.5
4
+ version: 2.0.0
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-11-05 00:00:00.000000000 Z
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ecdsa
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: commander
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rake
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +81,21 @@ dependencies:
53
81
  - !ruby/object:Gem::Version
54
82
  version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
- name: minitest
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
57
99
  requirement: !ruby/object:Gem::Requirement
58
100
  requirements:
59
101
  - - ">="
@@ -67,7 +109,21 @@ dependencies:
67
109
  - !ruby/object:Gem::Version
68
110
  version: '0'
69
111
  - !ruby/object:Gem::Dependency
70
- name: webmock
112
+ name: pry-byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-rescue
71
127
  requirement: !ruby/object:Gem::Requirement
72
128
  requirements:
73
129
  - - ">="
@@ -81,7 +137,63 @@ dependencies:
81
137
  - !ruby/object:Gem::Version
82
138
  version: '0'
83
139
  - !ruby/object:Gem::Dependency
84
- name: yard
140
+ name: capybara
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: poltergeist
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: airborne
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: mongo
85
197
  requirement: !ruby/object:Gem::Requirement
86
198
  requirements:
87
199
  - - ">="
@@ -97,7 +209,8 @@ dependencies:
97
209
  description: Powerful, flexible, lightweight, thread-safe interface to the BitPay
98
210
  developers API
99
211
  email: info@bitpay.com
100
- executables: []
212
+ executables:
213
+ - bitpay
101
214
  extensions: []
102
215
  extra_rdoc_files: []
103
216
  files:
@@ -107,15 +220,27 @@ files:
107
220
  - LICENSE.md
108
221
  - README.md
109
222
  - Rakefile
223
+ - bin/bitpay
110
224
  - bitpay-client.gemspec
225
+ - config/capybara.rb
226
+ - config/constants.rb
111
227
  - lib/bitpay.rb
112
228
  - lib/bitpay/cacert.pem
229
+ - lib/bitpay/cli.rb
113
230
  - lib/bitpay/client.rb
231
+ - lib/bitpay/key_utils.rb
114
232
  - lib/bitpay/version.rb
115
- - test/bitpay/client_test.rb
116
- - test/env.rb
233
+ - lib/harness.rb
234
+ - spec/client_spec.rb
235
+ - spec/features/pair_spec.rb
236
+ - spec/features/pos_spec.rb
237
+ - spec/features/setup_spec.rb
238
+ - spec/key_utils_spec.rb
239
+ - spec/set_constants.sh
240
+ - spec/spec_helper.rb
117
241
  homepage: https://github.com/bitpay/ruby-client
118
- licenses: []
242
+ licenses:
243
+ - MIT
119
244
  metadata: {}
120
245
  post_install_message:
121
246
  rdoc_options: []
@@ -123,9 +248,9 @@ require_paths:
123
248
  - lib
124
249
  required_ruby_version: !ruby/object:Gem::Requirement
125
250
  requirements:
126
- - - ">="
251
+ - - "~>"
127
252
  - !ruby/object:Gem::Version
128
- version: '0'
253
+ version: '2.1'
129
254
  required_rubygems_version: !ruby/object:Gem::Requirement
130
255
  requirements:
131
256
  - - ">="
@@ -1,70 +0,0 @@
1
- require File.join File.dirname(__FILE__), '..', 'env.rb'
2
-
3
- USER_AGENT = 'ruby-bitpay-client '+BitPay::VERSION
4
-
5
- def invoice_create_body
6
- {:price => 1, :currency => 'USD'}
7
- end
8
-
9
- def invoice_response_body
10
- {
11
- "id" => "DGrAEmbsXe9bavBPMJ8kuk",
12
- "url" => "https://bitpay.com/invoice?id=DGrAEmbsXe9bavBPMJ8kuk",
13
- "status" => "new",
14
- "btcPrice" => "0.0495",
15
- "price" => 10,
16
- "currency" => "USD",
17
- "invoiceTime" => 1383265343674,
18
- "expirationTime" => 1383266243674,
19
- "currentTime" => 1383265957613
20
- }
21
- end
22
-
23
- def unauthorized_key_body
24
- {"error" => {"type" => "unauthorized", "message" => "invalid api key"}}
25
- end
26
-
27
- stub_request(:post, "https://KEY:@bitpay.com/api/invoice/create").
28
- with(
29
- :headers => {'User-Agent'=>USER_AGENT, 'Content-Type' => 'application/json'},
30
- :body => invoice_create_body
31
- ).
32
- to_return(:body => invoice_response_body.to_json)
33
-
34
- stub_request(:get, "https://KEY:@bitpay.com/api/invoice/DGrAEmbsXe9bavBPMJ8kuk").
35
- with(:headers => {'User-Agent'=>USER_AGENT}).
36
- to_return(:body => invoice_response_body.to_json)
37
-
38
- stub_request(:get, "https://KEY:@bitpay.com/api/invoice/BADAPIKEY").
39
- with(:headers => {'User-Agent'=>USER_AGENT}).
40
- to_return(:status => 403, :body => unauthorized_key_body.to_json)
41
-
42
- describe BitPay::Client do
43
- before do
44
- @client = BitPay::Client.new 'KEY'
45
- end
46
-
47
- describe 'post' do
48
- it 'creates invoice' do
49
- response = @client.post 'invoice/create', invoice_create_body
50
- response.class.must_equal Hash
51
- response['id'].must_equal 'DGrAEmbsXe9bavBPMJ8kuk'
52
- end
53
- end
54
-
55
- describe 'get' do
56
- it 'retreives invoice' do
57
- response = @client.get 'invoice/DGrAEmbsXe9bavBPMJ8kuk'
58
- response.class.must_equal Hash
59
- response['id'].must_equal 'DGrAEmbsXe9bavBPMJ8kuk'
60
- end
61
- end
62
-
63
- describe 'bad API Key' do
64
- it 'returns Error' do
65
- assert_raises(BitPay::Client::BitPayError) {
66
- response = @client.get 'invoice/BADAPIKEY'
67
- }
68
- end
69
- end
70
- end
@@ -1,7 +0,0 @@
1
- require 'addressable/uri'
2
- require 'json'
3
- require 'minitest/autorun'
4
- require 'webmock'
5
- require './lib/bitpay.rb'
6
-
7
- include WebMock::API