bitpay-sdk 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b8fa092d5243a1f4759ce3735f53b892ffd70741
4
+ data.tar.gz: 2befc033218ad775ecada44facf7836498e86371
5
+ SHA512:
6
+ metadata.gz: 93fd95f0d1533ef5cf48eed9e964a03b2320409b6ee6fc3fbb66a75012f94a23c8568742bab6e2086994d1eae99635acac70c0b94254bbb2c7a8fb5448b29f9c
7
+ data.tar.gz: 5196595d3e0d36c58c1a3481d2a4924b848583e417e9418954c3f66921255fa0369cc37d3143afaf9d0a3b1fce138fdf551990a48182289cb153b9e7733da19f
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .DS_Store
2
+ test.rb
3
+ Gemfile.lock
4
+ pkg
5
+ .c9
6
+ .ruby-version
7
+ .ruby-gemset
data/.travis.yml ADDED
@@ -0,0 +1,2 @@
1
+ rvm:
2
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ platform :jruby do
5
+ gem 'jruby-openssl'
6
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2014 BitPay
2
+
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
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # BitPay Library for Ruby [![](https://secure.travis-ci.org/bitpay/ruby-client.png)](http://travis-ci.org/bitpay/ruby-client)
2
+ Powerful, flexible, lightweight interface to the BitPay Bitcoin Payment Gateway API.
3
+
4
+ ## Installation
5
+
6
+ gem install bitpay
7
+
8
+ In your Gemfile:
9
+
10
+ gem 'bitpay', :require => 'bitpay'
11
+
12
+ Or directly:
13
+
14
+ require 'bitpay'
15
+
16
+ ## Configuration
17
+
18
+ The bitpay client creates a cryptographically secure connection to your server by pairing an API code with keys generated by the library. The client can be initialized with pre-existing keys passed in as a pem file, or paired if initialized with a pem file and a tokens hash. Examples can be found in the cucumber step helpers.
19
+
20
+ ## Basic Usage
21
+
22
+ ### Pairing with Bitpay.com
23
+
24
+ To pair with bitpay.com you need to have an approved merchant account.
25
+ 1. Login to your account
26
+ 2. Navigate to bitpay.com/api-tokens (Dashboard > My Account > API Tokens)
27
+ 3. Create a new token and copy the pairing code.
28
+
29
+ client = BitPay::Client.new
30
+ client.pair_pos_client(<pairing_code>)
31
+ invoice = client.create_invoice (price: <price>, currency: <currency>)
32
+
33
+ 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.
34
+
35
+ Response will be a hash with information on your newly created invoice. Send your customer to the `url` to complete payment:
36
+
37
+ {
38
+ "id" => "DGrAEmbsXe9bavBPMJ8kuk",
39
+ "url" => "https://bitpay.com/invoice?id=DGrAEmbsXe9bavBPMJ8kuk",
40
+ "status" => "new",
41
+ "btcPrice" => "0.0495",
42
+ "price" => 10,
43
+ "currency" => "USD",
44
+ "invoiceTime" => 1383265343674,
45
+ "expirationTime" => 1383266243674,
46
+ "currentTime" => 1383265957613
47
+ }
48
+
49
+ There are many options available when creating invoices, which are listed in the [BitPay API documentation](https://bitpay.com/bitcoin-payment-gateway-api).
50
+
51
+ To get updated information on this invoice, make a get call with the id returned:
52
+
53
+ invoice = client.get_public_invoice(id: 'DGrAEmbsXe9bavBPMJ8kuk')
54
+
55
+ ## Testnet Usage
56
+
57
+ During development and testing, take advantage of the [Bitcoin TestNet](https://en.bitcoin.it/wiki/Testnet) by passing a custom `api_uri` option on initialization:
58
+
59
+ BitPay::Client.new(api_uri: "https://test.bitpay.com/api")
60
+
61
+ ## API Documentation
62
+
63
+ API Documentation is available on the [BitPay site](https://bitpay.com/api).
64
+
65
+ ## Running the Tests
66
+
67
+ In order to run the tests, you must have phantomjs installed and on your PATH.
68
+
69
+ The tests require that environment variables be set for the bitpay server, user name, and password. First run:
70
+
71
+ $ source ./spec/set_constants.sh https://test.bitpay.com <yourusername> <yourpassword>
72
+ $ bundle install
73
+ $ bundle exec rake
74
+
75
+ Tests are likely to run up against rate limiters on test.bitpay.com if used too frequently. Rake tasks which interact directly with BitPay will not run for the general public.
76
+
77
+ ## Found a bug?
78
+ Let us know! Send a pull request or a patch. Questions? Ask! We're here to help. We will respond to all filed issues.
79
+
80
+ ## Contributors
81
+ [Click here](https://github.com/bitpay/ruby-client/graphs/contributors) to see a list of the contributors to this library.
data/Rakefile ADDED
@@ -0,0 +1,73 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ require 'capybara'
4
+ require 'capybara/poltergeist'
5
+ require 'mongo'
6
+ require 'cucumber'
7
+ require 'cucumber/rake/task'
8
+ require_relative 'config/constants.rb'
9
+ require_relative 'config/capybara.rb'
10
+
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
13
+ task :default => :spec
14
+
15
+ Cucumber::Rake::Task.new(:features) do |t|
16
+ t.cucumber_opts = "features --format pretty"
17
+ end
18
+
19
+ desc "Bitpay Tasks"
20
+ namespace :bitpay do
21
+
22
+ desc "Clear all claim codes from the test server."
23
+ task :clear_claim_codes do
24
+ puts "clearing claim codes"
25
+ client = Mongo::MongoClient.new
26
+ db = client['bitpay-dev']
27
+ coll = db['tokenaccesses']
28
+ coll.remove()
29
+ puts "claim codes cleared"
30
+ end
31
+
32
+ desc "Clear rate limiters from local mongo host"
33
+ task :clear_rate_limiters do
34
+ puts "clearing rate limiters"
35
+ client = Mongo::MongoClient.new
36
+ db = client['bitpay-dev']
37
+ coll = db['ratelimiters']
38
+ coll.remove()
39
+ puts "rate limiters cleared"
40
+ end
41
+
42
+ desc "Clear local pem and token file"
43
+ task :clear_local_files do
44
+ puts "clearing local files"
45
+ HOME_DIR = File.join(Dir.home, '.bitpay')
46
+ KEY_FILE = File.join(HOME_DIR, 'bitpay.pem')
47
+ TOKEN_FILE = File.join(HOME_DIR, 'tokens.json')
48
+ File.delete(KEY_FILE) if File.file?(KEY_FILE)
49
+ File.delete(TOKEN_FILE) if File.file?(TOKEN_FILE)
50
+ puts "local files cleared"
51
+ end
52
+
53
+ desc "Clear tokens, rate limiters, and local files."
54
+ task :clear do
55
+ ["bitpay:clear_local_files", "bitpay:clear_rate_limiters", "bitpay:clear_claim_codes"].each{|task| Rake::Task[task].reenable}
56
+ ["bitpay:clear_local_files", "bitpay:clear_rate_limiters", "bitpay:clear_claim_codes"].each{|task| Rake::Task[task].invoke}
57
+ end
58
+
59
+ desc "Run specs and clear claim codes and rate_limiters."
60
+ task :spec_clear => ['spec', 'clear_claim_codes', 'clear_rate_limiters']
61
+
62
+ desc "Run specs, clear data, run cukes, clear data"
63
+ task :tests_clear do
64
+ Rake::Task["bitpay:clear"].invoke
65
+ Rake::Task["spec"].invoke
66
+ Rake::Task["bitpay:clear"].reenable
67
+ Rake::Task["bitpay:clear"].invoke
68
+ Rake::Task["features"].invoke
69
+ Rake::Task["bitpay:clear"].reenable
70
+ Rake::Task["bitpay:clear"].invoke
71
+ end
72
+
73
+ end
@@ -0,0 +1,35 @@
1
+ require './lib/bitpay/version.rb'
2
+ Gem::Specification.new do |s|
3
+ s.name = 'bitpay-sdk'
4
+ s.version = BitPay::VERSION
5
+ s.licenses = ['MIT']
6
+ s.authors = 'Bitpay, Inc.'
7
+ s.email = 'info@bitpay.com'
8
+ s.homepage = 'https://github.com/bitpay/ruby-client'
9
+ s.summary = 'Official Ruby library for the BitPay API'
10
+ s.description = 'Powerful, flexible, lightweight, thread-safe interface to the BitPay developers API'
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.require_paths = ["lib"]
14
+ s.rubyforge_project = s.name
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) }
19
+
20
+ s.add_dependency 'json', '~> 1.8.1'
21
+ s.add_dependency 'rack', '~> 1.5.2'
22
+ s.add_dependency 'ecdsa', '~> 1.2.0'
23
+
24
+ s.add_development_dependency 'rake', '~> 10.3.2'
25
+ s.add_development_dependency 'webmock', '~> 1.18.0'
26
+ s.add_development_dependency 'pry', '~> 0.10.1'
27
+ s.add_development_dependency 'pry-byebug', '~> 2.0.0'
28
+ s.add_development_dependency 'pry-rescue', '~> 1.4.1'
29
+ s.add_development_dependency 'capybara', '~> 2.4.3'
30
+ s.add_development_dependency 'cucumber', '~> 1.3.17'
31
+ s.add_development_dependency 'poltergeist', '~> 1.5.1'
32
+ s.add_development_dependency 'airborne', '~> 0.0.20'
33
+ s.add_development_dependency 'rspec', '~> 3.1.0'
34
+ s.add_development_dependency 'mongo', '~> 1.11.1'
35
+ end
@@ -0,0 +1,6 @@
1
+ Capybara.javascript_driver = :poltergeist
2
+ Capybara.default_driver = :poltergeist
3
+ Capybara.default_wait_time = 5
4
+ Capybara.register_driver :poltergeist do |app|
5
+ Capybara::Poltergeist::Driver.new(app, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1', '--web-security=false'] )
6
+ end
@@ -0,0 +1,3 @@
1
+ ROOT_ADDRESS = ENV['RCROOTADDRESS']
2
+ TEST_USER = ENV['RCTESTUSER']
3
+ TEST_PASS = ENV['RCTESTPASSWORD']
@@ -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,7 @@
1
+ Feature: retrieving an invoice
2
+ The user may want to retrieve invoices
3
+ So that they can view them
4
+
5
+ Scenario: The request is correct
6
+ Given that a user knows an invoice id
7
+ Then they can retrieve that invoice
@@ -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,79 @@
1
+ require 'capybara/poltergeist'
2
+ require 'pry'
3
+
4
+ require File.join File.dirname(__FILE__), '..', '..', 'lib', 'bitpay', 'client.rb'
5
+ require File.join File.dirname(__FILE__), '..', '..', 'lib', 'bitpay', 'key_utils.rb'
6
+ require File.join File.dirname(__FILE__), '..', '..', 'lib', 'bitpay.rb'
7
+ require_relative '../../config/constants.rb'
8
+ require_relative '../../config/capybara.rb'
9
+
10
+ #
11
+ ## Test Variables
12
+ #
13
+ #PEM = "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEICg7E4NN53YkaWuAwpoqjfAofjzKI7Jq1f532dX+0O6QoAcGBSuBBAAK\noUQDQgAEjZcNa6Kdz6GQwXcUD9iJ+t1tJZCx7hpqBuJV2/IrQBfue8jh8H7Q/4vX\nfAArmNMaGotTpjdnymWlMfszzXJhlw==\n-----END EC PRIVATE KEY-----\n"
14
+ #
15
+ #PUB_KEY = '038d970d6ba29dcfa190c177140fd889fadd6d2590b1ee1a6a06e255dbf22b4017'
16
+ #CLIENT_ID = "TeyN4LPrXiG5t2yuSamKqP3ynVk3F52iHrX"
17
+ module BitPay
18
+ # Location for API Credentials
19
+ BITPAY_CREDENTIALS_DIR = File.join(Dir.home, ".bitpay")
20
+ PRIVATE_KEY_FILE = 'bitpay.pem'
21
+ PRIVATE_KEY_PATH = File.join(BITPAY_CREDENTIALS_DIR, PRIVATE_KEY_FILE)
22
+ TOKEN_FILE = 'tokens.json'
23
+ TOKEN_FILE_PATH = File.join(BITPAY_CREDENTIALS_DIR, TOKEN_FILE)
24
+ end
25
+
26
+ def get_claim_code_from_server
27
+ Capybara::visit ROOT_ADDRESS
28
+ if logged_in
29
+ Capybara::visit "#{ROOT_ADDRESS}/home"
30
+ else
31
+ log_in
32
+ end
33
+ Capybara::click_link "My Account"
34
+ Capybara::click_link "API Tokens", match: :first
35
+ Capybara::find(".token-access-new-button").find(".btn").find(".icon-plus").click
36
+ sleep 0.25
37
+ Capybara::find_button("Add Token", match: :first).click
38
+ Capybara::find(".token-claimcode", match: :first).text
39
+ end
40
+
41
+ def log_in
42
+ Capybara::click_link('Login')
43
+ Capybara::fill_in 'email', :with => TEST_USER
44
+ Capybara::fill_in 'password', :with => TEST_PASS
45
+ Capybara::click_button('loginButton')
46
+ end
47
+
48
+ def new_paired_client
49
+ claim_code = get_claim_code_from_server
50
+ pem = BitPay::KeyUtils.generate_pem
51
+ client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
52
+ client.pair_pos_client(claim_code)
53
+ client
54
+ end
55
+
56
+ def new_client_from_stored_values
57
+ if File.file?(BitPay::PRIVATE_KEY_PATH) && File.file?(BitPay::TOKEN_FILE_PATH)
58
+ token = get_token_from_file
59
+ pem = File.read(BitPay::PRIVATE_KEY_PATH)
60
+ BitPay::Client.new(pem: pem, tokens: token, insecure: true, api_uri: ROOT_ADDRESS )
61
+ else
62
+ claim_code = get_claim_code_from_server
63
+ pem = BitPay::KeyUtils.generate_pem
64
+ client = BitPay::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
65
+ token = client.pair_pos_client(claim_code)
66
+ File.write(BitPay::PRIVATE_KEY_PATH, pem)
67
+ File.write(BitPay::TOKEN_FILE_PATH, JSON.generate(token))
68
+ client
69
+ end
70
+ end
71
+
72
+ def get_token_from_file
73
+ token = JSON.parse(File.read(BitPay::TOKEN_FILE_PATH))['data'][0]
74
+ {token['facade'] => token['token']}
75
+ end
76
+
77
+ def logged_in
78
+ Capybara::has_link?('Dashboard')
79
+ end