Code to pep8 standards, shared folders working
This commit is contained in:
parent
10b4a883a8
commit
8b1052a214
1 changed files with 62 additions and 62 deletions
124
mega/mega.py
124
mega/mega.py
|
@ -7,7 +7,7 @@ import os
|
||||||
import random
|
import random
|
||||||
import binascii
|
import binascii
|
||||||
import requests
|
import requests
|
||||||
from .errors import ValidationError,RequestError
|
from .errors import ValidationError, RequestError
|
||||||
from .crypto import *
|
from .crypto import *
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,14 +15,14 @@ class Mega(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.schema = 'https'
|
self.schema = 'https'
|
||||||
self.domain = 'mega.co.nz'
|
self.domain = 'mega.co.nz'
|
||||||
self.timeout = 160 #max time (secs) to wait for resp from api requests
|
self.timeout = 160 # max time (secs) to wait for resp from api requests
|
||||||
self.sid = None
|
self.sid = None
|
||||||
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
||||||
self.request_id = make_id(10)
|
self.request_id = make_id(10)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def login(class_, email, password):
|
def login(cls, email, password):
|
||||||
instance = class_()
|
instance = cls()
|
||||||
instance.login_user(email, password)
|
instance.login_user(email, password)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class Mega(object):
|
||||||
self.rsa_private_key = [0, 0, 0, 0]
|
self.rsa_private_key = [0, 0, 0, 0]
|
||||||
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
l = ((ord(private_key[0])*256+ord(private_key[1]) +7) / 8) + 2
|
l = ((ord(private_key[0]) * 256 + ord(private_key[1]) + 7) / 8) + 2
|
||||||
self.rsa_private_key[i] = mpi_to_int(private_key[:l])
|
self.rsa_private_key[i] = mpi_to_int(private_key[:l])
|
||||||
private_key = private_key[l:]
|
private_key = private_key[l:]
|
||||||
|
|
||||||
|
@ -80,9 +80,9 @@ class Mega(object):
|
||||||
|
|
||||||
req = requests.post(
|
req = requests.post(
|
||||||
'{0}://g.api.{1}/cs'.format(self.schema, self.domain),
|
'{0}://g.api.{1}/cs'.format(self.schema, self.domain),
|
||||||
params=params,
|
params=params,
|
||||||
data=json.dumps(data),
|
data=json.dumps(data),
|
||||||
timeout=self.timeout)
|
timeout=self.timeout)
|
||||||
json_resp = json.loads(req.text)
|
json_resp = json.loads(req.text)
|
||||||
|
|
||||||
#if numeric error code response
|
#if numeric error code response
|
||||||
|
@ -104,28 +104,28 @@ class Mega(object):
|
||||||
Process a file
|
Process a file
|
||||||
"""
|
"""
|
||||||
if file['t'] == 0 or file['t'] == 1:
|
if file['t'] == 0 or file['t'] == 1:
|
||||||
keys = dict(keypart.split(':',1) for keypart in file['k'].split('/'))
|
keys = dict(keypart.split(':', 1) for keypart in file['k'].split('/'))
|
||||||
uid = file['u']
|
uid = file['u']
|
||||||
key = None
|
key = None
|
||||||
# my objects
|
# my objects
|
||||||
if uid in keys :
|
if uid in keys:
|
||||||
key = decrypt_key(base64_to_a32( keys[uid] ), self.master_key)
|
key = decrypt_key(base64_to_a32(keys[uid]), self.master_key)
|
||||||
# shared folders
|
# shared folders
|
||||||
elif 'su' in file and 'sk' in file and ':' in file['k']:
|
elif 'su' in file and 'sk' in file and ':' in file['k']:
|
||||||
shared_key = decrypt_key(base64_to_a32(file['sk']),self.master_key)
|
shared_key = decrypt_key(base64_to_a32(file['sk']), self.master_key)
|
||||||
key = decrypt_key(base64_to_a32(keys[file['h']]),shared_key)
|
key = decrypt_key(base64_to_a32(keys[file['h']]), shared_key)
|
||||||
if file['su'] not in shared_keys :
|
if file['su'] not in shared_keys:
|
||||||
shared_keys[file['su']] = {}
|
shared_keys[file['su']] = {}
|
||||||
shared_keys[file['su']][file['h']] = shared_key
|
shared_keys[file['su']][file['h']] = shared_key
|
||||||
# shared files
|
# shared files
|
||||||
elif file['u'] and file['u'] in shared_keys :
|
elif file['u'] and file['u'] in shared_keys:
|
||||||
for hkey in shared_keys[file['u']] :
|
for hkey in shared_keys[file['u']]:
|
||||||
shared_key = shared_keys[file['u']][hkey]
|
shared_key = shared_keys[file['u']][hkey]
|
||||||
if hkey in keys :
|
if hkey in keys:
|
||||||
key = keys[hkey]
|
key = keys[hkey]
|
||||||
key = decrypt_key(base64_to_a32(key),shared_key)
|
key = decrypt_key(base64_to_a32(key), shared_key)
|
||||||
break
|
break
|
||||||
if key is not None :
|
if key is not None:
|
||||||
# file
|
# file
|
||||||
if file['t'] == 0:
|
if file['t'] == 0:
|
||||||
k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6],
|
k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6],
|
||||||
|
@ -152,55 +152,55 @@ class Mega(object):
|
||||||
file['a'] = {'n': 'Rubbish Bin'}
|
file['a'] = {'n': 'Rubbish Bin'}
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def init_shared_keys(self,files,shared_keys) :
|
def init_shared_keys(self, files, shared_keys):
|
||||||
'''
|
"""
|
||||||
Init shared key not associated with a user.
|
Init shared key not associated with a user.
|
||||||
It seems to happen when a folder is shared,
|
Seems to happen when a folder is shared,
|
||||||
some files are exachanged and then the
|
some files are exchanged and then the
|
||||||
folder is not shared anymore.
|
folder is un-shared.
|
||||||
Keys are stored in files['s'] and files['ok']
|
Keys are stored in files['s'] and files['ok']
|
||||||
'''
|
"""
|
||||||
ok_dict = {}
|
ok_dict = {}
|
||||||
for ok_item in files['ok'] :
|
for ok_item in files['ok']:
|
||||||
shared_key = decrypt_key(base64_to_a32(ok_item['k']),self.master_key)
|
shared_key = decrypt_key(base64_to_a32(ok_item['k']), self.master_key)
|
||||||
ok_dict[ok_item['h']] = shared_key
|
ok_dict[ok_item['h']] = shared_key
|
||||||
for s_item in files['s'] :
|
for s_item in files['s']:
|
||||||
if s_item['u'] not in shared_keys :
|
if s_item['u'] not in shared_keys:
|
||||||
shared_keys[s_item['u']] = {}
|
shared_keys[s_item['u']] = {}
|
||||||
if s_item['h'] in ok_dict :
|
if s_item['h'] in ok_dict:
|
||||||
shared_keys[s_item['u']][s_item['h']] = ok_dict[s_item['h']]
|
shared_keys[s_item['u']][s_item['h']] = ok_dict[s_item['h']]
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# GET
|
# GET
|
||||||
def find(self, filename):
|
def find(self, filename):
|
||||||
'''
|
"""
|
||||||
Return file object from given filename
|
Return file object from given filename
|
||||||
'''
|
"""
|
||||||
files = self.get_files()
|
files = self.get_files()
|
||||||
for file in files.items():
|
for file in files.items():
|
||||||
if file[1]['a'] and file[1]['a']['n'] == filename:
|
if file[1]['a'] and file[1]['a']['n'] == filename:
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def get_files(self):
|
def get_files(self):
|
||||||
'''
|
"""
|
||||||
Get all files in account
|
Get all files in account
|
||||||
'''
|
"""
|
||||||
files = self.api_request({'a': 'f', 'c': 1})
|
files = self.api_request({'a': 'f', 'c': 1})
|
||||||
files_dict = {}
|
files_dict = {}
|
||||||
shared_keys = {}
|
shared_keys = {}
|
||||||
self.init_shared_keys(files,shared_keys)
|
self.init_shared_keys(files, shared_keys)
|
||||||
for file in files['f']:
|
for file in files['f']:
|
||||||
processed_file = self.process_file(file,shared_keys)
|
processed_file = self.process_file(file, shared_keys)
|
||||||
#ensure each file has a name before returning
|
#ensure each file has a name before returning
|
||||||
if processed_file['a']:
|
if processed_file['a']:
|
||||||
files_dict[file['h']] = processed_file
|
files_dict[file['h']] = processed_file
|
||||||
return files_dict
|
return files_dict
|
||||||
|
|
||||||
def get_upload_link(self, file):
|
def get_upload_link(self, file):
|
||||||
'''
|
"""
|
||||||
Get a files public link inc. decrypted key
|
Get a files public link inc. decrypted key
|
||||||
Requires upload() response as input
|
Requires upload() response as input
|
||||||
'''
|
"""
|
||||||
if 'f' in file:
|
if 'f' in file:
|
||||||
file = file['f'][0]
|
file = file['f'][0]
|
||||||
public_handle = self.api_request({'a': 'l', 'n': file['h']})
|
public_handle = self.api_request({'a': 'l', 'n': file['h']})
|
||||||
|
@ -216,9 +216,9 @@ class Mega(object):
|
||||||
use get_link() for regular file input''')
|
use get_link() for regular file input''')
|
||||||
|
|
||||||
def get_link(self, file):
|
def get_link(self, file):
|
||||||
'''
|
"""
|
||||||
Get a file public link from given file object
|
Get a file public link from given file object
|
||||||
'''
|
"""
|
||||||
file = file[1]
|
file = file[1]
|
||||||
if 'h' in file and 'k' in file:
|
if 'h' in file and 'k' in file:
|
||||||
public_handle = self.api_request({'a': 'l', 'n': file['h']})
|
public_handle = self.api_request({'a': 'l', 'n': file['h']})
|
||||||
|
@ -237,30 +237,30 @@ class Mega(object):
|
||||||
return user_data
|
return user_data
|
||||||
|
|
||||||
def get_node_by_type(self, type):
|
def get_node_by_type(self, type):
|
||||||
'''
|
"""
|
||||||
Get a node by it's numeric type id, e.g:
|
Get a node by it's numeric type id, e.g:
|
||||||
0: file
|
0: file
|
||||||
1: dir
|
1: dir
|
||||||
2: special: root cloud drive
|
2: special: root cloud drive
|
||||||
3: special: inbox
|
3: special: inbox
|
||||||
4: special trash bin
|
4: special trash bin
|
||||||
'''
|
"""
|
||||||
nodes = self.get_files()
|
nodes = self.get_files()
|
||||||
for node in nodes.items():
|
for node in nodes.items():
|
||||||
if (node[1]['t'] == type):
|
if (node[1]['t'] == type):
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def get_files_in_node(self, target):
|
def get_files_in_node(self, target):
|
||||||
'''
|
"""
|
||||||
Get all files in a given target, e.g. 4=trash
|
Get all files in a given target, e.g. 4=trash
|
||||||
'''
|
"""
|
||||||
node_id = self.get_node_by_type(target)
|
node_id = self.get_node_by_type(target)
|
||||||
files = self.api_request({'a': 'f', 'c': 1})
|
files = self.api_request({'a': 'f', 'c': 1})
|
||||||
files_dict = {}
|
files_dict = {}
|
||||||
shared_keys = {}
|
shared_keys = {}
|
||||||
self.init_shared_keys(files,shared_keys)
|
self.init_shared_keys(files, shared_keys)
|
||||||
for file in files['f']:
|
for file in files['f']:
|
||||||
processed_file = self.process_file(file,shared_keys)
|
processed_file = self.process_file(file, shared_keys)
|
||||||
if processed_file['a'] and processed_file['p'] == node_id[0]:
|
if processed_file['a'] and processed_file['p'] == node_id[0]:
|
||||||
files_dict[file['h']] = processed_file
|
files_dict[file['h']] = processed_file
|
||||||
return files_dict
|
return files_dict
|
||||||
|
@ -278,18 +278,18 @@ class Mega(object):
|
||||||
return node_id
|
return node_id
|
||||||
|
|
||||||
def get_quota(self):
|
def get_quota(self):
|
||||||
'''
|
"""
|
||||||
Get current remaining disk quota in MegaBytes
|
Get current remaining disk quota in MegaBytes
|
||||||
'''
|
"""
|
||||||
json_resp = self.api_request({'a': 'uq', 'xfer': 1})
|
json_resp = self.api_request({'a': 'uq', 'xfer': 1})
|
||||||
#convert bytes to megabyes
|
#convert bytes to megabyes
|
||||||
return json_resp['mstrg']/1048576
|
return json_resp['mstrg'] / 1048576
|
||||||
|
|
||||||
def get_balance(self):
|
def get_balance(self):
|
||||||
'''
|
"""
|
||||||
Get account monetary balance, Pro accounts only
|
Get account monetary balance, Pro accounts only
|
||||||
'''
|
"""
|
||||||
user_data = self.api_request({"a":"uq","pro":1})
|
user_data = self.api_request({"a": "uq", "pro": 1})
|
||||||
if 'balance' in user_data:
|
if 'balance' in user_data:
|
||||||
return user_data['balance']
|
return user_data['balance']
|
||||||
|
|
||||||
|
@ -311,6 +311,7 @@ class Mega(object):
|
||||||
return self.api_request({'a': 'd',
|
return self.api_request({'a': 'd',
|
||||||
'n': file_id,
|
'n': file_id,
|
||||||
'i': self.request_id})
|
'i': self.request_id})
|
||||||
|
|
||||||
def destroy_url(self, url):
|
def destroy_url(self, url):
|
||||||
#delete a file via it's url
|
#delete a file via it's url
|
||||||
path = self.parse_url(url).split('!')
|
path = self.parse_url(url).split('!')
|
||||||
|
@ -319,7 +320,7 @@ class Mega(object):
|
||||||
return self.destroy(file_id)
|
return self.destroy(file_id)
|
||||||
|
|
||||||
def move(self, file_id, target):
|
def move(self, file_id, target):
|
||||||
'''
|
"""
|
||||||
Move a file to another parent node
|
Move a file to another parent node
|
||||||
params:
|
params:
|
||||||
a : command
|
a : command
|
||||||
|
@ -331,7 +332,7 @@ class Mega(object):
|
||||||
2 : root
|
2 : root
|
||||||
3 : inbox
|
3 : inbox
|
||||||
4 : trash
|
4 : trash
|
||||||
'''
|
"""
|
||||||
|
|
||||||
#determine target_node_id
|
#determine target_node_id
|
||||||
target_node_id = str(self.get_node_by_type(target)[0])
|
target_node_id = str(self.get_node_by_type(target)[0])
|
||||||
|
@ -340,7 +341,6 @@ class Mega(object):
|
||||||
't': target_node_id,
|
't': target_node_id,
|
||||||
'i': self.request_id})
|
'i': self.request_id})
|
||||||
|
|
||||||
|
|
||||||
def empty_trash(self):
|
def empty_trash(self):
|
||||||
# get list of files in rubbish out
|
# get list of files in rubbish out
|
||||||
files = self.get_files_in_node(4)
|
files = self.get_files_in_node(4)
|
||||||
|
@ -357,16 +357,16 @@ class Mega(object):
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# DOWNLOAD
|
# DOWNLOAD
|
||||||
def download(self, file, dest_path=None):
|
def download(self, file, dest_path=None):
|
||||||
'''
|
"""
|
||||||
Download a file by it's file object
|
Download a file by it's file object
|
||||||
'''
|
"""
|
||||||
url = self.get_link(file)
|
url = self.get_link(file)
|
||||||
self.download_url(url, dest_path)
|
self.download_url(url, dest_path)
|
||||||
|
|
||||||
def download_url(self, url, dest_path=None):
|
def download_url(self, url, dest_path=None):
|
||||||
'''
|
"""
|
||||||
Download a file by it's public url
|
Download a file by it's public url
|
||||||
'''
|
"""
|
||||||
path = self.parse_url(url).split('!')
|
path = self.parse_url(url).split('!')
|
||||||
file_id = path[0]
|
file_id = path[0]
|
||||||
file_key = path[1]
|
file_key = path[1]
|
||||||
|
@ -452,8 +452,8 @@ class Mega(object):
|
||||||
ul_url = self.api_request({'a': 'u', 's': size})['p']
|
ul_url = self.api_request({'a': 'u', 's': size})['p']
|
||||||
|
|
||||||
#generate random aes key (128) for file
|
#generate random aes key (128) for file
|
||||||
ul_key = [random.randint(0, 0xFFFFFFFF) for r in range(6)]
|
ul_key = [random.randint(0, 0xFFFFFFFF) for _ in range(6)]
|
||||||
count = Counter.new(128,initial_value=((ul_key[4]<<32)+ul_key[5])<<64)
|
count = Counter.new(128, initial_value=((ul_key[4] << 32) + ul_key[5]) << 64)
|
||||||
aes = AES.new(a32_to_str(ul_key[:4]), AES.MODE_CTR, counter=count)
|
aes = AES.new(a32_to_str(ul_key[:4]), AES.MODE_CTR, counter=count)
|
||||||
|
|
||||||
file_mac = [0, 0, 0, 0]
|
file_mac = [0, 0, 0, 0]
|
||||||
|
@ -512,7 +512,7 @@ class Mega(object):
|
||||||
dest = self.root_id
|
dest = self.root_id
|
||||||
|
|
||||||
#generate random aes key (128) for folder
|
#generate random aes key (128) for folder
|
||||||
ul_key = [random.randint(0, 0xFFFFFFFF) for r in range(6)]
|
ul_key = [random.randint(0, 0xFFFFFFFF) for _ in range(6)]
|
||||||
|
|
||||||
#encrypt attribs
|
#encrypt attribs
|
||||||
attribs = {'n': name}
|
attribs = {'n': name}
|
||||||
|
|
Loading…
Reference in a new issue