# -*- coding: utf-8 -*- import binascii import re import Crypto.Cipher from module.plugins.internal.Crypter import Crypter from module.plugins.captcha.ReCaptcha import ReCaptcha class NCryptIn(Crypter): __name__ = "NCryptIn" __type__ = "crypter" __version__ = "1.40" __status__ = "testing" __pattern__ = r'http://(?:www\.)?ncrypt\.in/(?P<TYPE>folder|link|frame)-([^/\?]+)' __config__ = [("activated" , "bool" , "Activated" , True ), ("use_premium" , "bool" , "Use premium account if available", True ), ("folder_per_package", "Default;Yes;No", "Create folder for each package" , "Default")] __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.cleaned_html = None self.links_source_order = ["cnl2", "rsdf", "ccf", "dlc", "web"] self.protection_type = None def decrypt(self, pyfile): #: Init self.package = pyfile.package() pack_links = [] pack_name = self.package.name folder_name = self.package.folder #: Deal with single links if self.is_single_link(): pack_links.extend(self.handle_single_link()) #: Deal with folders else: #: Request folder home self.data = self.request_folder_home() self.cleaned_html = self.remove_html_crap(self.data) if not self.is_online(): self.offline() #: Check for folder protection if self.is_protected(): self.data = self.unlock_protection() self.cleaned_html = self.remove_html_crap(self.data) self.handle_errors() #: Prepare package name and folder (pack_name, folder_name) = self.get_package_info() #: Extract package links for link_source_type in self.links_source_order: pack_links.extend(self.handle_link_source(link_source_type)) if pack_links: #: Use only first source which provides links break pack_links = set(pack_links) #: Pack and return links if pack_links: self.packages = [(pack_name, pack_links, folder_name)] def is_single_link(self): link_type = re.match(self.__pattern__, self.pyfile.url).group('TYPE') return link_type in ("link", "frame") def request_folder_home(self): return self.load(self.pyfile.url) def remove_html_crap(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 is_online(self): if "Your folder does not exist" in self.cleaned_html: self.log_debug("File not m") return False return True def is_protected(self): form = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleaned_html, re.S) if form: content = form.group(1) for keyword in ("password", "captcha"): if keyword in content: self.protection_type = keyword self.log_debug("Links are %s protected" % self.protection_type) return True return False def get_package_info(self): m = re.search(self.NAME_PATTERN, self.data) if m is not None: name = folder = m.group('N').strip() self.log_debug("Found name [%s] and folder [%s] in package info" % (name, folder)) else: name = self.package.name folder = self.package.folder self.log_debug("Package info not m, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) return name, folder def unlock_protection(self): postData = {} form = re.search(r'<form name="protected"(.*?)</form>', self.cleaned_html, re.S).group(1) #: Submit package password if "password" in form: password = self.get_password() self.log_debug("Submitting password [%s] for protected links" % password) postData['password'] = password #: Resolve anicaptcha if "anicaptcha" in form: self.log_debug("Captcha protected") captchaUri = re.search(r'src="(/temp/anicaptcha/.+?)"', form).group(1) captcha = self.captcha.decrypt("http://ncrypt.in" + captchaUri) self.log_debug("Captcha resolved [%s]" % captcha) postData['captcha'] = captcha #: Resolve recaptcha if "recaptcha" in form: self.log_debug("ReCaptcha protected") captcha_key = re.search(r'\?k=(.*?)"', form).group(1) self.log_debug("Resolving ReCaptcha with key [%s]" % captcha_key) self.captcha = ReCaptcha(self.pyfile) response, challenge = self.captcha.challenge(captcha_key) postData['recaptcha_challenge_field'] = challenge postData['recaptcha_response_field'] = response #: Resolve circlecaptcha if "circlecaptcha" in form: self.log_debug("CircleCaptcha protected") captcha_img_url = "http://ncrypt.in/classes/captcha/circlecaptcha.php" coords = self.captcha.decrypt(captcha_img_url, input_type="png", output_type='positional', ocr="CircleCaptcha") self.log_debug("Captcha resolved, coords %s" % 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) def handle_errors(self): if self.protection_type == "password": if "This password is invalid!" in self.cleaned_html: self.fail(_("Wrong password")) if self.protection_type == "captcha": if "The securitycheck was wrong" in self.cleaned_html: self.retry_captcha() else: self.captcha.correct() def handle_link_source(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.log_debug("No JS engine available, skip %s links" % link_source_type) return [] #: Select suitable handler if link_source_type == "single": return self.handle_single_link() if link_source_type == "cnl2": return self.handle_CNL2() elif link_source_type in ("rsdf", "ccf", "dlc"): return self.handle_container(link_source_type) elif link_source_type == "web": return self.handle_web_links() else: self.error(_('Unknown source type "%s"') % link_source_type) def handle_single_link(self): self.log_debug("Handling Single link") pack_links = [] #: Decrypt single link decrypted_link = self.decrypt_link(self.pyfile.url) if decrypted_link: pack_links.append(decrypted_link) return pack_links def handle_CNL2(self): self.log_debug("Handling CNL2 links") pack_links = [] if 'cnl2_output' in self.cleaned_html: try: (vcrypted, vjk) = self._get_cipher_params() for (crypted, jk) in zip(vcrypted, vjk): pack_links.extend(self._get_links(crypted, jk)) except Exception: self.fail(_("Unable to decrypt CNL2 links")) return pack_links def handle_containers(self): self.log_debug("Handling Container links") pack_links = [] pattern = r'/container/(rsdf|dlc|ccf)/(\w+)' containersLinks = re.findall(pattern, self.data) self.log_debug("Decrypting %d Container links" % len(containersLinks)) for containerLink in containersLinks: link = "http://ncrypt.in/container/%s/%s.%s" % (containerLink[0], containerLink[1], containerLink[0]) pack_links.append(link) return pack_links def handle_web_links(self): self.log_debug("Handling Web links") pattern = r'(http://ncrypt\.in/link-.*?=)' links = re.findall(pattern, self.data) pack_links = [] self.log_debug("Decrypting %d Web links" % len(links)) for i, link in enumerate(links): self.log_debug("Decrypting Web link %d, %s" % (i + 1, link)) decrypted_link = self.decrypt(link) if decrypted_link: pack_links.append(decrypted_link) return pack_links def decrypt_link(self, link): try: url = link.replace("link-", "frame-") link = self.load(url, just_header=True)['location'] return link except Exception, detail: self.log_debug("Error decrypting link %s, %s" % (link, detail)) def _get_cipher_params(self): pattern = r'<input.*?name="%s".*?value="(.*?)"' #: Get jk jk_re = pattern % NCryptIn.JK_KEY vjk = re.findall(jk_re, self.data) #: Get crypted crypted_re = pattern % NCryptIn.CRYPTED_KEY vcrypted = re.findall(crypted_re, self.data) #: Log and return self.log_debug("Detected %d crypted blocks" % len(vcrypted)) return vcrypted, vjk def _get_links(self, crypted, jk): #: Get key jreturn = self.js.eval("%s f()" % jk) self.log_debug("JsEngine returns value [%s]" % jreturn) key = binascii.unhexlify(jreturn) #: Decrypt Key = key IV = key obj = Crypto.Cipher.AES.new(Key, Crypto.Cipher.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.log_debug("Block has %d links" % len(links)) return links