Compare commits
4 Commits
master
...
bug-issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8defe21d3 | ||
|
|
25d6ebbcec | ||
|
|
48d3c753ee | ||
|
|
72487c9591 |
11
CHANGELOG.md
Normal file
11
CHANGELOG.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [2.3.3] - 2015-03-12
|
||||
### Changed
|
||||
- Pull refund functionality from 2.3 spec
|
||||
- Bump gem version
|
||||
|
||||
### Fixed
|
||||
- Fix Bug: GitHub issue #40 - error on return from endpoints that do not have a "data" field
|
||||
@ -11,9 +11,9 @@ TEST_PASS = ENV['RCTESTPASSWORD']
|
||||
DASHBOARD_URL = "#{ROOT_ADDRESS}/dashboard/merchant/home"
|
||||
|
||||
unless
|
||||
ROOT_ADDRESS &&
|
||||
TEST_USER &&
|
||||
TEST_PASS
|
||||
ROOT_ADDRESS &&
|
||||
TEST_USER &&
|
||||
TEST_PASS
|
||||
then
|
||||
raise "Missing configuration options - see constants.rb"
|
||||
raise "Missing configuration options - see constants.rb"
|
||||
end
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
@invoices
|
||||
Feature: creating an invoice
|
||||
The user won't get any money
|
||||
If they can't
|
||||
@ -10,9 +11,10 @@ Feature: creating an invoice
|
||||
When the user creates an invoice for <price> <currency>
|
||||
Then they should recieve an invoice in response for <price> <currency>
|
||||
Examples:
|
||||
| price | currency |
|
||||
| "5.23" | "USD" |
|
||||
| price | currency |
|
||||
| "5.23" | "USD" |
|
||||
| "10.21" | "EUR" |
|
||||
| "0.225" | "BTC" |
|
||||
|
||||
Scenario Outline: The invoice contains illegal characters
|
||||
When the user creates an invoice for <price> <currency>
|
||||
@ -20,7 +22,7 @@ Feature: creating an invoice
|
||||
Examples:
|
||||
| price | currency | message |
|
||||
| "5,023" | "USD" | "Price must be formatted as a float" |
|
||||
| "3.21" | "EaUR" | "Currency is invalid." |
|
||||
| "3.21" | "EaUR" | "Currency is invalid." |
|
||||
| "" | "USD" | "Price must be formatted as a float" |
|
||||
| "Ten" | "USD" | "Price must be formatted as a float" |
|
||||
| "10" | "" | "Currency is invalid." |
|
||||
|
||||
@ -61,5 +61,5 @@ Given(/^the user requests a client\-side pairing$/) do
|
||||
end
|
||||
|
||||
Then(/^they will receive a claim code$/) do
|
||||
expect(@response["data"].first["pairingCode"] ).not_to be_empty
|
||||
expect(@response.first["pairingCode"] ).not_to be_empty
|
||||
end
|
||||
|
||||
@ -66,7 +66,7 @@ def new_client_from_stored_values
|
||||
end
|
||||
|
||||
def get_token_from_file
|
||||
token = JSON.parse(File.read(BitPay::TOKEN_FILE_PATH))['data'][0]
|
||||
token = JSON.parse(File.read(BitPay::TOKEN_FILE_PATH))[0]
|
||||
{token['facade'] => token['token']}
|
||||
end
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# license Copyright 2011-2014 BitPay, Inc., MIT License
|
||||
# license Copyright 2011-2015 BitPay, Inc., MIT License
|
||||
# see http://opensource.org/licenses/MIT
|
||||
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
||||
|
||||
@ -7,13 +7,14 @@ require 'net/https'
|
||||
require 'json'
|
||||
|
||||
require_relative 'key_utils'
|
||||
require_relative 'rest_connector'
|
||||
|
||||
module BitPay
|
||||
# This class is used to instantiate a BitPay Client object. It is expected to be thread safe.
|
||||
#
|
||||
module SDK
|
||||
class Client
|
||||
|
||||
include BitPay::RestConnector
|
||||
# @return [Client]
|
||||
# @example
|
||||
# # Create a client with a pem file created by the bitpay client:
|
||||
@ -46,7 +47,8 @@ module BitPay
|
||||
# => Pass {pairingCode: 'WfD01d2'} to claim a server-initiated pairing code
|
||||
#
|
||||
def pair_client(params={})
|
||||
pairing_request(params)
|
||||
tokens = post(path: 'tokens', params: params)
|
||||
return tokens["data"]
|
||||
end
|
||||
|
||||
## Compatibility method for pos pairing
|
||||
@ -61,27 +63,22 @@ module BitPay
|
||||
# Defaults to pos facade, also works with merchant facade
|
||||
#
|
||||
def create_invoice(price:, currency:, facade: 'pos', params:{})
|
||||
raise BitPay::ArgumentError, "Illegal Argument: Price must be formatted as a float" unless ( price.is_a?(Numeric) || /^[[:digit:]]+(\.[[:digit:]]{2})?$/.match(price) )
|
||||
raise BitPay::ArgumentError, "Illegal Argument: Price must be formatted as a float" unless
|
||||
price.is_a?(Numeric) ||
|
||||
/^[[:digit:]]+(\.[[:digit:]]{2})?$/.match(price) ||
|
||||
currency == 'BTC' && /^[[:digit:]]+(\.[[:digit:]]{1,6})?$/.match(price)
|
||||
raise BitPay::ArgumentError, "Illegal Argument: Currency is invalid." unless /^[[:upper:]]{3}$/.match(currency)
|
||||
params.merge!({price: price, currency: currency})
|
||||
response = send_request("POST", "invoices", facade: facade, params: params)
|
||||
response["data"]
|
||||
token = get_token(facade)
|
||||
invoice = post(path: "invoices", token: token, params: params)
|
||||
invoice["data"]
|
||||
end
|
||||
|
||||
## Gets the privileged merchant-version of the invoice
|
||||
# Requires merchant facade token
|
||||
#
|
||||
def get_invoice(id:)
|
||||
response = send_request("GET", "invoices/#{id}", facade: 'merchant')
|
||||
response["data"]
|
||||
end
|
||||
|
||||
## Gets the public version of the invoice
|
||||
#
|
||||
def get_public_invoice(id:)
|
||||
request = Net::HTTP::Get.new("/invoices/#{id}")
|
||||
response = process_request(request)
|
||||
response["data"]
|
||||
invoice = get(path: "invoices/#{id}", public: true)
|
||||
invoice["data"]
|
||||
end
|
||||
|
||||
## Checks that the passed tokens are valid by
|
||||
@ -95,116 +92,12 @@ module BitPay
|
||||
tokens.each{|key, value| return false if server_tokens[key] != value}
|
||||
return true
|
||||
end
|
||||
|
||||
## Generates REST request to api endpoint
|
||||
# => Defaults to merchant facade unless token or facade is explicitly provided
|
||||
#
|
||||
def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
|
||||
token ||= get_token(facade)
|
||||
|
||||
# Verb-specific logic
|
||||
case verb.upcase
|
||||
when "GET"
|
||||
urlpath = '/' + path + '?token=' + token
|
||||
request = Net::HTTP::Get.new urlpath
|
||||
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
||||
|
||||
when "PUT"
|
||||
|
||||
when "POST" # Requires a GUID
|
||||
|
||||
urlpath = '/' + path
|
||||
request = Net::HTTP::Post.new urlpath
|
||||
params[:token] = token
|
||||
params[:guid] = SecureRandom.uuid
|
||||
params[:id] = @client_id
|
||||
request.body = params.to_json
|
||||
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath + request.body, @priv_key)
|
||||
|
||||
when "DELETE"
|
||||
|
||||
raise(BitPayError, "Invalid HTTP verb: #{verb.upcase}")
|
||||
end
|
||||
|
||||
# Build request headers and submit
|
||||
request['X-Identity'] = @pub_key
|
||||
|
||||
response = process_request(request)
|
||||
end
|
||||
|
||||
##### PRIVATE METHODS #####
|
||||
private
|
||||
|
||||
## Processes HTTP Request and returns parsed response
|
||||
# Otherwise throws error
|
||||
#
|
||||
def process_request(request)
|
||||
|
||||
request['User-Agent'] = @user_agent
|
||||
request['Content-Type'] = 'application/json'
|
||||
request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
|
||||
|
||||
begin
|
||||
response = @https.request request
|
||||
rescue => error
|
||||
raise BitPay::ConnectionError, "#{error.message}"
|
||||
end
|
||||
|
||||
if response.kind_of? Net::HTTPSuccess
|
||||
return JSON.parse(response.body)
|
||||
elsif JSON.parse(response.body)["error"]
|
||||
raise(BitPayError, "#{response.code}: #{JSON.parse(response.body)['error']}")
|
||||
else
|
||||
raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
## Fetches the tokens hash from the server and
|
||||
# updates @tokens
|
||||
#
|
||||
def refresh_tokens
|
||||
urlpath = '/tokens'
|
||||
|
||||
request = Net::HTTP::Get.new(urlpath)
|
||||
request['X-Identity'] = @pub_key
|
||||
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
||||
|
||||
response = process_request(request)
|
||||
token_array = response["data"] || {}
|
||||
|
||||
tokens = {}
|
||||
token_array.each do |t|
|
||||
tokens[t.keys.first] = t.values.first
|
||||
end
|
||||
|
||||
@tokens = tokens
|
||||
return tokens
|
||||
|
||||
end
|
||||
|
||||
## Makes a request to /tokens for pairing
|
||||
# Adds passed params as post parameters
|
||||
# If empty params, retrieves server-generated pairing code
|
||||
# If pairingCode key/value is passed, will pair client ID to this account
|
||||
# Returns response hash
|
||||
#
|
||||
def pairing_request(params)
|
||||
urlpath = '/tokens'
|
||||
request = Net::HTTP::Post.new urlpath
|
||||
params[:guid] = SecureRandom.uuid
|
||||
params[:id] = @client_id
|
||||
request.body = params.to_json
|
||||
process_request(request)
|
||||
end
|
||||
|
||||
def get_token(facade)
|
||||
token = @tokens[facade] || refresh_tokens[facade] || raise(BitPayError, "Not authorized for facade: #{facade}")
|
||||
end
|
||||
|
||||
def verify_claim_code(claim_code)
|
||||
regex = /^[[:alnum:]]{7}$/
|
||||
matches = regex.match(claim_code)
|
||||
matches = regex.match(claim_code)
|
||||
!(matches.nil?)
|
||||
end
|
||||
end
|
||||
|
||||
96
lib/bitpay/rest_connector.rb
Normal file
96
lib/bitpay/rest_connector.rb
Normal file
@ -0,0 +1,96 @@
|
||||
# license Copyright 2011-2015 BitPay, Inc., MIT License
|
||||
# see http://opensource.org/licenses/MIT
|
||||
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
||||
|
||||
module BitPay
|
||||
module RestConnector
|
||||
def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
|
||||
token ||= get_token(facade)
|
||||
case verb.upcase
|
||||
when "GET"
|
||||
return get(path: path, token:token)
|
||||
when "POST"
|
||||
return post(path: path, token: token, params: params)
|
||||
else
|
||||
raise(BitPayError, "Invalid HTTP verb: #{verb.upcase}")
|
||||
end
|
||||
end
|
||||
|
||||
def get(path:, token: nil, public: false)
|
||||
urlpath = '/' + path
|
||||
urlpath = urlpath + '?token=' + token if token
|
||||
request = Net::HTTP::Get.new urlpath
|
||||
unless public
|
||||
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
||||
request['X-Identity'] = @pub_key
|
||||
end
|
||||
process_request(request)
|
||||
end
|
||||
|
||||
def post(path:, token: nil, params:)
|
||||
urlpath = '/' + path
|
||||
request = Net::HTTP::Post.new urlpath
|
||||
params[:token] = token if token
|
||||
params[:guid] = SecureRandom.uuid
|
||||
params[:id] = @client_id
|
||||
request.body = params.to_json
|
||||
if token
|
||||
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath + request.body, @priv_key)
|
||||
request['X-Identity'] = @pub_key
|
||||
end
|
||||
process_request(request)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
## Processes HTTP Request and returns parsed response
|
||||
# Otherwise throws error
|
||||
#
|
||||
def process_request(request)
|
||||
request['User-Agent'] = @user_agent
|
||||
request['Content-Type'] = 'application/json'
|
||||
request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
|
||||
|
||||
begin
|
||||
response = @https.request request
|
||||
rescue => error
|
||||
raise BitPay::ConnectionError, "#{error.message}"
|
||||
end
|
||||
|
||||
if response.kind_of? Net::HTTPSuccess
|
||||
return JSON.parse(response.body)
|
||||
elsif JSON.parse(response.body)["error"]
|
||||
raise(BitPayError, "#{response.code}: #{JSON.parse(response.body)['error']}")
|
||||
else
|
||||
raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
## Fetches the tokens hash from the server and
|
||||
# updates @tokens
|
||||
#
|
||||
def refresh_tokens
|
||||
response = get(path: 'tokens')["data"]
|
||||
token_array = response || {}
|
||||
tokens = {}
|
||||
token_array.each do |t|
|
||||
tokens[t.keys.first] = t.values.first
|
||||
end
|
||||
@tokens = tokens
|
||||
return tokens
|
||||
end
|
||||
|
||||
## Makes a request to /tokens for pairing
|
||||
# Adds passed params as post parameters
|
||||
# If empty params, retrieves server-generated pairing code
|
||||
# If pairingCode key/value is passed, will pair client ID to this account
|
||||
# Returns response hash
|
||||
#
|
||||
|
||||
def get_token(facade)
|
||||
token = @tokens[facade] || refresh_tokens[facade] || raise(BitPayError, "Not authorized for facade: #{facade}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -3,5 +3,5 @@
|
||||
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
||||
|
||||
module BitPay
|
||||
VERSION = '2.3.1'
|
||||
VERSION = '2.3.3'
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user