]> git.lizzy.rs Git - torbrowser-launcher.git/blobdiff - torbrowser_launcher/launcher.py
Make downloading over Tor work
[torbrowser-launcher.git] / torbrowser_launcher / launcher.py
index 6f319fe7b077070754d116fcd0769d2479622760..959a2aca66a22b95f3406859689735b3683e83bd 100644 (file)
@@ -37,8 +37,8 @@ import threading
 import re
 import unicodedata
 import requests
+import socks
 import gpg
-import OpenSSL
 import xml.etree.ElementTree as ET
 
 from PyQt5 import QtCore, QtWidgets, QtGui
@@ -81,16 +81,6 @@ class Launcher(QtWidgets.QMainWindow):
 
         # If Tor Browser is not installed, detect latest version, download, and install
         if not self.common.settings['installed'] or not self.check_min_version():
-            # If downloading over Tor, include txsocksx
-            if self.common.settings['download_over_tor']:
-                try:
-                    import txsocksx
-                    print(_('Downloading over Tor'))
-                except ImportError:
-                    Alert(self.common, _("The python-txsocksx package is missing, downloads will not happen over tor"))
-                    self.common.settings['download_over_tor'] = False
-                    self.common.save_settings()
-
             # Different message if downloading for the first time, or because your installed version is too low
             download_message = ""
             if not self.common.settings['installed']:
@@ -109,6 +99,9 @@ class Launcher(QtWidgets.QMainWindow):
                           'extract',
                           'run'])
 
+            if self.common.settings['download_over_tor']:
+                print(_('Downloading over Tor'))
+
         else:
             # Tor Browser is already installed, so run
             self.run(False)
@@ -283,12 +276,10 @@ class Launcher(QtWidgets.QMainWindow):
         # Initialize the progress bar
         self.progress_bar.setValue(0)
         self.progress_bar.setMaximum(100)
-        self.progress_bar.setFormat(_('Downloading') + ' {0}, %p%'.format(name))
-
         if self.common.settings['download_over_tor']:
-            # TODO: make requests work over SOCKS5 proxy
-            # this is the proxy to use: self.common.settings['tor_socks_address']
-            pass
+            self.progress_bar.setFormat(_('Downloading') + ' {0} '.format(name) + _('(over Tor)') + ', %p%')
+        else:
+            self.progress_bar.setFormat(_('Downloading') + ' {0}, %p%'.format(name))
 
         def progress_update(total_bytes, bytes_so_far):
             percent = float(bytes_so_far) / float(total_bytes)
@@ -300,8 +291,9 @@ class Launcher(QtWidgets.QMainWindow):
                     amount /= float(size)
                     break
 
-            message = _('Downloaded')+(' %2.1f%% (%2.1f %s)' % ((percent * 100.0), amount, units))
-            print(message, end='\r')
+            message = _('Downloaded') + (' %2.1f%% (%2.1f %s)' % ((percent * 100.0), amount, units))
+            if self.common.settings['download_over_tor']:
+                message += ' ' + _('(over Tor)')
 
             self.progress_bar.setMaximum(total_bytes)
             self.progress_bar.setValue(bytes_so_far)
@@ -323,21 +315,21 @@ class Launcher(QtWidgets.QMainWindow):
         t.start()
         time.sleep(0.2)
 
-    def try_default_mirror(self, widget, data=None):
+    def try_default_mirror(self):
         # change mirror to default and relaunch TBL
         self.common.settings['mirror'] = self.common.default_mirror
         self.common.save_settings()
         subprocess.Popen([self.common.paths['tbl_bin']])
         self.close()
 
-    def try_forcing_english(self, widget, data=None):
+    def try_forcing_english(self):
         # change force english to true and relaunch TBL
         self.common.settings['force_en-US'] = True
         self.common.save_settings()
         subprocess.Popen([self.common.paths['tbl_bin']])
         self.close()
 
-    def try_tor(self, widget, data=None):
+    def try_tor(self):
         # set download_over_tor to true and relaunch TBL
         self.common.settings['download_over_tor'] = True
         self.common.save_settings()
@@ -361,10 +353,10 @@ class Launcher(QtWidgets.QMainWindow):
     def verify(self):
         self.progress_bar.setValue(0)
         self.progress_bar.setMaximum(0)
-        self.progress_bar.setFormat(_('Verifying Signature'))
-        self.progress_bar.setTextVisible(True)
         self.progress_bar.show()
 
+        self.label.setText(_('Verifying Signature'))
+
         def success():
             self.run_task()
 
@@ -384,35 +376,24 @@ class Launcher(QtWidgets.QMainWindow):
         time.sleep(0.2)
 
     def extract(self):
-        # initialize the progress bar
         self.progress_bar.setValue(0)
         self.progress_bar.setMaximum(0)
-        self.progress_bar.setFormat(_('Installing'))
         self.progress_bar.show()
 
-        extracted = False
-        try:
-            if self.common.paths['tarball_file'][-2:] == 'xz':
-                # if tarball is .tar.xz
-                xz = lzma.LZMAFile(self.common.paths['tarball_file'])
-                tf = tarfile.open(fileobj=xz)
-                tf.extractall(self.common.paths['tbb']['dir'])
-                extracted = True
-            else:
-                # if tarball is .tar.gz
-                if tarfile.is_tarfile(self.common.paths['tarball_file']):
-                    tf = tarfile.open(self.common.paths['tarball_file'])
-                    tf.extractall(self.common.paths['tbb']['dir'])
-                    extracted = True
-        except:
-            pass
+        self.label.setText(_('Installing'))
 
-        if not extracted:
+        def success():
+            self.run_task()
+
+        def error(message):
             self.set_state('task', _("Tor Browser Launcher doesn't understand the file format of {0}".format(self.common.paths['tarball_file'])), ['start_over'], False)
             self.update()
-            return
 
-        self.run_task()
+        t = ExtractThread(self.common)
+        t.error.connect(error)
+        t.success.connect(success)
+        t.start()
+        time.sleep(0.2)
 
     def check_min_version(self):
         installed_version = None
@@ -496,11 +477,23 @@ class DownloadThread(QtCore.QThread):
         self.url = url
         self.path = path
 
+        # Use tor socks5 proxy, if enabled
+        if self.common.settings['download_over_tor']:
+            socks5_address = 'socks5://{}'.format(self.common.settings['tor_socks_address'])
+            self.proxies = {
+                'https': socks5_address,
+                'http': socks5_address
+            }
+        else:
+            self.proxies = None
+
     def run(self):
         with open(self.path, "wb") as f:
             try:
                 # Start the request
-                r = requests.get(self.url, headers={'User-Agent': 'torbrowser-launcher'}, stream=True)
+                r = requests.get(self.url,
+                                 headers={'User-Agent': 'torbrowser-launcher'},
+                                 stream=True, proxies=self.proxies)
 
                 # If status code isn't 200, something went wrong
                 if r.status_code != 200:
@@ -508,7 +501,7 @@ class DownloadThread(QtCore.QThread):
                     if self.common.settings['mirror'] != self.common.default_mirror:
                         message = (_("Download Error:") +
                                    " {0}\n\n" + _("You are currently using a non-default mirror") +
-                                   ":\n{1}\n\n" + _("Would you like to switch back to the default?")).format(r.status_code, common.settings['mirror'])
+                                   ":\n{1}\n\n" + _("Would you like to switch back to the default?")).format(r.status_code, self.common.settings['mirror'])
                         self.download_error.emit('error_try_default_mirror', message)
 
                     # Should we switch to English?
@@ -532,6 +525,15 @@ class DownloadThread(QtCore.QThread):
                     f.write(data)
                     self.progress_update.emit(total_bytes, bytes_so_far)
 
+            except requests.exceptions.SSLError:
+                if not self.common.settings['download_over_tor']:
+                    message = _('Invalid SSL certificate for:\n{0}\n\nYou may be under attack.').format(self.url.decode()) + "\n\n" + _('Try the download again using Tor?')
+                    self.download_error.emit('error_try_tor', message)
+                else:
+                    message = _('Invalid SSL certificate for:\n{0}\n\nYou may be under attack.'.format(self.url.decode()))
+                    self.download_error.emit('error', message)
+                return
+
             except requests.exceptions.ConnectionError:
                 # Connection error
                 message = _("Error starting download:\n\n{0}\n\nAre you connected to the internet?").format(self.url.decode())
@@ -539,13 +541,12 @@ class DownloadThread(QtCore.QThread):
                 # TODO: check for SSL error, also check if connecting over Tor if there's a socks5 error
                 return
 
-        print('')
         self.download_complete.emit()
 
 
 class VerifyThread(QtCore.QThread):
     """
-    Verify a signature in a separate thread
+    Verify the signature in a separate thread
     """
     success = QtCore.pyqtSignal()
     error = QtCore.pyqtSignal(str)
@@ -570,3 +571,38 @@ class VerifyThread(QtCore.QThread):
                 self.error.emit(str(e))
             else:
                 self.success.emit()
+
+
+class ExtractThread(QtCore.QThread):
+    """
+    Extract the tarball in a separate thread
+    """
+    success = QtCore.pyqtSignal()
+    error = QtCore.pyqtSignal()
+
+    def __init__(self, common):
+        super(ExtractThread, self).__init__()
+        self.common = common
+
+    def run(self):
+        extracted = False
+        try:
+            if self.common.paths['tarball_file'][-2:] == 'xz':
+                # if tarball is .tar.xz
+                xz = lzma.LZMAFile(self.common.paths['tarball_file'])
+                tf = tarfile.open(fileobj=xz)
+                tf.extractall(self.common.paths['tbb']['dir'])
+                extracted = True
+            else:
+                # if tarball is .tar.gz
+                if tarfile.is_tarfile(self.common.paths['tarball_file']):
+                    tf = tarfile.open(self.common.paths['tarball_file'])
+                    tf.extractall(self.common.paths['tbb']['dir'])
+                    extracted = True
+        except:
+            pass
+
+        if extracted:
+            self.success.emit()
+        else:
+            self.error.emit()