diff options
Diffstat (limited to 'module/plugins/crypter')
-rw-r--r-- | module/plugins/crypter/MegaCoNzFolder.py | 131 |
1 files changed, 13 insertions, 118 deletions
diff --git a/module/plugins/crypter/MegaCoNzFolder.py b/module/plugins/crypter/MegaCoNzFolder.py index de95c6b73..3d47ede05 100644 --- a/module/plugins/crypter/MegaCoNzFolder.py +++ b/module/plugins/crypter/MegaCoNzFolder.py @@ -1,49 +1,14 @@ # -*- coding: utf-8 -*- -import base64 -import random -import re -import struct - -import Crypto.Cipher.AES - from module.plugins.internal.Crypter import Crypter -from module.plugins.internal.misc import decode, json - - -############################ General errors ################################### -# EINTERNAL (-1): An internal error has occurred. Please submit a bug report, detailing the exact circumstances in which this error occurred -# EARGS (-2): You have passed invalid arguments to this command -# EAGAIN (-3): (always at the request level) A temporary congestion or server malfunction prevented your request from being processed. No data was altered. Retry. Retries must be spaced with exponential backoff -# ERATELIMIT (-4): You have exceeded your command weight per time quota. Please wait a few seconds, then try again (this should never happen in sane real-life applications) -# -############################ Upload errors #################################### -# EFAILED (-5): The upload failed. Please restart it from scratch -# ETOOMANY (-6): Too many concurrent IP addresses are accessing this upload target URL -# ERANGE (-7): The upload file packet is out of range or not starting and ending on a chunk boundary -# EEXPIRED (-8): The upload target URL you are trying to access has expired. Please request a fresh one -# -############################ Stream/System errors ############################# -# ENOENT (-9): Object (typically, node or user) not found -# ECIRCULAR (-10): Circular linkage attempted -# EACCESS (-11): Access violation (e.g., trying to write to a read-only share) -# EEXIST (-12): Trying to create an object that already exists -# EINCOMPLETE (-13): Trying to access an incomplete resource -# EKEY (-14): A decryption operation failed (never returned by the API) -# ESID (-15): Invalid or expired user session, please relogin -# EBLOCKED (-16): User blocked -# EOVERQUOTA (-17): Request over quota -# ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later -# ETOOMANYCONNECTIONS (-19): Too many connections on this resource -# EWRITE (-20): Write failed -# EREAD (-21): Read failed -# EAPPKEY (-22): Invalid application key; request not processed +from module.plugins.internal.misc import json +from module.plugins.hoster.MegaCoNz import MegaClient, MegaCrypto class MegaCoNzFolder(Crypter): __name__ = "MegaCoNzFolder" __type__ = "crypter" - __version__ = "0.15" + __version__ = "0.16" __status__ = "testing" __pattern__ = r'(https?://(?:www\.)?mega(\.co)?\.nz/|mega:|chrome:.+?)#F!(?P<ID>[\w^_]+)!(?P<KEY>[\w,\-=]+)' @@ -57,99 +22,29 @@ class MegaCoNzFolder(Crypter): ("GammaC0de", "nitzo2001[AT]yahoo[DOT]com")] - API_URL = "https://eu.api.mega.co.nz/cs" - - - def base64_decode(self, data): - data += '=' * (-len(data) % 4) - return base64.b64decode(str(data), "-_") - - - def base64_encode(self, data): - return base64.b64encode(data, "-_") - - - def a32_to_str(self, a): - return struct.pack(">%dI" % len(a), *a) #: big-endian, unsigned int - - - def str_to_a32(self, s): - s += '\0' * (-len(s) % 4) # Add padding, we need a string with a length multiple of 4 - return struct.unpack(">%dI" % (len(s) / 4), s) #: big-endian, unsigned int - - - def base64_to_a32(self, s): - return self.str_to_a32(self.base64_decode(s)) - - - def cbc_decrypt(self, data, key): - cbc = Crypto.Cipher.AES.new(self.a32_to_str(key), Crypto.Cipher.AES.MODE_CBC, "\0" * 16) - return cbc.decrypt(data) - - - def decrypt_key(self, a, key): - a = self.base64_decode(a) - k = sum((self.str_to_a32(self.cbc_decrypt(a[_i:_i + 16], key)) - for _i in xrange(0, len(a), 16)), ()) - - self.log_debug("Decrypted Key: %s" % decode(k)) - - return k - - - def api_response(self, **kwargs): - """ - Dispatch a call to the api, see https://mega.co.nz/#developers - """ - uid = random.randint(10 << 9, 10 ** 10) #: Generate a session id, no idea where to obtain elsewhere - - res = self.load(self.API_URL, - get={'id': uid, - 'n' : self.info['pattern']['ID']}, - post=json.dumps([kwargs])) - - self.log_debug("Api Response: " + res) - - return json.loads(res) - - - def check_error(self, code): - ecode = abs(code) - - if ecode in (9, 16, 21): - self.offline() - - elif ecode in (3, 13, 17, 18, 19): - self.temp_offline() - - elif ecode in (1, 4, 6, 10, 15, 21): - self.retry(5, 30, _("Error code: [%s]") % -ecode) - - else: - self.fail(_("Error code: [%s]") % -ecode) - - def decrypt(self, pyfile): id = self.info['pattern']['ID'] master_key = self.info['pattern']['KEY'] self.log_debug("ID: %s" % id, "Key: %s" % master_key, "Type: public folder") - master_key = self.base64_to_a32(master_key) + master_key = MegaCrypto.base64_to_a32(master_key) + + mega = MegaClient(self, id) #: F is for requesting folder listing (kind like a `ls` command) - mega = self.api_response(a="f", c=1, r=1, ca=1, ssl=1)[0] + res = mega.api_response(a="f", c=1, r=1, ca=1, ssl=1)[0] - if isinstance(mega, int): - self.check_error(mega) - elif "e" in mega: - self.check_error(mega['e']) + if isinstance(res, int): + mega.check_error(res) + elif "e" in res: + mega.check_error(res['e']) - get_node_key = lambda k: self.base64_encode(self.a32_to_str(self.decrypt_key(k, master_key))) + get_node_key = lambda k: MegaCrypto.base64_encode(MegaCrypto.a32_to_str(MegaCrypto.decrypt_key(k, master_key))) self.links = [_("https://mega.co.nz/#N!%s!%s###n=%s") % (_f['h'], get_node_key(_f['k'][_f['k'].index(':') + 1:]), id) - for _f in mega['f'] + for _f in res['f'] if _f['t'] == 0 and ':' in _f['k']] |