From 4b62ecf07f97a43ab5bebf715499d3faa69975e6 Mon Sep 17 00:00:00 2001
From: GamaC0de <nitzo2001@yahoo.com>
Date: Tue, 10 May 2016 02:04:45 +0300
Subject: [SafelinkingNet] fix #2457

---
 module/plugins/crypter/SafelinkingNet.py | 141 ++++++++++++++++++++-----------
 1 file changed, 90 insertions(+), 51 deletions(-)

(limited to 'module/plugins/crypter')

diff --git a/module/plugins/crypter/SafelinkingNet.py b/module/plugins/crypter/SafelinkingNet.py
index d1c23d14f..8b49ac1d2 100644
--- a/module/plugins/crypter/SafelinkingNet.py
+++ b/module/plugins/crypter/SafelinkingNet.py
@@ -1,84 +1,123 @@
 # -*- coding: utf-8 -*-
 
-import re
+import pycurl
 
-import BeautifulSoup
-
-from module.plugins.internal.misc import json
+from module.network.HTTPRequest import BadHeader
 from module.plugins.internal.Crypter import Crypter
+from module.plugins.internal.misc import json
 from module.plugins.captcha.SolveMedia import SolveMedia
 
 
 class SafelinkingNet(Crypter):
     __name__    = "SafelinkingNet"
     __type__    = "crypter"
-    __version__ = "0.20"
+    __version__ = "0.21"
     __status__  = "testing"
 
-    __pattern__ = r'https?://(?:www\.)?safelinking\.net/([pd])/\w+'
+    __pattern__ = r'https?://(?:www\.)?safelinking\.net/(?P<TYPE>[pd]/)?(?P<ID>\w{7})'
     __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__ = """Safelinking.net decrypter plugin"""
     __license__     = "GPLv3"
-    __authors__     = [("quareevo", "quareevo@arcor.de")]
+    __authors__     = [("quareevo",  "quareevo@arcor.de"         ),
+                       ("tbsn",      "tbsnpy_github@gmx.de"      ),
+                       ("GammaC0de", "nitzo2001[AT]yahoo[DOT]com")]
 
+    # Safelinking seems to use a static SolveMedia key
+    SOLVEMEDIA_KEY = "OZ987i6xTzNs9lw5.MA-2Vxbc-UxFrLu"
 
-    SOLVEMEDIA_PATTERN = "solvemediaApiKey = '([\w\-.]+)';"
 
+    def api_response(self, url, post_data):
+        self.req.http.c.setopt(pycurl.HTTPHEADER, ["Accept: application/json, text/plain, */*",
+                                                   "Content-Type: application/json"])
 
-    def decrypt(self, pyfile):
-        url = pyfile.url
+        try:
+            res = json.loads(self.load(url, post=json.dumps(post_data)))
+
+        except (BadHeader, ValueError), e:
+            self.log_error(e.message)
+            self.fail(e.message)
+
+        # Headers back to normal
+        self.req.http.c.setopt(pycurl.HTTPHEADER, ["Accept: */*",
+                                                   "Accept-Language: en-US,en",
+                                                   "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+                                                   "Connection: keep-alive",
+                                                   "Keep-Alive: 300",
+                                                   "Expect:"])
 
-        if re.match(self.__pattern__, url).group(1) == "d":
+        return res
+
+
+    def decrypt(self, pyfile):
+        # Process direct links
+        if self.info['pattern']['TYPE'] == "d/":
+            header = self.load(pyfile.url, just_header=True)
 
-            header = self.load(url, just_header=True)
             if 'location' in header:
                 self.links = [header.get('location')]
+
             else:
                 self.error(_("Couldn't find forwarded Link"))
 
-        else:
-            postData = {"post-protect": "1"}
+        else:  # Process protected links
+            self.package_password = self.get_password()
+
+            post_data = {'hash': self.info['pattern']['ID']}
+
+            link_info = self.api_response("http://safelinking.net/v1/protected", post_data)
 
-            self.data = self.load(url)
+            if "messsage" in link_info:
+                self.log_error(link_info['messsage'])
+                self.fail(link_info['messsage'])
 
-            if "link-password" in self.data:
-                postData['link-password'] = self.get_password()
+            # Response: Links
+            elif "links" in link_info:
+                for link in link_info['links']:
+                    self.links.append(link['url'])
+                    return
+
+            if link_info['security'].get('usePassword', False):
+                if self.package_password:
+                    self.log_debug(_("Using package password"))
+                    post_data['password'] = self.package_password
 
-            if "altcaptcha" in self.data:
-                m = re.search(self.SOLVEMEDIA_PATTERN, self.data)
-                if m is not None:
-                    captchaKey = m.group(1)
-                    captcha = SolveMedia(pyfile)
-                    captchaProvider = "Solvemedia"
                 else:
-                    self.fail(_("Error parsing captcha"))
-
-                response, challenge = captcha.challenge(captchaKey)
-                postData['adcopy_challenge'] = challenge
-                postData['adcopy_response']  = response
-
-                self.data = self.load(url, post=postData)
-
-                if "The CAPTCHA code you entered was wrong" in self.data:
-                    self.retry_captcha()
-
-                if "The password you entered was incorrect" in self.data:
-                    self.fail(_("Wrong password"))
-
-            pyfile.package().password = ""
-            soup = BeautifulSoup.BeautifulSoup(self.data)
-            scripts = soup.findAll("script")
-            for s in scripts:
-                if "d_links" in s.text:
-                    break
-            m = re.search('d_links":(\[.*?\])', s.text)
-            if m is not None:
-                linkDict = json.loads(m.group(1))
-                for link in linkDict:
-                    if not "http://" in link['full']:
-                        self.links.append("https://safelinking.net/d/" + link['full'])
-                    else:
-                        self.links.append(link['full'])
+                    self.fail(_("Password required"))
+
+            if link_info['security'].get('useCaptcha', False):
+                self.captcha = SolveMedia(pyfile)
+                response, challenge = self.captcha.challenge(self.SOLVEMEDIA_KEY)
+
+                post_data['answer']      = response
+                post_data['challengeId'] = challenge
+                post_data['type']        = "0"
+
+            json_res = self.api_response("https://safelinking.net/v1/captcha", post_data)
+
+            # Evaluate response
+            if json_res is None:
+                self.fail(_("Invalid JSON response"))
+
+            # Response: Wrong password
+            elif "passwordFail" in json_res:
+                self.log_error(_('Wrong password: "%s"') % self.package_password)
+                self.fail(_("Wrong password"))
+
+            elif "captchaFail" in json_res:
+                self.retry_captcha()
+
+            # Response: Error message
+            elif "message" in json_res:
+                self.log_error(_("Site error: %s") % json_res['message'] )
+                self.retry(wait=60, msg=json_res['message'])
+
+            # Response: Links
+            elif "links" in json_res:
+                for link in json_res['links']:
+                    self.links.append(link['url'])
+
+            else:
+                self.fail(_("Unexpected JSON response"))
-- 
cgit v1.2.3