diff --git a/examples.py b/examples.py index bfd5342..fefd64b 100644 --- a/examples.py +++ b/examples.py @@ -27,16 +27,16 @@ def test(): files = m.get_files() # get account disk quota in MB - print(m.get_quota()) + print((m.get_quota())) # get account storage space - print(m.get_storage_space()) + print((m.get_storage_space())) # example iterate over files for file in files: - print(files[file]) + print((files[file])) # upload file - print(m.upload('examples.py')) + print((m.upload('examples.py'))) # search for a file in account file = m.find('examples.py') @@ -47,17 +47,17 @@ def test(): print(link) # download file. by file object or url - print m.download(file, '/tmp') + print(m.download(file, '/tmp')) # m.download_url(link) # delete or destroy file. by id or url - print(m.delete(file[0])) + print((m.delete(file[0]))) # print(m.destroy(file[0])) # print(m.delete_url(link)) # print(m.destroy_url(link)) # empty trash - print(m.empty_trash()) + print((m.empty_trash())) if __name__ == '__main__': diff --git a/mega/crypto.py b/mega/crypto.py index 0c10b91..9d87476 100644 --- a/mega/crypto.py +++ b/mega/crypto.py @@ -4,15 +4,33 @@ import base64 import struct import binascii import random +import sys + +### Python3 compatibility +if sys.version_info < (3, ): + + def makebyte(x): + return x + + def makestring(x): + return x +else: + import codecs + + def makebyte(x): + return codecs.latin_1_encode(x)[0] + + def makestring(x): + return codecs.latin_1_decode(x)[0] def aes_cbc_encrypt(data, key): - aes_cipher = AES.new(key, AES.MODE_CBC, '\0' * 16) + aes_cipher = AES.new(key, AES.MODE_CBC, makebyte('\0' * 16)) return aes_cipher.encrypt(data) def aes_cbc_decrypt(data, key): - aes_cipher = AES.new(key, AES.MODE_CBC, '\0' * 16) + aes_cipher = AES.new(key, AES.MODE_CBC, makebyte('\0' * 16)) return aes_cipher.decrypt(data) @@ -59,14 +77,16 @@ def decrypt_key(a, key): def encrypt_attr(attr, key): - attr = 'MEGA' + json.dumps(attr) + attr = makebyte('MEGA' + json.dumps(attr)) if len(attr) % 16: - attr += '\0' * (16 - len(attr) % 16) + attr += b'\0' * (16 - len(attr) % 16) return aes_cbc_encrypt(attr, a32_to_str(key)) def decrypt_attr(attr, key): - attr = aes_cbc_decrypt(attr, a32_to_str(key)).rstrip('\0') + attr = aes_cbc_decrypt(attr, a32_to_str(key)) + attr = makestring(attr) + attr = attr.rstrip('\0') return json.loads(attr[4:]) if attr[:6] == 'MEGA{"' else False @@ -75,9 +95,11 @@ def a32_to_str(a): def str_to_a32(b): + if isinstance(b, str): + b = makebyte(b) if len(b) % 4: # pad to multiple of 4 - b += '\0' * (4 - len(b) % 4) + b += b'\0' * (4 - len(b) % 4) return struct.unpack('>%dI' % (len(b) / 4), b) @@ -98,6 +120,7 @@ def base64_to_a32(s): def base64_url_encode(data): data = base64.b64encode(data) + data = makestring(data) for search, replace in (('+', '-'), ('/', '_'), ('=', '')): data = data.replace(search, replace) return data @@ -118,7 +141,6 @@ def get_chunks(size): yield (p, size - p) -# more general functions def make_id(length): text = '' possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" diff --git a/mega/mega.py b/mega/mega.py index b7f103a..eb38599 100644 --- a/mega/mega.py +++ b/mega/mega.py @@ -59,9 +59,7 @@ class Mega(object): a32_to_base64(encrypt_key(master_key, password_key)), 'ts': base64_url_encode( - a32_to_str(session_self_challenge) + a32_to_str( - encrypt_key(session_self_challenge, master_key) - ) + a32_to_str(session_self_challenge) + a32_to_str(encrypt_key(session_self_challenge, master_key)) ) } ) @@ -101,7 +99,7 @@ class Mega(object): encrypted_sid = mpi_to_int(base64_url_decode(resp['csid'])) rsa_decrypter = RSA.construct( ( - self.rsa_private_key[0] * self.rsa_private_key[1], 0L, + self.rsa_private_key[0] * self.rsa_private_key[1], 0, self.rsa_private_key[2], self.rsa_private_key[0], self.rsa_private_key[1] ) @@ -256,7 +254,7 @@ class Mega(object): found = False for foldername in paths: if foldername != '': - for file in files.iteritems(): + for file in files.items(): if file[1]['a'] and file[1]['t'] and \ file[1]['a']['n'] == foldername: if parent_desc == file[1]['p']: @@ -273,7 +271,7 @@ class Mega(object): Return file object from given filename """ files = self.get_files() - for file in files.items(): + for file in list(files.items()): if not isinstance(file[1]['a'], dict): continue if file[1]['a'] and file[1]['a']['n'] == filename: @@ -348,7 +346,7 @@ class Mega(object): 4: special trash bin """ nodes = self.get_files() - for node in nodes.items(): + for node in list(nodes.items()): if node[1]['t'] == type: return node @@ -385,7 +383,7 @@ class Mega(object): node_id = None for i in node_data['f']: - if i['h'] != u'': + if i['h'] != '': node_id = i['h'] return node_id @@ -608,11 +606,11 @@ class Mega(object): if self.options.get('verbose') is True: # temp file size file_info = os.stat(temp_output_file.name) - print( + print(( '{0} of {1} downloaded'.format( file_info.st_size, file_size ) - ) + )) file_mac = str_to_a32(mac_str) @@ -685,11 +683,11 @@ class Mega(object): if self.options.get('verbose') is True: # upload progress - print( + print(( '{0} of {1} uploaded'.format( upload_progress, file_size ) - ) + )) else: output_file = requests.post( ul_url + "/0", data='', timeout=self.timeout @@ -818,7 +816,7 @@ class Mega(object): # determine target_node_id if type(target) == int: target_node_id = str(self.get_node_by_type(target)[0]) - elif type(target) in (str, unicode): + elif type(target) in (str, str): target_node_id = target else: file = target[1] diff --git a/tox.ini b/tox.ini index 581e6f6..c05eeaa 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,8 @@ envlist = py{27,37}-normal,lint commands = flake8 {toxinidir}/src/ coverage erase - PYTHONPATH=. pytest --cov=. {toxinidir}/tests/tests.py + python setup.py install + pytest {toxinidir}/tests/tests.py deps = -rrequirements-dev.txt