ruby-client/lib/bitpay/client.rb
Paul Daigle c95945e710 Remove bitpay client.
Bitpay client removed, bitpay bin for client removed.
Features modified to run with local token/key saved or not.
Rake task to clean up local files if created.
Rake task to run all tests, cucumbers, and clean up.

Move local file constants to the cucumber helper
2014-12-29 17:06:28 -05:00

182 lines
5.7 KiB
Ruby

# license Copyright 2011-2014 BitPay, Inc., MIT License
# see http://opensource.org/licenses/MIT
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
require 'uri'
require 'net/https'
require 'json'
require_relative 'key_utils'
module BitPay
# This class is used to instantiate a BitPay Client object. It is expected to be thread safe.
#
class Client
# @return [Client]
# @example
# # Create a client with a pem file created by the bitpay client:
# client = BitPay::Client.new
def initialize(opts={})
@pem = opts[:pem] || ENV['BITPAY_PEM'] || KeyUtils.generate_pem
@key = KeyUtils.create_key @pem
@priv_key = KeyUtils.get_private_key @key
@pub_key = KeyUtils.get_public_key @key
@client_id = KeyUtils.generate_sin_from_pem @pem
@uri = URI.parse opts[:api_uri] || API_URI
@user_agent = opts[:user_agent] || USER_AGENT
@https = Net::HTTP.new @uri.host, @uri.port
@https.use_ssl = true
@https.ca_file = CA_FILE
@tokens = opts[:tokens] || {}
# Option to disable certificate validation in extraordinary circumstance. NOT recommended for production use
@https.verify_mode = opts[:insecure] == true ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
# Option to enable http request debugging
@https.set_debug_output($stdout) if opts[:debug] == true
end
def pair_pos_client(claimCode)
raise BitPay::ArgumentError, "pairing code is not legal" unless verify_claim_code(claimCode)
response = set_pos_token(claimCode)
get_token 'pos'
response
end
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: 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"]
end
def get_public_invoice(id:)
request = Net::HTTP::Get.new("/invoices/#{id}")
response = process_request(request)
response["data"]
end
def set_token
end
def verify_token
server_tokens = load_tokens
@tokens.each{|key, value| return false if server_tokens[key] != value}
return true
end
## Generates REST request to api endpoint
def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
token ||= get_token(facade)
# Verb-specific logic
case verb.upcase
when "GET"
urlpath = '/' + path + '?nonce=' + KeyUtils.nonce + '&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[:nonce] = KeyUtils.nonce
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
## Requests token by appending nonce and signing URL
# Returns a hash of available tokens
#
def load_tokens
urlpath = '/tokens?nonce=' + KeyUtils.nonce
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
## Retrieves specified token from hash, otherwise tries to refresh @tokens and retry
def set_pos_token(claim_code)
params = {pairingCode: claim_code}
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] || load_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.nil?)
end
end
end