adds logging

This commit is contained in:
Richard O'Dwyer 2019-11-04 23:42:44 +00:00
parent f26421658d
commit e9985e7831

View file

@ -1,6 +1,7 @@
import re import re
import time import time
import json import json
import logging
import secrets import secrets
from pathlib import Path from pathlib import Path
import hashlib import hashlib
@ -8,23 +9,24 @@ from Crypto.Cipher import AES
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.Util import Counter from Crypto.Util import Counter
import os import os
import sys
import random import random
import binascii import binascii
import requests import tempfile
import shutil import shutil
import requests
from .errors import ValidationError, RequestError from .errors import ValidationError, RequestError
from .crypto import ( from .crypto import (
a32_to_base64, encrypt_key, base64_url_encode, encrypt_attr, base64_to_a32, a32_to_base64, encrypt_key, base64_url_encode, encrypt_attr, base64_to_a32,
base64_url_decode, decrypt_attr, a32_to_str, get_chunks, str_to_a32, base64_url_decode, decrypt_attr, a32_to_str, get_chunks, str_to_a32,
decrypt_key, mpi_to_int, stringhash, prepare_key, make_id, makebyte decrypt_key, mpi_to_int, stringhash, prepare_key, make_id, makebyte
) )
import tempfile
PYTHON2 = sys.version_info < (3, ) logger = logging.getLogger(__name__)
class Mega(object): class Mega:
def __init__(self, options=None): def __init__(self, options=None):
self.schema = 'https' self.schema = 'https'
self.domain = 'mega.co.nz' self.domain = 'mega.co.nz'
@ -44,9 +46,11 @@ class Mega(object):
else: else:
self.login_anonymous() self.login_anonymous()
self._trash_folder_node_id = self.get_node_by_type(4)[0] self._trash_folder_node_id = self.get_node_by_type(4)[0]
logger.info('Login complete')
return self return self
def _login_user(self, email, password): def _login_user(self, email, password):
logger.info('Logging in user...')
email = email.lower() email = email.lower()
get_user_salt_resp = self._api_request({'a': 'us0', 'user': email}) get_user_salt_resp = self._api_request({'a': 'us0', 'user': email})
user_salt = None user_salt = None
@ -73,6 +77,7 @@ class Mega(object):
self._login_process(resp, password_aes) self._login_process(resp, password_aes)
def login_anonymous(self): def login_anonymous(self):
logger.info('Logging in anonymous temporary user...')
master_key = [random.randint(0, 0xFFFFFFFF)] * 4 master_key = [random.randint(0, 0xFFFFFFFF)] * 4
password_key = [random.randint(0, 0xFFFFFFFF)] * 4 password_key = [random.randint(0, 0xFFFFFFFF)] * 4
session_self_challenge = [random.randint(0, 0xFFFFFFFF)] * 4 session_self_challenge = [random.randint(0, 0xFFFFFFFF)] * 4
@ -116,12 +121,6 @@ class Mega(object):
private_key = a32_to_str(rsa_private_key) private_key = a32_to_str(rsa_private_key)
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):
if PYTHON2:
l = (
(ord(private_key[0]) * 256 +
ord(private_key[1]) + 7) / 8
) + 2
else:
l = int( l = int(
((private_key[0]) * 256 + (private_key[1]) + 7) / 8 ((private_key[0]) * 256 + (private_key[1]) + 7) / 8
) + 2 ) + 2
@ -151,7 +150,7 @@ class Mega(object):
if not isinstance(data, list): if not isinstance(data, list):
data = [data] data = [data]
url = '{0}://g.api.{1}/cs'.format(self.schema, self.domain) url = f'{self.schema}://g.api.{self.domain}/cs'
req = requests.post( req = requests.post(
url, url,
params=params, params=params,
@ -161,7 +160,8 @@ class Mega(object):
json_resp = json.loads(req.text) json_resp = json.loads(req.text)
if isinstance(json_resp, int): if isinstance(json_resp, int):
if json_resp == -3: if json_resp == -3:
time.sleep(0.2) logger.info('Request failed, retrying...')
time.sleep(10)
return self._api_request(data=data) return self._api_request(data=data)
raise RequestError(json_resp) raise RequestError(json_resp)
return json_resp[0] return json_resp[0]
@ -332,9 +332,7 @@ class Mega(object):
return file return file
def get_files(self): def get_files(self):
""" logger.info('Getting all files...')
Get all files in account
"""
files = self._api_request({'a': 'f', 'c': 1, 'r': 1}) files = self._api_request({'a': 'f', 'c': 1, 'r': 1})
files_dict = {} files_dict = {}
shared_keys = {} shared_keys = {}
@ -358,8 +356,9 @@ class Mega(object):
decrypted_key = a32_to_base64( decrypted_key = a32_to_base64(
decrypt_key(base64_to_a32(file_key), self.master_key) decrypt_key(base64_to_a32(file_key), self.master_key)
) )
return '{0}://{1}/#!{2}!{3}'.format( return (
self.schema, self.domain, public_handle, decrypted_key f'{self.schema}://{self.domain}'
f'/#!{public_handle}!{decrypted_key}'
) )
else: else:
raise ValueError( raise ValueError(
@ -380,8 +379,9 @@ class Mega(object):
"(is this a shared file?)" "(is this a shared file?)"
) )
decrypted_key = a32_to_base64(file['key']) decrypted_key = a32_to_base64(file['key'])
return '{0}://{1}/#!{2}!{3}'.format( return (
self.schema, self.domain, public_handle, decrypted_key f'{self.schema}://{self.domain}'
f'/#!{public_handle}!{decrypted_key}'
) )
else: else:
raise ValidationError('File id and key must be present') raise ValidationError('File id and key must be present')
@ -405,8 +405,9 @@ class Mega(object):
"(is this a shared file?)" "(is this a shared file?)"
) )
decrypted_key = a32_to_base64(file['shared_folder_key']) decrypted_key = a32_to_base64(file['shared_folder_key'])
return '{0}://{1}/#F!{2}!{3}'.format( return (
self.schema, self.domain, public_handle, decrypted_key f'{self.schema}://{self.domain}'
f'/#F!{public_handle}!{decrypted_key}'
) )
else: else:
raise ValidationError('File id and key must be present') raise ValidationError('File id and key must be present')
@ -740,14 +741,8 @@ class Mega(object):
block += '\0' * (16 - (len(block) % 16)) block += '\0' * (16 - (len(block) % 16))
mac_str = mac_encryptor.encrypt(encryptor.encrypt(block)) mac_str = mac_encryptor.encrypt(encryptor.encrypt(block))
if self.options.get('verbose') is True:
# temp file size
file_info = os.stat(temp_output_file.name) file_info = os.stat(temp_output_file.name)
print(( logger.info('%s of %s downloaded', file_info.st_size, file_size)
'{0} of {1} downloaded'.format(
file_info.st_size, file_size
)
))
file_mac = str_to_a32(mac_str) file_mac = str_to_a32(mac_str)
@ -768,7 +763,7 @@ class Mega(object):
dest = self.root_id dest = self.root_id
# request upload url, call 'u' method # request upload url, call 'u' method
input_file = open(filename, 'rb') with open(filename, 'rb') as input_file:
file_size = os.path.getsize(filename) file_size = os.path.getsize(filename)
ul_url = self._api_request({'a': 'u', 's': file_size})['p'] ul_url = self._api_request({'a': 'u', 's': file_size})['p']
@ -815,44 +810,39 @@ class Mega(object):
timeout=self.timeout timeout=self.timeout
) )
completion_file_handle = output_file.text completion_file_handle = output_file.text
logger.info('%s of %s uploaded', upload_progress, file_size)
if self.options.get('verbose') is True:
# upload progress
print((
'{0} of {1} uploaded'.format(
upload_progress, file_size
)
))
else: else:
output_file = requests.post( output_file = requests.post(
ul_url + "/0", data='', timeout=self.timeout ul_url + "/0", data='', timeout=self.timeout
) )
completion_file_handle = output_file.text completion_file_handle = output_file.text
logger.info('Chunks uploaded')
logger.info('Setting attributes to complete upload')
logger.info('Computing attributes')
file_mac = str_to_a32(mac_str) file_mac = str_to_a32(mac_str)
# determine meta mac # determine meta mac
meta_mac = (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]) meta_mac = (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3])
if dest_filename is not None: dest_filename = dest_filename or os.path.basename(filename)
attribs = {'n': dest_filename} attribs = {'n': dest_filename}
else:
attribs = {'n': os.path.basename(filename)}
encrypt_attribs = base64_url_encode(encrypt_attr(attribs, ul_key[:4])) encrypt_attribs = base64_url_encode(
encrypt_attr(attribs, ul_key[:4])
)
key = [ key = [
ul_key[0] ^ ul_key[4], ul_key[1] ^ ul_key[5], ul_key[0] ^ ul_key[4], ul_key[1] ^ ul_key[5],
ul_key[2] ^ meta_mac[0], ul_key[3] ^ meta_mac[1], ul_key[4], ul_key[2] ^ meta_mac[0], ul_key[3] ^ meta_mac[1], ul_key[4],
ul_key[5], meta_mac[0], meta_mac[1] ul_key[5], meta_mac[0], meta_mac[1]
] ]
encrypted_key = a32_to_base64(encrypt_key(key, self.master_key)) encrypted_key = a32_to_base64(encrypt_key(key, self.master_key))
logger.info('Sending request to update attributes')
# update attributes # update attributes
data = self._api_request( data = self._api_request(
{ {
'a': 'a': 'p',
'p', 't': dest,
't':
dest,
'n': [ 'n': [
{ {
'h': completion_file_handle, 'h': completion_file_handle,
@ -863,8 +853,7 @@ class Mega(object):
] ]
} }
) )
# close input file and return API msg logger.info('Upload complete')
input_file.close()
return data return data
def _mkdir(self, name, parent_node_id): def _mkdir(self, name, parent_node_id):