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