s4w3d0ff / python-poloniex

Poloniex API wrapper for Python 2.7 & 3
https://poloniex.com/support/api
GNU General Public License v2.0
568 stars 166 forks source link

Hmac Library issue? Expected Bytes or ByteArray, but got string when creating "sign" function #3

Closed TheDeafMute closed 8 years ago

TheDeafMute commented 8 years ago
bot.myAvailBalances()
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    bot.myAvailBalances()
  File "C:\Python35\lib\poloniex.py", line 46, in <lambda>
    self.myAvailBalances = lambda x=0: self.api('returnAvailableAccountBalances')
  File "C:\Python35\lib\poloniex.py", line 85, in api
    sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest()
  File "C:\Python35\lib\hmac.py", line 144, in new
    return HMAC(key, msg, digestmod)
  File "C:\Python35\lib\hmac.py", line 42, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
s4w3d0ff commented 8 years ago

Interesting, I will look deeper into it. Could just try to convert the str into a bytearray...

s4w3d0ff commented 8 years ago

http://stackoverflow.com/questions/31848293/python3-and-hmac-how-to-handle-string-not-being-binary

I'll make the fix soon, for now you can probably get away with what was suggested in the above link.

So when you pass your Secret key to the Poloiex object use: bot = poloniex.Poloniex('yourApiKeyHere', b'yourSecretKeyHere123')

Not sure if it will work but worth the shot.

TheDeafMute commented 8 years ago

Ohhh ok so the byte has to be assigned in the creation of the polo class instance? I tried changing the func call here: sign = hmac.new(bytearray(self.Secret.encode('utf-8')), bytes(post_data).encode('utf-8'), hashlib.sha512).hexdigest()

to each object trying different ways of converting each to a byte and bytearray and even tried using .encode() method which I heard might work - will try changing it in that part of the code, thanks.

s4w3d0ff commented 8 years ago

Sorry I can't be more help, my machine is waiting for a new PSU and I'm on my tablet.

TheDeafMute commented 8 years ago
bot2 = Poloniex('xxxx', b'xxxx')
bot2.myAvailBalances('lending')
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    bot2.myAvailBalances('lending')
  File "C:\Python35\lib\poloniex.py", line 46, in <lambda>
    self.myAvailBalances = lambda x=0: self.api('returnAvailableAccountBalances')
  File "C:\Python35\lib\poloniex.py", line 86, in api
    sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest()
  File "C:\Python35\lib\hmac.py", line 144, in new
    return HMAC(key, msg, digestmod)
  File "C:\Python35\lib\hmac.py", line 84, in __init__
    self.update(msg)
  File "C:\Python35\lib\hmac.py", line 93, in update
    self.inner.update(msg)
TypeError: Unicode-objects must be encoded before hashing
TheDeafMute commented 8 years ago

When I use .encode('utf-8') in the "key" value of the sign variable like sign = hmac.new(self.Secret.encode('utf-8'), post_data, hashlib.sha512), - I get an error saying bytes type cannot be encoded

>>>bot.myAvailBalances('lending')
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    bot.myAvailBalances('lending')
  File "C:\Python35\lib\poloniex.py", line 46, in <lambda>
    self.myAvailBalances = lambda x=0: self.api('returnAvailableAccountBalances')
  File "C:\Python35\lib\poloniex.py", line 86, in api
    sign = hmac.new(self.Secret.encode('utf-8'), post_data, hashlib.sha512).hexdigest()
AttributeError: 'bytes' object has no attribute 'encode'
TheDeafMute commented 8 years ago

Maybe this problem only occurs in 3.5+ -- Havent tried on 3.4-- but it definitely does work with 2.7, although I need coroutines from 3+ :P

TheDeafMute commented 8 years ago

Doubtful this will work - but trying changing --- def __init__(self, APIKey='', Secret=' ') to be def __init__(self, APIKey='', Secret=b'')

edit: nope

TheDeafMute commented 8 years ago

Found this with more info: http://lucumr.pocoo.org/2014/1/5/unicode-in-2-and-3/

"The main difference between Python 2 and Python 3 is the basic types that exist to deal with texts and bytes. On Python 3 we have one text type: str which holds Unicode data and two byte types bytes and bytearray.

On the other hand on Python 2 we have two text types: str which for all intents and purposes is limited to ASCII + some undefined data above the 7 bit range, unicode which is equivalent to the Python 3 str type and one byte type bytearray which it inherited from Python 3.

Looking at that you can see that Python 3 removed something: support for non Unicode data text. For that sacrifice it gained a hashable byte type, the bytes object. bytearray is a mutable type, so it's not suitable for hashing. I very rarely use true binary data as dictionary keys though so it does not show up as big problem. Especially not because in Python 2, you can just put bytes into the str type without issues."

s4w3d0ff commented 8 years ago

Perhaps this is the fix? https://github.com/s4w3d0ff/python-poloniex/issues/2

Edit: Yup, tested in 3.4.3 and it works, making a commit now...

TheDeafMute commented 8 years ago

Yep, it worked perfectly -- Thank you

Kailisic commented 8 years ago

The problem remains how to fix

balance = polo.api('returnBalances')
  File "/usr/local/lib/python3.4/dist-packages/poloniex-0.1-py3.4.egg/poloniex/__init__.py", line 279, in api
    except Exception as e:raise e
  File "/usr/local/lib/python3.4/dist-packages/poloniex-0.1-py3.4.egg/poloniex/__init__.py", line 275, in api
    sign = hmac.new(self.Secret, post_data.encode('utf-8'), hashlib.sha512).hexdigest()
  File "/usr/lib/python3.4/hmac.py", line 144, in new
    return HMAC(key, msg, digestmod)
  File "/usr/lib/python3.4/hmac.py", line 42, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
s4w3d0ff commented 8 years ago

I just did another test and had no issues, please make sure you are using the newest code.

To update:

Remove old install: sudo pip3 uninstall poloniex

Clone repo: git clone https://github.com/s4w3d0ff/python-poloniex.git && cd python-poloniex or pull updates into already cloned repo cd python-poloniex && git pull

Install the module: sudo python3 setup.py install

Kailisic commented 8 years ago

I followed your instructions, but it did not help sign = hmac.new(self.Secret, post_data.encode('utf-8'), hashlib.sha512).hexdigest() I get a working version of the code below sign = hmac.new(self.Secret.encode('utf-8'), post_data.encode('utf-8'), hashlib.sha512).hexdigest() I have read about and did hmac.new self.Secret.encode('utf-8') self.APIKey, self.Secret, self.timeout, self._coaching = [APIKey, Secret.encode('utf8'), timeout, coach] Do not understand why .encode( 'utf-8') does not work in the above code

s4w3d0ff commented 8 years ago

I see I have a typo in the code, Line 5d920a6 .encode('utf8') should be .encode('utf-8') ... (face:palm_tree:)

Not sure why it works for my system (and possibly others) but not yours.

Your version should be fine and is what I will change the code to.

josephbestjames commented 7 years ago

Viewing in 2017, the fix mentioned above still works. Thanks @s4w3d0ff ^_^