diff options
Diffstat (limited to 'pyload/plugin/crypter/NCryptIn.py')
-rw-r--r-- | pyload/plugin/crypter/NCryptIn.py | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/pyload/plugin/crypter/NCryptIn.py b/pyload/plugin/crypter/NCryptIn.py new file mode 100644 index 000000000..bc9702f21 --- /dev/null +++ b/pyload/plugin/crypter/NCryptIn.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- + +import binascii +import re + +from Crypto.Cipher import AES + +from pyload.plugin.Crypter import Crypter +from pyload.plugin.captcha.ReCaptcha import ReCaptcha + + +class NCryptIn(Crypter): + __name = "NCryptIn" + __type = "crypter" + __version = "1.34" + + __pattern = r'http://(?:www\.)?ncrypt\.in/(?P<TYPE>folder|link|frame)-([^/\?]+)' + __config = [("use_subfolder" , "bool", "Save package to subfolder" , True), + ("subfolder_per_pack", "bool", "Create a subfolder for each package", True)] + + __description = """NCrypt.in decrypter plugin""" + __license = "GPLv3" + __authors = [("fragonib", "fragonib[AT]yahoo[DOT]es"), + ("stickell", "l.stickell@yahoo.it")] + + + JK_KEY = "jk" + CRYPTED_KEY = "crypted" + + NAME_PATTERN = r'<meta name="description" content="(?P<N>.+?)"' + + + def setup(self): + self.package = None + self.cleanedHtml = None + self.links_source_order = ["cnl2", "rsdf", "ccf", "dlc", "web"] + self.protection_type = None + + + def decrypt(self, pyfile): + # Init + self.package = pyfile.package() + package_links = [] + package_name = self.package.name + folder_name = self.package.folder + + # Deal with single links + if self.isSingleLink(): + package_links.extend(self.handleSingleLink()) + + # Deal with folders + else: + + # Request folder home + self.html = self.requestFolderHome() + self.cleanedHtml = self.removeHtmlCrap(self.html) + if not self.isOnline(): + self.offline() + + # Check for folder protection + if self.isProtected(): + self.html = self.unlockProtection() + self.cleanedHtml = self.removeHtmlCrap(self.html) + self.handleErrors() + + # Prepare package name and folder + (package_name, folder_name) = self.getPackageInfo() + + # Extract package links + for link_source_type in self.links_source_order: + package_links.extend(self.handleLinkSource(link_source_type)) + if package_links: #: use only first source which provides links + break + package_links = set(package_links) + + # Pack and return links + if package_links: + self.packages = [(package_name, package_links, folder_name)] + + + def isSingleLink(self): + link_type = re.match(self.__pattern, self.pyfile.url).group('TYPE') + return link_type in ("link", "frame") + + + def requestFolderHome(self): + return self.load(self.pyfile.url, decode=True) + + + def removeHtmlCrap(self, content): + patterns = (r'(type="hidden".*?(name=".*?")?.*?value=".*?")', + r'display:none;">(.*?)</(div|span)>', + r'<div\s+class="jdownloader"(.*?)</div>', + r'<table class="global">(.*?)</table>', + r'<iframe\s+style="display:none(.*?)</iframe>') + for pattern in patterns: + rexpr = re.compile(pattern, re.S) + content = re.sub(rexpr, "", content) + return content + + + def isOnline(self): + if "Your folder does not exist" in self.cleanedHtml: + self.logDebug("File not m") + return False + return True + + + def isProtected(self): + form = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleanedHtml, re.S) + if form: + content = form.group(1) + for keyword in ("password", "captcha"): + if keyword in content: + self.protection_type = keyword + self.logDebug("Links are %s protected" % self.protection_type) + return True + return False + + + def getPackageInfo(self): + m = re.search(self.NAME_PATTERN, self.html) + if m: + name = folder = m.group('N').strip() + self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) + else: + name = self.package.name + folder = self.package.folder + self.logDebug("Package info not m, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) + return name, folder + + + def unlockProtection(self): + postData = {} + + form = re.search(r'<form name="protected"(.*?)</form>', self.cleanedHtml, re.S).group(1) + + # Submit package password + if "password" in form: + password = self.getPassword() + self.logDebug("Submitting password [%s] for protected links" % password) + postData['password'] = password + + # Resolve anicaptcha + if "anicaptcha" in form: + self.logDebug("Captcha protected") + captchaUri = re.search(r'src="(/temp/anicaptcha/.+?)"', form).group(1) + captcha = self.decryptCaptcha("http://ncrypt.in" + captchaUri) + self.logDebug("Captcha resolved [%s]" % captcha) + postData['captcha'] = captcha + + # Resolve recaptcha + if "recaptcha" in form: + self.logDebug("ReCaptcha protected") + captcha_key = re.search(r'\?k=(.*?)"', form).group(1) + self.logDebug("Resolving ReCaptcha with key [%s]" % captcha_key) + recaptcha = ReCaptcha(self) + response, challenge = recaptcha.challenge(captcha_key) + postData['recaptcha_challenge_field'] = challenge + postData['recaptcha_response_field'] = response + + # Resolve circlecaptcha + if "circlecaptcha" in form: + self.logDebug("CircleCaptcha protected") + captcha_img_url = "http://ncrypt.in/classes/captcha/circlecaptcha.php" + coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') + self.logDebug("Captcha resolved, coords [%s]" % str(coords)) + postData['circle.x'] = coords[0] + postData['circle.y'] = coords[1] + + # Unlock protection + postData['submit_protected'] = 'Continue to folder' + return self.load(self.pyfile.url, post=postData, decode=True) + + + def handleErrors(self): + if self.protection_type == "password": + if "This password is invalid!" in self.cleanedHtml: + self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry") + self.fail(_("Incorrect password, please set right password on 'Edit package' form and retry")) + + if self.protection_type == "captcha": + if "The securitycheck was wrong!" in self.cleanedHtml: + self.invalidCaptcha() + self.retry() + else: + self.correctCaptcha() + + + def handleLinkSource(self, link_source_type): + # Check for JS engine + require_js_engine = link_source_type in ("cnl2", "rsdf", "ccf", "dlc") + if require_js_engine and not self.js: + self.logDebug("No JS engine available, skip %s links" % link_source_type) + return [] + + # Select suitable handler + if link_source_type == 'single': + return self.handleSingleLink() + if link_source_type == 'cnl2': + return self.handleCNL2() + elif link_source_type in ("rsdf", "ccf", "dlc"): + return self.handleContainer(link_source_type) + elif link_source_type == "web": + return self.handleWebLinks() + else: + self.error(_('Unknown source type "%s"') % link_source_type) + + + def handleSingleLink(self): + self.logDebug("Handling Single link") + package_links = [] + + # Decrypt single link + decrypted_link = self.decryptLink(self.pyfile.url) + if decrypted_link: + package_links.append(decrypted_link) + + return package_links + + + def handleCNL2(self): + self.logDebug("Handling CNL2 links") + package_links = [] + + if 'cnl2_output' in self.cleanedHtml: + try: + (vcrypted, vjk) = self._getCipherParams() + for (crypted, jk) in zip(vcrypted, vjk): + package_links.extend(self._getLinks(crypted, jk)) + except Exception: + self.fail(_("Unable to decrypt CNL2 links")) + + return package_links + + + def handleContainers(self): + self.logDebug("Handling Container links") + package_links = [] + + pattern = r'/container/(rsdf|dlc|ccf)/(\w+)' + containersLinks = re.findall(pattern, self.html) + self.logDebug("Decrypting %d Container links" % len(containersLinks)) + for containerLink in containersLinks: + link = "http://ncrypt.in/container/%s/%s.%s" % (containerLink[0], containerLink[1], containerLink[0]) + package_links.append(link) + + return package_links + + + def handleWebLinks(self): + self.logDebug("Handling Web links") + pattern = r'(http://ncrypt\.in/link-.*?=)' + links = re.findall(pattern, self.html) + + package_links = [] + self.logDebug("Decrypting %d Web links" % len(links)) + for i, link in enumerate(links): + self.logDebug("Decrypting Web link %d, %s" % (i + 1, link)) + decrypted_link = self.decrypt(link) + if decrypted_link: + package_links.append(decrypted_link) + + return package_links + + + def decryptLink(self, link): + try: + url = link.replace("link-", "frame-") + link = self.load(url, just_header=True)['location'] + return link + except Exception, detail: + self.logDebug("Error decrypting link %s, %s" % (link, detail)) + + + def _getCipherParams(self): + pattern = r'<input.*?name="%s".*?value="(.*?)"' + + # Get jk + jk_re = pattern % NCryptIn.JK_KEY + vjk = re.findall(jk_re, self.html) + + # Get crypted + crypted_re = pattern % NCryptIn.CRYPTED_KEY + vcrypted = re.findall(crypted_re, self.html) + + # Log and return + self.logDebug("Detected %d crypted blocks" % len(vcrypted)) + return vcrypted, vjk + + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted.decode('base64')) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = filter(bool, text.split('\n')) + + # Log and return + self.logDebug("Block has %d links" % len(links)) + return links |