How to sign a POST request using HMAC-SHA512 and the Python request library?

I am trying to use Python to access the trading API on poloniex.com, cryptocurrency exchange. To do this, I must follow this recipe:

All trading API calls are sent via HTTP POST to https://poloniex.com/tradingApi and should contain the following headers:

The key is your API key.
Sign - POST request data signed with your key "secretly" in accordance with the HMAC-SHA512 method.

In addition, all requests must include the "nonce" POST parameter. The nonce parameter is an integer that must always be greater than the previous unused one.

Here is what I still have. My current problem is that I don’t know how to compile the POST URL so that it can be signed without initially requesting an incomplete request. This is clearly not working.

import requests import hmac import hashlib import time headers = { 'nonce': '', 'Key' : 'myKey', 'Sign': '',} payload = { 'command': 'returnCompleteBalances', 'account': 'all'} secret = 'mySecret' headers['nonce'] = int(time.time()) response = requests.post( 'https://poloniex.com/tradingApi', params= payload, headers= headers ) headers['Sign'] = hmac.new( secret, response.url, hashlib.sha512) 
+5
source share
1 answer

Create a prepared request ; you can add headers to them after creating the body:

 import requests import hmac import hashlib request = requests.Request( 'POST', 'https://poloniex.com/tradingApi', data=payload, headers=headers) prepped = request.prepare() signature = hmac.new(secret, prepped.body, digestmod=hashlib.sha512) prepped.headers['Sign'] = signature.hexdigest() with requests.Session() as session: response = session.send(prepped) 

I changed your params argument to data ; for a POST request, it is customary to send parameters in the body, not in the URL.

For nonce, I would use the itertools.count() object sown from the current time, so restarting does not affect it. According to the Poloniex API documentation (which you quoted in your question), nonce is part of the POST body, not the headers, so it is in the payload dictionary:

 from itertools import count import time # store as a global variable NONCE_COUNTER = count(int(time.time() * 1000)) # then every time you create a request payload['nonce'] = next(NONCE_COUNTER) 

Using int(time.time()) will reuse the same number if you created more than one request per second. In the example presented by Poloniex , int(time.time()*1000) is used to create a request for every microsecond instead, but using its monotonically increasing counter (seeded from time.time() ) is much more reliable.

You can also encapsulate the digest signing process in a user authentication object ; such an object is transmitted in the prepared request as the last step in the preparation process:

 import hmac import hashlib class BodyDigestSignature(object): def __init__(self, secret, header='Sign', algorithm=hashlib.sha512): self.secret = secret self.header = header self.algorithm = algorithm def __call__(self, request): body = request.body if not isinstance(body, bytes): # Python 3 body = body.encode('latin1') # standard encoding for HTTP signature = hmac.new(self.secret, body, digestmod=self.algorithm) request.headers[self.header] = signature.hexdigest() return request 

Use this for requests calls:

 response = requests.post( 'https://poloniex.com/tradingApi', data=payload, headers=headers, auth=BodyDigestSignature(secret)) 

The argument passed is the secret used in the HMAC digest; You can also pass a different header name.

+11
source

Source: https://habr.com/ru/post/1263941/


All Articles