hash_hmac sha512 authentication in python - python

I'm trying to write python authentication bot for: https://comkort.com/page/private_api
There is no full php example. I'm guess somebody could put it here.
There is only snippet of php code:
$query_string = http_build_query($_POST, '', '&');
$ethalon_sign = hash_hmac("sha512", $query_string, $api_secret_key);
How to write authentication on python with hash_hmac sha512 ?
I want to extract my open orders POST https://api.comkort.com/v1/private/order/list.
My current variant is:
import hashlib
import hmac
import requests
import time
privateKey = b'myprivatekey'
publicKey = 'my public key'
url = 'https://api.comkort.com/v1/private/order/list'
tosign = b'market_alias=doge_ltc'
signing = hmac.new( privateKey , tosign, hashlib.sha512 )
headers = {'sign': signing.digest(), "apikey": publicKey, "nonce": int( time.time() ) }
r = requests.get(url, headers=headers)
print r.text
I'm caught this
{"code":401,"error":"Invalid sign","field":"sign"}
May be hexdigest() instead digest()? I don't know, I'm playing around this b prefix and different output hmac's options, everytime I'm caught one error: "Invalid sign".
Related: HMAC signing requests in Python

If somebody interesting, I've solve this by myself.
#!/usr/bin/python
import hashlib
import hmac
import requests
import time
apikey = '';
apisecret = '';
def request_comkort( url, payload ):
tosign = "&".join( [i + '=' + payload[i] for i in payload] )
sign = hmac.new( apisecret, tosign , hashlib.sha512);
headers = {'sign': sign.hexdigest(), 'nonce': int( time.time() ), 'apikey': apikey }
r = requests.post(url, data=payload, headers=headers)
return r.text
# Get balance
print request_comkort( "https://api.comkort.com/v1/private/user/balance";, {} )
# Get Open Orders
print request_comkort( "https://api.comkort.com/v1/private/order/list";, {'market_alias': "DOGE_LTC" } )
# Make Ask
print request_comkort( "https://api.comkort.com/v1/private/order/sell";, { 'market_alias':"HTML_DOGE", "amount": "1000", "price": "123123" } )
# Cancel order
print request_comkort( "https://api.comkort.com/v1/private/order/cancel";, { 'order_id': 10943 } )

Related

Bybit api connection "retCode":10004,"retMsg":"error sign!"

According to official documentation https://bybit-exchange.github.io/docs/derivativesV3/unified_margin/#t-constructingtherequest I try to get account balance endpoint: GET /unified/v3/private/account/wallet/balance. But anyway I get this response: {"retCode":10004,"retMsg":"error sign!","result":null,"retExtInfo":null,"time":1665751778451}
from urllib.parse import urlencode
import requests
import hashlib
import time
import hmac
import uuid
api_key = 'xxxxxxxxxxxx'
secret_key = 'xxxxxxxxxxxxxxxxxxxx'
httpClient = requests.Session()
recv_window = "5000"
url = "https://api.bybit.com"
def HTTP_Request(endPoint, method, payload):
time_stamp = requests.get(url + "/v3/public/time").json()
time_stamp = str(time_stamp["time"])
signature = genSignature(params, time_stamp)
headers = {
'X-BAPI-SIGN-TYPE': '2',
'X-BAPI-SIGN': signature,
'X-BAPI-API-KEY': api_key,
'X-BAPI-TIMESTAMP': time_stamp,
'X-BAPI-RECV-WINDOW': recv_window
}
response = httpClient.request(method, url+endpoint+"?"+payload, headers=headers)
print(response.text)
def genSignature(payload, time_stamp):
# encoding list obj to url format str
peyload_url_enc = urlencode(
sorted(payload.items(), key=lambda tup: tup[0])
)
param_str = str(time_stamp) + api_key + recv_window + peyload_url_enc
hash = hmac.new(
key=bytes(secret_key, "utf-8"),
msg=param_str.encode("utf-8"),
digestmod="sha256"
)
signature = hash.hexdigest()
return signature
endpoint = "/unified/v3/private/account/wallet/balance"
method = "GET"
params = {"coin": "USDT"}
HTTP_Request(endpoint, method, str(params))
The problem seems to be in genSignature, but no matter how I change the function, the error remains the same
Thanks to this repository I found another method of connecting to the Bybit. So if you faced with similar problem, open the link, there are also some examples of creating different post/get queries
My working variant:
def bybit_spot_balance(AccessKey: str, SecretKey: str) -> dict:
params = {
"api_key": AccessKey,
"timestamp": round(time.time() * 1000),
"recv_window": 10000
}
# Create the param str
param_str = urlencode(
sorted(params.items(), key=lambda tup: tup[0])
)
# Generate the signature
hash = hmac.new(
bytes(SecretKey, "utf-8"),
param_str.encode("utf-8"),
hashlib.sha256
)
signature = hash.hexdigest()
sign_real = {
"sign": signature
}
param_str = quote_plus(param_str, safe="=&")
full_param_str = f"{param_str}&sign={sign_real['sign']}"
# Request information
url = "https://api.bybit.com/spot/v3/private/account"
headers = {"Content-Type": "application/json"}
body = dict(params, **sign_real)
urllib3.disable_warnings()
response = requests.get(f"{url}?{full_param_str}", headers=headers, verify=False).json()
return response

REST request to App Store Connect API response with '401' | 'NOT_AUTHORIZED'

we launched an iOS-App and I want to grab some Information (e.g. Installations, Updates, Reviews) from the App Store Connect API.
I create an JSON Web Token as described in the official Apple documentation: Link
Afterwards I make a request with the token in the header. Now I get an '401' | 'NOT_AUTHORIZED' each time as an answer, see the following picture:
REST Response
In the following snippets you can see my python code (I tried to solve it in Python and R, but the result is always the same).
First, I create an JWT:
from datetime import datetime, timedelta
from jose import jwt, jws
import ecdsa
KEY_ID = "XXXXXXXXXX"
ISSUER_ID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read()
TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp() * 1000)
claim = {"iss" : ISSUER_ID,
"exp" : TIMESTAMP,
"aud" : "appstoreconnect-v1"}
header = {
"alg": "ES256",
"kid": KEY_ID,
"typ": "JWT"
}
# Create the JWT
encoded = jwt.encode(claim, PRIVATE_KEY, algorithm='ES256', headers=header)
Now when I print encoded, I get to following JWT (looks valid for me):
'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ.eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9.eTl6iaAW-Gp67FNmITrWCpLTtJzVdLYXIl5_KKgqaNgzwyGo7npBOBo9_u5PtLNnssQFEwJWbPND-6Ww5ACgEg'
Even if I decode the first two parts of the JWT via Base64 I get the right Header (it also contains the right algorithm for encoding: 'alg': 'ES256') and Claim:
from jose.utils import base64url_decode
print(base64url_decode(b'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ'))
print(base64url_decode(b'eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9'))
See the following picture: Output Base64 Decoding
So now, that I'm think that the JWT-Object is ready I send the request to the API:
import requests
JWT = 'Bearer ' + encoded
URL = 'https://api.appstoreconnect.apple.com/v1/apps'
HEAD = {'Authorization': JWT}
print(HEAD)
R = requests.get(URL, headers=HEAD)
R.json()
And now we can see my problem, see the picture: Header | REST Response
Please note that I have hidden the KEY_ID, ISSUER_ID and PRIVATE_KEY for the example.
Your token contains an expiry time
"exp": 1545397514580,
which equals September 12th, 50941.
When I delete the last three digits
"exp": 1545397514,
I get December 21st, 2018
which makes much more sense.
Change that line
TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp() * 1000)
to
TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp())
exp is a timestamp that is defined as seconds since 01.01.1970 00:00
See also here
First of all, please don't open files without context managers. This string:
PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read()
should be:
with open('AuthKey_XXXXXXXXXX.p8', 'r') as f:
PRIVATE_KEY = f.read()
It save you from many problems with unclosed files in future.
Then, check what token you've read from file. Is it correct?
The next problem I see is timestamp. "The token's expiration time, in Unix epoch time;" You provide it in milliseconds, I guess.
Here is working solution for me. Without delay it return 401 error
KEY_ID = "xxxxx"
ISSUER_ID = "xxxxx"
EXPIRATION_TIME = int(round(time.time() + (20.0 * 60.0))) # 20 minutes timestamp
PATH_TO_KEY = '../credentials/AuthKey_xxxxx.p8'
with open(PATH_TO_KEY, 'r') as f:
PRIVATE_KEY = f.read()
header = {
"alg": "ES256",
"kid": KEY_ID,
"typ": "JWT"
}
payload = {
"iss": ISSUER_ID,
"exp": EXPIRATION_TIME,
"aud": "appstoreconnect-v1"
}
# Create the JWT
token = jwt.encode(header, payload, PRIVATE_KEY)
JWT = 'Bearer ' + token.decode()
HEAD = {'Authorization': JWT}
# Without delay I got 401 error
time.sleep(5)
URL = 'https://api.appstoreconnect.apple.com/v1/apps';
r = requests.get(URL, params={'limit': 200}, headers=HEAD)

twitter oauth with python

i'm trying to access twitter using the api
i created an app and checked "Allow this application to be used to Sign in with Twitter", then i followed these steps:
https://dev.twitter.com/docs/api/1/post/oauth/request_token
https://dev.twitter.com/docs/auth/authorizing-request
https://dev.twitter.com/docs/auth/creating-signature
but i'm getting
urllib2.HTTPError: HTTP Error 401: Unauthorized
so i must have done something wrong or missed something
can somebody spot my mistake?
import urllib2
import time
import urllib
import hashlib
import hmac
import base64
def escape(s):
return urllib.quote(s, safe='~')
consumer_key = 'yBsHl3G6MqXx9JpnoLoGbA'
consumer_secret = 'JBk5oUDLSuNAXxdBHrDmoUFxemw7IJ1a2yWPmCydX7w'
http_method = 'POST'
base_url = 'https://api.twitter.com/oauth/request_token'
oauth_token_secret = ''
data={'oauth_callback':'http://localhost.de:8000/accounts/callback/twitter'}
header = {
'oauth_consumer_key': consumer_key,
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': hashlib.md5(str(time.clock())).hexdigest(),
'oauth_version': '1.0',
'oauth_signature_method': 'HMAC-SHA1'
}
header.update(data)
paramstr = ''
for k in sorted(header):
paramstr+=escape(k)+'='+escape(header[k])+'&'
paramstr = paramstr[:-1]
print paramstr
sig_base_str = http_method.upper()+'&'+escape(base_url)+'&'+escape(paramstr)
print sig_base_str
key = escape(consumer_secret)+'&'+escape(oauth_token_secret)
signature = base64.b64encode(hmac.new(key, sig_base_str, hashlib.sha1).digest())
header['oauth_signature'] = signature
header_str = 'OAuth '
for k in sorted(header):
header_str+=escape(k)+'="'+escape(header[k])+'", '
header_str = header_str[:-2]
print header_str
req=urllib2.Request(base_url, data=urllib.urlencode(data))
req.add_header('Authorization', header_str)
print urllib2.urlopen(req).read()
i know there are libs for doing this, but i would like to write my own code for testing purposes
i solved it myself. the twitter docs are not 100% correct.
for example here
https://dev.twitter.com/docs/api/1/post/oauth/request_token
they say that the authorization header should look like this
OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw", oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1300228849", oauth_consumer_key="OqEqJeafRSF11jBMStrZz", oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D", oauth_version="1.0"
but this is wrong, you should not add oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback" to the authorization header

Cannot get DELETE working with liburl2 with python for REST api

Okay so I'm using code very similar to this (https://gist.github.com/metadaddy-sfdc/1374762)
to get authentication token and do simple query's using the libur2 for the rest api in python for a sales force database, but when I tried to follow the instructions which were given in this answer How to make HTTP DELETE method using urllib2?,
I cannot get it to work so that I can use delete, both codes use liburl but they seem to be in different format, so that I don't know how to apply the solution offered on stack exchange, to my code, as you can tell I am a beginner so any help would be greatly appreciated
edit:
here is the code I'm using with keys/passwords blanked
import urllib
import urllib2
import json
import pprint
import re
import subprocess
def authorise():
consumer_key = '**********************'
consumer_secret = '**************'
username = '***********'
password = '*****************'
login_server = 'https://login.salesforce.com'
token_url = login_server+'/services/oauth2/token'
params = urllib.urlencode({
'grant_type': 'password',
'client_id': consumer_key,
'client_secret': consumer_secret,
'username': username,
'password': password
})
data = urllib2.urlopen(token_url, params).read()
oauth = json.loads(data)
return oauth
def country_id_query(params):
query_url = oauth['instance_url']+'/services/data/v23.0/query?%s' % params
headers = {
'Authorization': 'OAuth '+oauth['access_token']
}
req = urllib2.Request(query_url, None, headers)
data = urllib2.urlopen(req).read()
result = json.loads(data)
id = result['records'][0]['Id']
return id
oauth = authorise()
token = oauth['access_token']
print "\ntoken is = " + token
params = urllib.urlencode({
'q': 'SELECT id from Country__c WHERE name = \'A New Found Land\''
})
id = country_id_query(params)
print "\nCountry id is "+id + "\n"
I am looking to find out what I need to add to this to get DELETE working
Okay, found the solution to above for anyone with a similar problem:
def delete_country(id):
query_url = oauth['instance_url']+'/services/data/v23.0/sobjects/Country__c/%s' % id + '/'
headers = {
'Authorization': 'OAuth '+oauth['access_token']
}
opener = urllib2.build_opener(urllib2.HTTPHandler)
req = urllib2.Request(query_url, None, headers)
req.get_method = lambda: 'DELETE' # creates the delete method
url = urllib2.urlopen(req) # deletes database item

Yahoo BOSS V2 authorization troubles

I'm having an awfully hard time with Yahoo's authentication/authorization. I've enabled BOSS in my account, set up a payment method, and now I'm trying to run a search using some python code:
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
params['oauth_version'] = "1.0",
params['oauth_nonce'] = oauth.generate_nonce(),
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
req_url = req.to_url()
print req_url
result = urllib2.urlopen(req_url)
I keep getting a urllib2.HTTPError: HTTP Error 401: Unauthorized exception. I can't figure out whether there's something wrong with my key, or the method of signing, or if I'm somehow tampering with my data after signing, or what the deal is. Anyone have suggestions?
I made some small changes to make your example work. See code for comments.
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
# Removed trailing commas here - they make a difference.
params['oauth_version'] = "1.0" #,
params['oauth_nonce'] = oauth.generate_nonce() #,
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
# This one is a bit nasty. Apparently the BOSS API does not like
# "+" in its URLs so you have to replace "%20" manually.
# Not sure if the API should be expected to accept either.
# Not sure why to_url does not just return %20 instead...
# Also, oauth2.Request seems to store parameters as unicode and forget
# to encode to utf8 prior to percentage encoding them in its to_url
# method. However, it's handled correctly for generating signatures.
# to_url fails when query parameters contain non-ASCII characters. To
# work around, manually utf8 encode the request parameters.
req['q'] = req['q'].encode('utf8')
req_url = req.to_url().replace('+', '%20')
print req_url
result = urllib2.urlopen(req_url)
Here is a Python code snippet that works for me against Yahoo! BOSS:
import httplib2
import oauth2
import time
OAUTH_CONSUMER_KEY = "Blah"
OAUTH_CONSUMER_SECRET = "Blah"
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web?q=cats%20dogs"
consumer = oauth2.Consumer(key=OAUTH_CONSUMER_KEY,secret=OAUTH_CONSUMER_SECRET)
params = {
'oauth_version': '1.0',
'oauth_nonce': oauth2.generate_nonce(),
'oauth_timestamp': int(time.time()),
}
oauth_request = oauth2.Request(method='GET', url=url, parameters=params)
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, None)
oauth_header=oauth_request.to_header(realm='yahooapis.com')
# Get search results
http = httplib2.Http()
resp, content = http.request(url, 'GET', headers=oauth_header)
print resp
print content
Im using an Authenticate Header to submit the OAuth signature.
So I decided to ditch Python and try Perl, and it Just Worked. Here's a minimal code sample:
use strict;
use Net::OAuth;
use LWP::UserAgent;
my $CC_KEY = "blahblahblah";
my $CC_SECRET = "blah";
my $url = 'http://yboss.yahooapis.com/ysearch/web';
print make_request($url, {q => "cat dog", format => "xml", count => 5});
sub make_request {
my ($url, $args) = #_;
my $request = Net::OAuth->request("request token")
->new(
consumer_key => $CC_KEY,
consumer_secret => $CC_SECRET,
request_url => $url,
request_method => 'GET',
signature_method => 'HMAC-SHA1',
timestamp => time,
nonce => int(rand 10**6),
callback => 'oob',
extra_params => $args,
protocol_version => Net::OAuth::PROTOCOL_VERSION_1_0A,
);
$request->sign;
my $res = LWP::UserAgent->new(env_proxy=>1)->get($request->to_url);
return $res->content if $res->is_success;
die $res->status_line;
}
Here's another solution, this time back in python-land. This was put together by Tom De Smedt, author of the Pattern web-mining kit.
I'll communicate with the author of python-oauth2 to see if it can be fixed.
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
import urllib
import hmac
import time
import random
import base64
try:
from hashlib import sha1
from hashlib import md5
except:
import sha as sha1
import md5; md5=md5.new
def hmac_sha1(key, text):
return hmac.new(key, text, sha1).digest()
def oauth_nonce(length=40):
h = "".join([str(random.randint(0, 9)) for i in range(length)])
h = md5(str(time.time()) + h).hexdigest()
return h
def oauth_timestamp():
return str(int(time.time()))
def oauth_encode(s):
return urllib.quote(s, "~")
def oauth_signature(url, data={}, method="get", secret="", token=""):
# Signature base string: http://tools.ietf.org/html/rfc5849#section-3.4.1
base = oauth_encode(method.upper()) + "&"
base += oauth_encode(url.rstrip("?")) + "&"
base += oauth_encode("&".join(["%s=%s" % (k, v) for k, v in sorted(data.items())]))
# HMAC-SHA1 signature algorithm: http://tools.ietf.org/html/rfc5849#section-3.4.2
signature = hmac_sha1(oauth_encode(secret) + "&" + token, base)
signature = base64.b64encode(signature)
return signature
q = "cat"
url = "http://yboss.yahooapis.com/ysearch/" + "web" # web | images | news
data = {
"q": q,
"start": 0,
"count": 50, # 35 for images
"format": "xml",
"oauth_version": "1.0",
"oauth_nonce" : oauth_nonce(),
"oauth_timestamp" : oauth_timestamp(),
"oauth_consumer_key" : OAUTH_CONSUMER_KEY,
"oauth_signature_method" : "HMAC-SHA1",
}
data["oauth_signature"] = oauth_signature(url, data, secret=OAUTH_CONSUMER_SECRET)
complete_url = url + "?" + urllib.urlencode(data)
response = urllib.urlopen(complete_url)
print response.read()
Here is sample code to access Yahoo! BOSS API v2 using with python-oauth as oauth liberary.
OAUTH_CONSUMER_KEY = "<oauth consumer key>"
OAUTH_CONSUMER_SECRET = "<oauth consumer secret>"
URL = "http://yboss.yahooapis.com/ysearch/web"
import urllib
import oauth.oauth as oauth
data = {
"q": "yahoo boss search",
"start":0,
"count":2,
"format":"json"
}
consumer = oauth.OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET)
signature_method_plaintext = oauth.OAuthSignatureMethod_PLAINTEXT()
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method='GET', http_url=URL, parameters=data)
oauth_request.sign_request(signature_method_hmac_sha1, consumer, "")
complete_url = oauth_request.to_url()
response = urllib.urlopen(complete_url)
print "REQUEST URL => %s" % complete_url
print ""
print "RESPONSE =>"
print response.read()
I stepped into the urllib2.open code using the debugger, and found that the response has this header:
WWW-Authenticate: OAuth oauth_problem="version_rejected", realm="yahooapis.com"
So I guess I'm having some kind of version mismatch of OAuth.

Categories