diff options
Diffstat (limited to 'module/plugins/crypter')
| -rw-r--r-- | module/plugins/crypter/RelinkUs.py | 270 | 
1 files changed, 189 insertions, 81 deletions
| diff --git a/module/plugins/crypter/RelinkUs.py b/module/plugins/crypter/RelinkUs.py index d00e4cc18..8f29a9158 100644 --- a/module/plugins/crypter/RelinkUs.py +++ b/module/plugins/crypter/RelinkUs.py @@ -5,136 +5,244 @@ from module.plugins.Crypter import Crypter  import base64  import binascii  import re -import urllib +import os +  class RelinkUs(Crypter):      __name__ = "RelinkUs"      __type__ = "crypter"      __pattern__ = r"http://(www\.)?relink.us/(f/|((view|go).php\?id=))(?P<id>.+)" -    __version__ = "2.3" +    __version__ = "3.0"      __description__ = """Relink.us Crypter Plugin"""      __author_name__ = ("fragonib")      __author_mail__ = ("fragonib[AT]yahoo[DOT]es")      # Constants -    _JK_KEY_ = "jk" -    _CRYPTED_KEY_ = "crypted" +    PREFERRED_LINK_SOURCES = ['cnl2', 'dlc', 'web'] + +    OFFLINE_TOKEN = "<title>Tattooside" +    PASSWORD_TOKEN = "container_password.php" +    PASSWORD_ERROR_ROKEN = "You have entered an incorrect password" +    PASSWORD_SUBMIT_URL = "http://www.relink.us/container_password.php" +    CAPTCHA_TOKEN = "container_captcha.php" +    CAPTCHA_ERROR_ROKEN = "You have solved the captcha wrong" +    CAPTCHA_IMG_URL = "http://www.relink.us/core/captcha/circlecaptcha.php" +    CAPTCHA_SUBMIT_URL = "http://www.relink.us/container_captcha.php"  +    FILE_TITLE_REGEX = r"<th>Title</th><td><i>(.*)</i></td></tr>" +    FILE_NOTITLE = 'No title' +         +    CNL2_FORM_REGEX = r'<form id="cnl_form-(.*?)</form>' +    CNL2_FORMINPUT_REGEX = r'<input.*?name="%s".*?value="(.*?)"' +    CNL2_JK_KEY = "jk" +    CNL2_CRYPTED_KEY = "crypted" +    DLC_LINK_REGEX = r'<a href=".*?" class="dlc_button" target="_blank">' +    DLC_DOWNLOAD_URL = "http://www.relink.us/download.php"  +    WEB_FORWARD_REGEX = r"getFile\('(?P<link>.+)'\)"; +    WEB_FORWARD_URL = "http://www.relink.us/frame.php"  +    WEB_LINK_REGEX = r'<iframe name="Container" height="100%" frameborder="no" width="100%" src="(?P<link>.+)"></iframe>' +          def setup(self): +        self.fileid = None +        self.package = None +        self.password = None          self.html = None - +        self.captcha = False +              def decrypt(self, pyfile): +          # Init -        self.pyfile = pyfile -        self.package = pyfile.package() +        self.initPackage(pyfile)          # Request package -        self.html = self.requestPackageInfo() +        self.requestPackage() +         +        # Check for online          if not self.isOnline():              self.offline() -        # Check for password protection     +        # Check for protection              if self.isPasswordProtected(): -            self.html = self.submitPassword() -            if self.html is None: -                self.fail("Incorrect password, please set right password on Edit package form and retry") +            self.unlockPasswordProtection() +            self.handleErrors() +             +        if self.isCaptchaProtected(): +            self.captcha = True +            self.unlockCaptchaProtection() +            self.handleErrors()          # Get package name and folder -        (package_name, folder_name) = self.getPackageNameAndFolder() +        (package_name, folder_name) = self.getPackageInfo() -        # Get package links -        try: -            (crypted, jk) = self.getCipherParams() -            package_links = self.getLinks(crypted, jk) -        except: -            self.fail("Unable to decrypt package") +        # Extract package links +        package_links = [] +        for sources in self.PREFERRED_LINK_SOURCES: +            package_links.extend(self.handleLinkSource(sources)) +            if package_links:  # use only first source which provides links +                break +        package_links = set(package_links)          # Pack -        self.packages = [(package_name, package_links, folder_name)] +        if package_links: +            self.packages = [(package_name, package_links, folder_name)] +        else: +            self.fail('Could not extract any links') + +    def initPackage(self, pyfile): +        self.fileid = re.match(self.__pattern__, pyfile.url).group('id') +        self.package = pyfile.package() +        self.password = self.getPassword() +        self.url = pyfile.url + +    def requestPackage(self): +        self.html = self.load(self.url, decode = True)      def isOnline(self): -        if "sorry.png" in self.html: +        if self.OFFLINE_TOKEN in self.html:              self.logDebug("File not found")              return False          return True      def isPasswordProtected(self): -        if "<h1>Container Protection</h1>" in self.html: +        if self.PASSWORD_TOKEN in self.html:              self.logDebug("Links are password protected")              return True -        return False -     -    def requestPackageInfo(self): -        return self.load(self.pyfile.url) -     -    def submitPassword(self): -        # Gather data -        url = self.pyfile.url -        m = re.match(self.__pattern__, url) -        if m is None: -            self.logDebug("Unable to get package id from url [%s]" % url) -            return -        id = m.group('id') -        password = self.getPassword() -                    -        # Submit package password      -        url = "http://www.relink.us/container_password.php?id=" + id -        post = { '#' : '', 'password' : password, 'pw' : 'submit' } -        self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id)) -        html = self.load(url, {}, post) -        # Check for invalid password -        if "An error occurred!" in html: -            self.logDebug("Incorrect password, please set right password on Add package form and retry") -            return None -        else: -            return html    - -    def getPackageNameAndFolder(self): -        # Get title from html -        try: -            title_re = r'<td class="top">Title</td><td class="top">\|</td><td><span class="info_view_id"><i>(?P<title>.+)</i></span></td>' -            title = re.search(title_re, self.html).group('title') -            if 'Title deactived by the owner' in title: -                title = None -        except: -            title = None +    def isCaptchaProtected(self): +        if self.CAPTCHA_TOKEN in self.html: +            self.logDebug("Links are captcha protected") +            return True +        return False -        # Set name & folder -        if title is None: +    def unlockPasswordProtection(self): +        self.logDebug("Submitting password [%s] for protected links" % self.password) +        passwd_url = self.PASSWORD_SUBMIT_URL + "?id=%s" % self.fileid +        passwd_data = { 'id': self.fileid, 'password': self.password, 'pw': 'submit' } +        self.html = self.load(passwd_url, post=passwd_data, decode=True) +             +    def unlockCaptchaProtection(self): +        self.logDebug("Request user positional captcha resolving") +        captcha_img_url = self.CAPTCHA_IMG_URL + "?id=%s" % self.fileid +        coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') +        self.logDebug("Captcha resolved, coords [%s]" % str(coords)) +        captcha_post_url = self.CAPTCHA_SUBMIT_URL + "?id=%s" % self.fileid +        captcha_post_data = { 'button.x': coords[0], 'button.y': coords[1], 'captcha': 'submit' } +        self.html = self.load(captcha_post_url, post=captcha_post_data, decode=True) + +    def getPackageInfo(self): +        name = folder = None + +        # Try to get info from web         +        m = re.search(self.FILE_TITLE_REGEX, self.html) +        if m is not None: +            title = m.group(1).strip() +            if not self.FILE_NOTITLE in title: +                name = folder = title +                self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) +                 +        # Fallback to defaults +        if not name or not folder:              name = self.package.name              folder = self.package.folder              self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) -        else: -            name = folder = title -            self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) -        return name, folder - -    def getCipherParams(self): +        # Return package info  +        return name, folder  +     +    def handleErrors(self):       +        if self.PASSWORD_ERROR_ROKEN in self.html: +            msg = "Incorrect password, please set right password on 'Edit package' form and retry" +            self.logDebug(msg) +            self.fail(msg)   -        # Get vars dict -        vars = {} -        m = re.search(r'flashVars="(?P<vars>.*)"', self.html) -        text = m.group('vars') -        pairs = text.split('&') -        for pair in pairs: -            index = pair.index('=') -            vars[pair[:index]] = pair[index + 1:] +        if self.captcha:           +            if self.CAPTCHA_ERROR_ROKEN in self.html: +                self.logDebug("Invalid captcha, retrying") +                self.invalidCaptcha() +                self.retry() +            else: +                self.correctCaptcha() +            +    def handleLinkSource(self, source): +        if source == 'cnl2': +            return self.handleCNL2Links() +        elif source == 'dlc': +            return self.handleDLCLinks() +        elif source == 'web': +            return self.handleWEBLinks() +        else: +            self.fail('Unknown source [%s] (this is probably a bug)' % source) +             +    def handleCNL2Links(self): +        self.logDebug("Search for CNL2 links") +        package_links = [] +        m = re.search(self.CNL2_FORM_REGEX, self.html, re.DOTALL) +        if m is not None: +            cnl2_form = m.group(1) +            try: +                (vcrypted, vjk) = self._getCipherParams(cnl2_form) +                for (crypted, jk) in zip(vcrypted, vjk): +                    package_links.extend(self._getLinks(crypted, jk)) +            except: +                self.logDebug("Unable to decrypt CNL2 links") +        return package_links +     +    def handleDLCLinks(self): +        self.logDebug('Search for DLC links') +        package_links = [] +        m = re.search(self.DLC_LINK_REGEX, self.html) +        if m is not None: +            container_url = self.DLC_DOWNLOAD_URL + "?id=%s&dlc=1" % self.fileid  +            self.logDebug("Downloading DLC container link [%s]" % container_url) +            try: +                dlc = self.load(container_url) +                dlc_filename = self.fileid + ".dlc" +                dlc_filepath = os.path.join(self.config["general"]["download_folder"], dlc_filename) +                f = open(dlc_filepath, "wb") +                f.write(dlc) +                f.close() +                package_links.append(dlc_filepath) +            except: +                self.logDebug("Unable to download DLC container")     +        return package_links -        # Extract cipher pair -        jk = urllib.unquote(vars[RelinkUs._JK_KEY_].replace("+", " ")) -        crypted = vars[RelinkUs._CRYPTED_KEY_] +    def handleWEBLinks(self): +        self.logDebug("Search for WEB links") +        package_links = [] +        fw_params = re.findall(self.WEB_FORWARD_REGEX, self.html) +        self.logDebug("Decrypting %d Web links" % len(fw_params)) +        for index, fw_param in enumerate(fw_params): +            try: +                fw_url = self.WEB_FORWARD_URL + "?%s" % fw_param +                self.logDebug("Decrypting Web link %d, %s" % (index+1, fw_url)) +                fw_response = self.load(fw_url, decode=True) +                dl_link = re.search(self.WEB_LINK_REGEX, fw_response).group('link') +                package_links.append(dl_link) +            except Exception, detail: +                self.logDebug("Error decrypting Web link %s, %s" % (index, detail)) +            self.setWait(4) +            self.wait() +        return package_links +     +    def _getCipherParams(self, cnl2_form): +             +        # Get jk +        jk_re = self.CNL2_FORMINPUT_REGEX % self.CNL2_JK_KEY        +        vjk = re.findall(jk_re, cnl2_form, re.IGNORECASE) +         +        # Get crypted +        crypted_re = self.CNL2_FORMINPUT_REGEX % RelinkUs.CNL2_CRYPTED_KEY        +        vcrypted = re.findall(crypted_re, cnl2_form, re.IGNORECASE)          # Log and return -        self.logDebug("Javascript cipher key function [%s]" % jk) -        return crypted, jk +        self.logDebug("Detected %d crypted blocks" % len(vcrypted)) +        return vcrypted, vjk -    def getLinks(self, crypted, jk): +    def _getLinks(self, crypted, jk):          # Get key          jreturn = self.js.eval("%s f()" % jk) -        self.logDebug("JsEngine returns value key=[%s]" % jreturn) +        self.logDebug("JsEngine returns value [%s]" % jreturn)          key = binascii.unhexlify(jreturn)          # Decode crypted | 
