move coinify vendor stuff to a submodule

This commit is contained in:
Thomas Steen Rasmussen 2017-03-24 01:58:04 +01:00
parent 8956c5300f
commit 5ef381f973
5 changed files with 2 additions and 294 deletions

View file

@ -35,8 +35,8 @@ from shop.models import (
from .forms import AddToOrderForm from .forms import AddToOrderForm
from .epay import calculate_epay_hash, validate_epay_callback from .epay import calculate_epay_hash, validate_epay_callback
from collections import OrderedDict from collections import OrderedDict
from vendor.coinify_api import CoinifyAPI from vendor.coinify.coinify_api import CoinifyAPI
from vendor.coinify_callback import CoinifyCallback from vendor.coinify.coinify_callback import CoinifyCallback
import json, time import json, time
import logging import logging
logger = logging.getLogger("bornhack.%s" % __name__) logger = logging.getLogger("bornhack.%s" % __name__)

View file

1
src/vendor/coinify vendored

@ -1 +0,0 @@
Subproject commit abc76101756a95e59abc8dd13e50a45d26855ccb

View file

@ -1,268 +0,0 @@
import requests, json, time, hashlib, hmac
class CoinifyAPI:
api_key = None
"""Coinify API key. Get yours at https://www.coinify.com/merchant/api"""
api_secret = None
"""Coinify API secret. Get yours at https://www.coinify.com/merchant/api"""
api_base_url = None
"""Base URL to the Coinify API"""
API_DEFAULT_BASE_URL = "https://api.coinify.com"
def __init__(self, api_key=None, api_secret=None, api_base_url=None):
"""
Create an instance of the CoinifyAPI class.
Provide your API key and API secret.
Set api_base_url to None to use default
"""
self.api_key = api_key
self.api_secret = api_secret
self.api_base_url = api_base_url or self.API_DEFAULT_BASE_URL
def invoices_list(self, limit=None, offset=None, include_expired=None):
"""
Returns an array of your Coinify invoices
See https://www.coinify.com/docs/api/#list-all-invoices
"""
query_params = {}
if limit is not None:
query_params['limit'] = limit
if offset is not None:
query_params['offset'] = offset
if include_expired is not None:
query_params['include_expired'] = include_expired
return self.call_api_authenticated('/v3/invoices', query_params=query_params)
def invoice_create(self, amount, currency, plugin_name, plugin_version,
description=None, custom=None, callback_url=None, callback_email=None,
return_url=None, cancel_url=None, input_currency=None, input_return_address=None):
"""
Create a new invoice.
See https://www.coinify.com/docs/api/#create-an-invoice
"""
params = {
'amount': amount,
'currency': currency,
'plugin_name': plugin_name,
'plugin_version': plugin_version
}
if description is not None:
params['description'] = description
if custom is not None:
params['custom'] = custom
if callback_url is not None:
params['callback_url'] = callback_url
if callback_email is not None:
params['callback_email'] = callback_email
if return_url is not None:
params['return_url'] = return_url
if cancel_url is not None:
params['cancel_url'] = cancel_url
if input_currency is not None:
params['input_currency'] = input_currency
if input_return_address is not None:
params['input_return_address'] = input_return_address
return self.call_api_authenticated('/v3/invoices', 'POST', params)
def invoice_get(self, invoice_id):
"""
Get a specific invoice
See https://www.coinify.com/docs/api/#get-a-specific-invoice
"""
path = '/v3/invoices/%d' % (invoice_id,)
return self.call_api_authenticated(path)
def invoice_update(self, invoice_id, description=None, custom=None):
"""
Update the description and custom data of an invoice
See https://www.coinify.com/docs/api/#update-an-invoice
"""
params = {}
if description is not None:
params['description'] = description
if custom is not None:
params['custom'] = custom
path = '/v3/invoices/%d' % (invoice_id,)
return self.call_api_authenticated(path, 'PUT', params)
def invoice_input_create(self, invoice_id, currency, return_address):
"""
Request for an invoice to be paid with another input currency.
See https://www.coinify.com/docs/api/#pay-with-another-input-currency
"""
params = {
'currency': currency,
'return_address': return_address
}
path = '/v3/invoices/%d/inputs' % (invoice_id,)
return self.call_api_authenticated(path, 'POST', params)
def buy_orders_list(self, limit=None, offset=None, include_cancelled=None):
"""
Returns an array of your Coinify buy orders
See https://www.coinify.com/docs/api/#list-all-buy-orders
"""
query_params = {}
if limit is not None:
query_params['limit'] = limit
if offset is not None:
query_params['offset'] = offset
if include_cancelled is not None:
query_params['include_cancelled'] = include_cancelled
return self.call_api_authenticated('/v3/buys', query_params=query_params)
def buy_order_create(self, amount, currency, btc_address, instant_order=None,
callback_url=None, callback_email=None):
"""
Create a new buy order
See https://www.coinify.com/docs/api/#create-a-buy-order
"""
params = {
'amount': amount,
'currency': currency,
'btc_address': btc_address
}
if instant_order is not None:
params['instant_order'] = instant_order
if callback_url is not None:
params['callback_url'] = callback_url
if callback_email is not None:
params['callback_email'] = callback_email
return self.call_api_authenticated('/v3/buys', 'POST', params)
def buy_order_confirm(self, buy_order_id):
"""
Confirm a buy order
See https://www.coinify.com/docs/api/#buy-order-confirm
"""
path = '/v3/buys/%d/actions/confirm' % (buy_order_id,)
return self.call_api_authenticated(path, 'PUT')
def buy_order_get(self, buy_order_id):
"""
Get a specific buy order
See https://www.coinify.com/docs/api/#get-a-specific-buy-order
"""
path = '/v3/buys/%d' % (buy_order_id,)
return self.call_api_authenticated(path)
def rates_get(self, currency=None):
"""
Return buy and sell rates for all available currencies or for the specified currency.
:param self:
:param currency|None: A 3-char currency code
:return:
"""
if currency is None:
path = '/v3/rates'
else:
path = '/v3/rates/%s' % (currency,)
return self.call_api_authenticated(path)
def balance_get(self):
"""
Get the balance of a merchant
:param path:
:return: An array as described in https://www.coinify.com/docs/api/#check-account-balance . If success,
then the 'data' value contains the balance in BTC and fiat currency and also the base currency
of the merchant that requests it.
"""
path = '/v3/balance'
return self.call_api_authenticated(path)
def input_currencies_list(self):
"""
Receive a list of supported input currencies
"""
return self.call_api('/v3/input-currencies')
def call_api_authenticated(self, path, method='GET', params={}, query_params={}):
"""
Perform an authenticated API call, using the
API key and secret provided in the constructor.
path: API path, WITH a leading slash, e.g. '/v3/invoices'
params: dict with parameters to send with the API call
Returns a dict as described in https://www.coinify.com/docs/api/#response-format,
or None if the HTTP call couldn't be performed correctly.
"""
extra_headers = {
'Authorization': self.generate_authorization_header()
}
return self.call_api(path, method, params, query_params, extra_headers)
def call_api(self, path, method='GET', params={}, query_params={}, headers={}):
"""
Perform an API call
path: API path, WITH a leading slash, e.g. '/v3/invoices'
params: dict with parameters to send with the API call
Returns a dict as described in https://www.coinify.com/docs/api/#response-format,
or None if the HTTP call couldn't be performed correctly.
"""
url = self.api_base_url + path
headers['Content-Type'] = 'application/json'
if self.api_key is not None:
headers['Authorization'] = self.generate_authorization_header()
r = requests.request(method, url, json=params, headers=headers, params=query_params)
return r.json()
def generate_authorization_header(self):
"""
Generate a nonce and a signature for an API call
and wrap those in a HTTP header
"""
# Generate nonce, based on the current Unix timestamp
nonce = str(int(time.time() * 1000000))
# Concatenate nonce and API key
message = nonce + self.api_key
# Compute signature
signature = hmac.new(self.api_secret, msg=message, digestmod=hashlib.sha256).hexdigest()
# Construct the header value
header_value = 'Coinify apikey="%s", nonce="%s", signature="%s"' % (self.api_key, nonce, signature)
return header_value

View file

@ -1,23 +0,0 @@
import hashlib, hmac
class CoinifyCallback:
"""
Class to validate callbacks from Coinfy
"""
ipn_secret = None
"""Coinify IPN callback secret. Get yours at https://www.coinify.com/merchant/ipn"""
def __init__( self, ipn_secret ):
self.ipn_secret = ipn_secret
def validate_callback( self, callback_raw, signature ):
"""
Validates a callback and it's signature based on the IPN secret given in the constructor.
callback_raw must contain the raw JSON POST data sent with the callback (before any JSON decoding)
signature must contain the signature as extracted from the 'X-Coinify-Callback-Signature' header,
which should be a 64-byte hexadecimal string
"""
return signature == hmac.new(self.ipn_secret, msg=callback_raw, digestmod=hashlib.sha256).hexdigest()