]> git.lizzy.rs Git - torbrowser-launcher.git/blobdiff - torbrowser-launcher
Update torbrowser-settings.desktop
[torbrowser-launcher.git] / torbrowser-launcher
index 86469fd8bff31cd0e31fdfb4a37336edf7b2f2a4..e811242caf12fbf42fe54fa8152f7ee095b2751d 100755 (executable)
@@ -1,9 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 Tor Browser Launcher
 https://github.com/micahflee/torbrowser-launcher/
 
 """
 Tor Browser Launcher
 https://github.com/micahflee/torbrowser-launcher/
 
-Copyright (c) 2013 Micah Lee <micahflee@riseup.net>
+Copyright (c) 2013-2017 Micah Lee <micah@micahflee.com>
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
@@ -26,811 +26,5 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 """
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 """
-
-import gettext
-gettext.install('torbrowser-launcher', '/usr/share/torbrowser-launcher/locale')
-
-from twisted.internet import gtk2reactor
-gtk2reactor.install()
-from twisted.internet import reactor
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-import os, sys, subprocess, locale, urllib2, gobject, time, pickle, json, tarfile, psutil
-
-from twisted.web.client import Agent, ResponseDone
-from twisted.web.http_headers import Headers
-from twisted.internet.protocol import Protocol
-from twisted.internet.ssl import ClientContextFactory
-
-from OpenSSL.SSL import Context, VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT
-from OpenSSL.crypto import load_certificate, FILETYPE_PEM
-
-class VerifyTorProjectCert(ClientContextFactory):
-
-    def __init__(self, torproject_pem):
-        self.torproject_ca = load_certificate(FILETYPE_PEM, open(torproject_pem, 'r').read())
-
-    def getContext(self, host, port):
-        ctx = ClientContextFactory.getContext(self)
-        ctx.set_verify_depth(0)
-        ctx.set_verify(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, self.verifyHostname)
-        return ctx
-
-    def verifyHostname(self, connection, cert, errno, depth, preverifyOK):
-        return cert.digest('sha256') == self.torproject_ca.digest('sha256')
-
-class TBLCommon:
-
-    def __init__(self):
-        print _('Initializing Tor Browser Launcher')
-        
-        # initialize the app
-        self.discover_arch_lang()
-        self.build_paths()
-        self.mkdir(self.paths['dir']['download'])
-        self.mkdir(self.paths['dir']['tbb'])
-        self.init_gnupg()
-
-        self.available_versions = {
-            'tbl_stable': _('Tor Browser Bundle - stable'), 
-            'tbl_alpha': _('Tor Browser Bundle - alpha'), 
-            'obs_tbl': _('Obsfproxy Tor Browser Bundle')
-        }
-
-        # allow buttons to have icons
-        try:
-            settings = gtk.settings_get_default()
-            settings.props.gtk_button_images = True
-        except:
-            pass
-
-    # discover the architecture and language
-    def discover_arch_lang(self):
-        # figure out the architecture
-        (sysname, nodename, release, version, machine) = os.uname()
-        self.architecture = machine
-
-        # figure out the language
-        available_languages = ['en-US', 'ar', 'de', 'es-ES', 'fa', 'fr', 'it', 'ko', 'nl', 'pl', 'pt-PT', 'ru', 'vi', 'zh-CN']
-        default_locale = locale.getdefaultlocale()[0]
-        if default_locale == None:
-            self.language = 'en-US'
-        else:
-            self.language = default_locale.replace('_', '-')
-            if self.language not in available_languages:
-                self.language = self.language.split('-')[0]
-                if self.language not in available_languages:
-                    for l in available_languages:
-                        if l[0:2] == self.language:
-                            self.language = l
-            # if language isn't available, default to english
-            if self.language not in available_languages:
-                self.language = 'en-US'
-
-    # build all relevant paths
-    def build_paths(self, tbb_version = None):
-        homedir = os.getenv('HOME')
-        if not homedir:
-            homedir = '/tmp/.torbrowser-'+os.getenv('USER')
-            if os.path.exists(homedir) == False:
-                try:
-                    os.mkdir(homedir, 0700)
-                except:
-                    self.set_gui('error', _("Error creating {0}").format(homedir), [], False)
-        if not os.access(homedir, os.W_OK):
-            self.set_gui('error', _("{0} is not writable").format(homedir), [], False)
-
-        tbb_data = '%s/.torbrowser' % homedir
-
-        if tbb_version:
-            tarball_filename = 'tor-browser-gnu-linux-'+self.architecture+'-'+tbb_version+'-dev-'+self.language+'.tar.gz'
-            self.paths['file']['tarball'] = tbb_data+'/download/'+tarball_filename
-            self.paths['file']['tarball_sig'] = tbb_data+'/download/'+tarball_filename+'.asc'
-            self.paths['url']['tarball'] = 'https://www.torproject.org/dist/torbrowser/linux/'+tarball_filename
-            self.paths['url']['tarball_sig'] = 'https://www.torproject.org/dist/torbrowser/linux/'+tarball_filename+'.asc'
-            self.paths['filename']['tarball'] = tarball_filename
-            self.paths['filename']['tarball_sig'] = tarball_filename+'.asc'
-
-        else:
-            self.paths = {
-                'dir': {
-                    'data': tbb_data,
-                    'download': tbb_data+'/download',
-                    'tbb': tbb_data+'/tbb/'+self.architecture,
-                    'gnupg_homedir': tbb_data+'/gnupg_homedir'
-                },
-                'file': {
-                    'tbl_bin': '/usr/bin/torbrowser-launcher',
-                    'settings': tbb_data+'/settings',
-                    'version': tbb_data+'/version',
-                    'start': tbb_data+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/start-tor-browser',
-                    'vidalia_bin': tbb_data+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/App/vidalia',
-                    'firefox_bin': tbb_data+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/App/Firefox/firefox',
-                    'firefox_profile': tbb_data+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/Data/profile',
-                    'update_check': tbb_data+'/download/RecommendedTBBVersions',
-                    'icon': '/usr/share/pixmaps/torbrowser80.xpm',
-                    'torproject_pem': '/usr/share/torbrowser-launcher/torproject.pem',
-                    'erinn_key': '/usr/share/torbrowser-launcher/erinn.asc',
-                    'sebastian_key': '/usr/share/torbrowser-launcher/sebastian.asc',
-                    'alexandre_key': '/usr/share/torbrowser-launcher/alexandre.asc'
-                },
-                'url': {
-                    'update_check': 'https://check.torproject.org/RecommendedTBBVersions'
-                },
-                'filename': {}
-            }
-
-    # create a directory
-    def mkdir(self, path):
-        try:
-            if os.path.exists(path) == False:
-                os.makedirs(path, 0700)
-                return True
-        except:
-            self.set_gui('error', _("Cannot create directory {0}").format(path), [], False)
-            return False
-        if not os.access(path, os.W_OK):
-            self.set_gui('error', _("{0} is not writable").format(path), [], False)
-            return False
-        return True
-
-    # if gnupg_homedir isn't set up, set it up
-    def init_gnupg(self):
-        if not os.path.exists(self.paths['dir']['gnupg_homedir']):
-            print _('Creating GnuPG homedir'), self.paths['dir']['gnupg_homedir']
-            if self.mkdir(self.paths['dir']['gnupg_homedir']):
-                # import keys
-                print _('Importing keys')
-                p1 = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['dir']['gnupg_homedir'], '--import', self.paths['file']['erinn_key']])
-                p1.wait()
-                p2 = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['dir']['gnupg_homedir'], '--import', self.paths['file']['sebastian_key']])
-                p2.wait()
-                p3 = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['dir']['gnupg_homedir'], '--import', self.paths['file']['alexandre_key']])
-                p3.wait()
-
-    # load settings
-    def load_settings(self):
-        if os.path.isfile(self.paths['file']['settings']):
-            self.settings = pickle.load(open(self.paths['file']['settings']))
-            # sanity checks
-            if not 'installed_version' in self.settings:
-                return False
-            if not 'latest_version' in self.settings:
-                return False
-            if not 'last_update_check_timestamp' in self.settings:
-                return False
-        else:
-            self.settings = {
-                'preferred_version': 'tbl_stable',
-                'installed_version': False,
-                'latest_version': '0',
-                'last_update_check_timestamp': 0
-            }
-            self.save_settings()
-        return True
-
-    # save settings
-    def save_settings(self):
-        pickle.dump(self.settings, open(self.paths['file']['settings'], 'w'))
-        return True
-
-    # get the process id of a program
-    def get_pid(self, bin_path, python = False):
-        pid = None
-
-        for p in psutil.process_iter():
-            try:
-                if p.pid != os.getpid():
-                    exe = None
-                    if python:
-                        if len(p.cmdline) > 1:
-                            if 'python' in p.cmdline[0]:
-                                exe = p.cmdline[1]
-                    else:
-                        if len(p.cmdline) > 0:
-                            exe = p.cmdline[0]
-                    
-                    if exe == bin_path:
-                        pid = p.pid
-
-            except:
-                pass
-
-        return pid
-
-    # bring program's x window to front
-    def bring_window_to_front(self, pid):
-        # figure out the window id
-        win_id = None
-        p = subprocess.Popen(['wmctrl', '-l', '-p'], stdout=subprocess.PIPE)
-        for line in p.stdout.readlines():
-            line_split = line.split()
-            cur_win_id = line_split[0]
-            cur_win_pid = int(line_split[2])
-            if cur_win_pid == pid:
-                win_id = cur_win_id
-
-        # bring to front
-        if win_id:
-            subprocess.call(['wmctrl', '-i', '-a', win_id])
-
-class TBLSettings:
-    def __init__(self, common):
-        print _('Starting settings dialog')
-        self.common = common
-        self.common.load_settings()
-
-        # set up the window
-        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
-        self.window.set_title(_("Tor Browser Launcher Settings"))
-        self.window.set_icon_from_file(self.common.paths['file']['icon'])
-        self.window.set_position(gtk.WIN_POS_CENTER)
-        self.window.set_border_width(10)
-        self.window.connect("delete_event", self.delete_event)
-        self.window.connect("destroy", self.destroy)
-        
-        # build the rest of the UI
-        self.box = gtk.VBox(False, 10)
-        self.window.add(self.box)
-        self.box.show()
-
-        self.hbox = gtk.HBox(False, 10)
-        self.box.pack_start(self.hbox, True, True, 0)
-        self.hbox.show()
-
-        self.settings_box = gtk.VBox(False, 10)
-        self.hbox.pack_start(self.settings_box, True, True, 0)
-        self.settings_box.show()
-
-        self.labels_box = gtk.VBox(False, 10)
-        self.hbox.pack_start(self.labels_box, True, True, 0)
-        self.labels_box.show()
-
-        # preferred version
-        self.pref_ver_box = gtk.HBox(False, 10)
-        self.settings_box.pack_start(self.pref_ver_box, True, True, 0)
-        self.pref_ver_box.show()
-
-        self.pref_ver_label = gtk.Label(_('I prefer'))
-        self.pref_ver_label.set_line_wrap(True)
-        self.pref_ver_box.pack_start(self.pref_ver_label, True, True, 0)
-        self.pref_ver_label.show()
-
-        options = []
-        for i in self.common.available_versions:
-            options.append(self.common.available_versions[i])
-        options.sort()
-
-        self.pref_ver = gtk.combo_box_new_text()
-        for option in options:
-            self.pref_ver.append_text(option)
-        self.pref_ver.set_active(0)
-        self.pref_ver_box.pack_start(self.pref_ver, True, True, 0)
-        self.pref_ver.show()
-
-        # download over tor
-        self.tor_update_checkbox = gtk.CheckButton(_("Check for and download updates over Tor"))
-        self.settings_box.pack_start(self.tor_update_checkbox, True, True, 0)
-        self.tor_update_checkbox.show()
-
-        # check for updates
-        self.update_checkbox = gtk.CheckButton(_("Check for updates next launch"))
-        self.settings_box.pack_start(self.update_checkbox, True, True, 0)
-        self.update_checkbox.show()
-
-        # labels
-        if(self.common.settings['installed_version']):
-            self.label1 = gtk.Label(_('Installed version:\n{0}').format(self.common.settings['installed_version']))
-        else:
-            self.label1 = gtk.Label(_('Not installed'))
-        self.label1.set_line_wrap(True)
-        self.labels_box.pack_start(self.label1, True, True, 0)
-        self.label1.show()
-
-        if(self.common.settings['last_update_check_timestamp'] > 0):
-            self.label1 = gtk.Label(_('Last checked for updates:\n{0}').format(time.strftime("%B %d, %Y %I:%M %P", time.gmtime(self.common.settings['last_update_check_timestamp']))))
-        else:
-            self.label1 = gtk.Label(_('Never checked for updates'))
-        self.label1.set_line_wrap(True)
-        self.labels_box.pack_start(self.label1, True, True, 0)
-        self.label1.show()
-
-        # button box
-        self.button_box = gtk.HButtonBox()
-        self.button_box.set_layout(gtk.BUTTONBOX_SPREAD)
-        self.box.pack_start(self.button_box, True, True, 0)
-        self.button_box.show()
-
-        # save and launch button
-        save_launch_image = gtk.Image()
-        save_launch_image.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_BUTTON)
-        self.save_launch_button = gtk.Button(_("Launch Tor Browser"))
-        self.save_launch_button.set_image(save_launch_image)
-        self.save_launch_button.connect("clicked", self.save_launch, None)
-        self.button_box.add(self.save_launch_button)
-        self.save_launch_button.show()
-
-        # save and exit button
-        save_exit_image = gtk.Image()
-        save_exit_image.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_BUTTON)
-        self.save_exit_button = gtk.Button(_("Save & Exit"))
-        self.save_exit_button.set_image(save_exit_image)
-        self.save_exit_button.connect("clicked", self.save_exit, None)
-        self.button_box.add(self.save_exit_button)
-        self.save_exit_button.show()
-
-        # cancel button
-        cancel_image = gtk.Image()
-        cancel_image.set_from_stock(gtk.STOCK_CANCEL, gtk.ICON_SIZE_BUTTON)
-        self.cancel_button = gtk.Button(_("Cancel"))
-        self.cancel_button.set_image(cancel_image)
-        self.cancel_button.connect("clicked", self.destroy, None)
-        self.button_box.add(self.cancel_button)
-        self.cancel_button.show()
-
-        # show the window
-        self.window.show()
-
-        # start gtk
-        gtk.main()
-
-    # save and launch
-    def save_launch(self, widget, data=None):
-        self.save()
-        p = subprocess.Popen([self.common.paths['file']['tbl_bin']])
-        self.destroy(False)
-
-    # save and exit
-    def save_exit(self, widget, data=None):
-        self.save()
-        self.destroy(False)
-
-    # save settings
-    def save(self):
-        pass
-
-    # exit
-    def delete_event(self, widget, event, data=None):
-        return False
-    def destroy(self, widget, data=None):
-        gtk.main_quit()
-
-
-class TBLLauncher:
-    def __init__(self, common):
-        print _('Starting launcher dialog')
-        self.common = common
-
-        self.set_gui(None, '', [])
-        self.launch_gui = True
-
-        # if we haven't already hit an error
-        if self.gui != 'error':
-            # load settings
-            if self.common.load_settings():
-                self.common.build_paths(self.common.settings['latest_version'])
-
-                # is vidalia already running and we just need to open a new firefox?
-                if self.common.settings['installed_version']:
-                    vidalia_pid = self.common.get_pid('./App/vidalia')
-                    firefox_pid = self.common.get_pid(self.common.paths['file']['firefox_bin'])
-
-                    if vidalia_pid and not firefox_pid:
-                        print _('Vidalia is already open, but Firefox is closed. Launching new Firefox.')
-                        self.common.bring_window_to_front(vidalia_pid)
-                        subprocess.Popen([self.common.paths['file']['firefox_bin'], '-no-remote', '-profile', self.common.paths['file']['firefox_profile']])
-                        return
-                    elif vidalia_pid and firefox_pid:
-                        print _('Vidalia and Firefox are already open, bringing them to focus')
-
-                        # bring firefox to front, then vidalia
-                        self.common.bring_window_to_front(firefox_pid)
-                        self.common.bring_window_to_front(vidalia_pid)
-                        return
-
-                # how long was it since the last update check?
-                # 86400 seconds = 24 hours
-                current_timestamp = int(time.time())
-                if current_timestamp - self.common.settings['last_update_check_timestamp'] >= 86400:
-                    # check for update
-                    print 'Checking for update'
-                    self.set_gui('task', _("Checking for Tor Browser update."), 
-                        ['download_update_check', 
-                         'attempt_update'])
-
-                else:
-                    # no need to check for update
-                    print _('Checked for update within 24 hours, skipping')
-                    self.start_launcher()
-
-            else:
-                self.set_gui('error', _("Error loading settings. Delete {0} and try again.").format(self.common.paths['file']['settings']), [])
-
-        if self.launch_gui:
-            # set up the window
-            self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
-            self.window.set_title(_("Tor Browser"))
-            self.window.set_icon_from_file(self.common.paths['file']['icon'])
-            self.window.set_position(gtk.WIN_POS_CENTER)
-            self.window.set_border_width(10)
-            self.window.connect("delete_event", self.delete_event)
-            self.window.connect("destroy", self.destroy)
-
-            # build the rest of the UI
-            self.build_ui()
-
-    # download or run TBB
-    def start_launcher(self):
-      # is TBB already installed?
-      if os.path.isfile(self.common.paths['file']['start']) and os.access(self.common.paths['file']['start'], os.X_OK):
-        if self.common.settings['installed_version'] == self.common.settings['latest_version']:
-          # current version of tbb is installed, launch it
-          self.run(False)
-          self.launch_gui = False
-        elif self.common.settings['installed_version'] < self.common.settings['latest_version']:
-          # there is a tbb upgrade available
-          self.set_gui('task', _("Your Tor Browser is out of date."), 
-            ['download_tarball', 
-             'download_tarball_sig', 
-             'verify', 
-             'extract', 
-             'run'])
-        else:
-          # for some reason the installed tbb is newer than the current version?
-          self.set_gui('error', _("Something is wrong. The version of Tor Browser Bundle you have installed is newer than the current version?"), [])
-
-      # not installed
-      else:
-          # are the tarball and sig already downloaded?
-          if os.path.isfile(self.common.paths['file']['tarball']) and os.path.isfile(self.common.paths['file']['tarball_sig']):
-              # start the gui with verify
-              self.set_gui('task', _("Installing Tor Browser."), 
-                  ['verify', 
-                   'extract', 
-                   'run'])
-
-          # first run
-          else:
-              self.set_gui('task', _("Downloading and installing Tor Browser."), 
-                  ['download_tarball', 
-                   'download_tarball_sig', 
-                   'verify', 
-                   'extract', 
-                   'run'])
-   
-    # there are different GUIs that might appear, this sets which one we want
-    def set_gui(self, gui, message, tasks, autostart=True):
-        self.gui = gui
-        self.gui_message = message
-        self.gui_tasks = tasks
-        self.gui_task_i = 0
-        self.gui_autostart = autostart
-
-    # set all gtk variables to False
-    def clear_ui(self):
-        if hasattr(self, 'box'):
-            self.box.destroy()
-        self.box = False
-
-        self.label = False
-        self.progressbar = False
-        self.button_box = False
-        self.start_button = False
-        self.exit_button = False
-
-    # build the application's UI
-    def build_ui(self):
-        self.box = gtk.VBox(False, 20)
-        self.window.add(self.box)
-
-        if self.gui == 'error':
-            # labels
-            self.label = gtk.Label( self.gui_message ) 
-            self.label.set_line_wrap(True)
-            self.box.pack_start(self.label, True, True, 0)
-            self.label.show()
-
-            # exit button
-            exit_image = gtk.Image()
-            exit_image.set_from_stock(gtk.STOCK_CANCEL, gtk.ICON_SIZE_BUTTON)
-            self.exit_button = gtk.Button("Exit")
-            self.exit_button.set_image(exit_image)
-            self.exit_button.connect("clicked", self.destroy, None)
-            self.box.add(self.exit_button)
-            self.exit_button.show()
-
-        elif self.gui == 'task':
-            # label
-            self.label = gtk.Label( self.gui_message ) 
-            self.label.set_line_wrap(True)
-            self.box.pack_start(self.label, True, True, 0)
-            self.label.show()
-            
-            # progress bar
-            self.progressbar = gtk.ProgressBar(adjustment=None)
-            self.progressbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
-            self.progressbar.set_pulse_step(0.01)
-            self.box.pack_start(self.progressbar, True, True, 0)
-
-            # button box
-            self.button_box = gtk.HButtonBox()
-            self.button_box.set_layout(gtk.BUTTONBOX_SPREAD)
-            self.box.pack_start(self.button_box, True, True, 0)
-            self.button_box.show()
-
-            # start button
-            start_image = gtk.Image()
-            start_image.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_BUTTON)
-            self.start_button = gtk.Button(_("Start"))
-            self.start_button.set_image(start_image)
-            self.start_button.connect("clicked", self.start, None)
-            self.button_box.add(self.start_button)
-            if not self.gui_autostart:
-              self.start_button.show()
-
-            # exit button
-            exit_image = gtk.Image()
-            exit_image.set_from_stock(gtk.STOCK_CANCEL, gtk.ICON_SIZE_BUTTON)
-            self.exit_button = gtk.Button(_("Exit"))
-            self.exit_button.set_image(exit_image)
-            self.exit_button.connect("clicked", self.destroy, None)
-            self.button_box.add(self.exit_button)
-            self.exit_button.show()
-
-        self.box.show()
-        self.window.show()
-
-        if self.gui_autostart:
-            self.start(None)
-
-    # start button clicked, begin tasks
-    def start(self, widget, data=None):
-        # disable the start button
-        if self.start_button:
-            self.start_button.set_sensitive(False)
-
-        # start running tasks
-        self.run_task()
-      
-    # run the next task in the task list
-    def run_task(self):
-        self.refresh_gtk()
-
-        if self.gui_task_i >= len(self.gui_tasks):
-            self.destroy(False)
-            return
-
-        task = self.gui_tasks[self.gui_task_i]
-        
-        # get ready for the next task
-        self.gui_task_i += 1
-
-        if task == 'download_update_check':
-            print _('Downloading'), self.common.paths['url']['update_check']
-            self.download('update check', self.common.paths['url']['update_check'], self.common.paths['file']['update_check'])
-        
-        if task == 'attempt_update':
-            print _('Checking to see if update it needed')
-            self.attempt_update()
-
-        elif task == 'download_tarball':
-            print _('Downloading'), self.common.paths['url']['tarball']
-            self.download('tarball', self.common.paths['url']['tarball'], self.common.paths['file']['tarball'])
-
-        elif task == 'download_tarball_sig':
-            print _('Downloading'), self.common.paths['url']['tarball_sig']
-            self.download('signature', self.common.paths['url']['tarball_sig'], self.common.paths['file']['tarball_sig'])
-
-        elif task == 'verify':
-            print _('Verifying signature')
-            self.verify()
-
-        elif task == 'extract':
-            print _('Extracting'), self.common.paths['filename']['tarball']
-            self.extract()
-
-        elif task == 'run':
-            print _('Running'), self.common.paths['file']['start']
-            self.run()
-        
-        elif task == 'start_over':
-            print _('Starting download over again')
-            self.start_over()
-
-    def response_received(self, response):
-        class FileDownloader(Protocol):
-            def __init__(self, file, total, progress, done_cb):
-                self.file = file
-                self.total = total
-                self.so_far = 0
-                self.progress = progress
-                self.all_done = done_cb
-
-            def dataReceived(self, bytes):
-                self.file.write(bytes)
-                self.so_far += len(bytes)
-                percent = float(self.so_far) / float(self.total)
-                self.progress.set_fraction(percent)
-                amount = float(self.so_far)
-                units = "bytes"
-                for (size, unit) in [(1024 * 1024, "MiB"), (1024, "KiB")]:
-                    if amount > size:
-                        units = unit
-                        amount = amount / float(size)
-                        break
-
-                self.progress.set_text(_('Downloaded')+(' %2.1f%% (%2.1f %s)' % ((percent * 100.0), amount, units)))
-
-            def connectionLost(self, reason):
-                print _('Finished receiving body:'), reason.getErrorMessage()
-                self.all_done(reason)
-
-        dl = FileDownloader(self.file_download, response.length, self.progressbar, self.response_finished)
-        response.deliverBody(dl)
-
-    def response_finished(self, msg):
-        if msg.check(ResponseDone):
-            self.file_download.close()
-            # next task!
-            self.run_task()
-
-        else:
-            print "FINISHED", msg
-            ## FIXME handle errors
-
-    def download_error(self, f):
-        print _("Download error"), f
-        self.set_gui('error', _("Error starting download:\n\n{0}\n\nAre you connected to the internet?").format(f.value), [], False)
-        self.clear_ui()
-        self.build_ui()
-
-    def download(self, name, url, path):
-        # initialize the progress bar
-        self.progressbar.set_fraction(0) 
-        self.progressbar.set_text(_('Downloading {0}').format(name))
-        self.progressbar.show()
-        self.refresh_gtk()
-
-        agent = Agent(reactor, VerifyTorProjectCert(self.common.paths['file']['torproject_pem']))
-        d = agent.request('GET', url,
-                          Headers({'User-Agent': ['torbrowser-launcher']}),
-                          None)
-
-        self.file_download = open(path, 'w')
-        d.addCallback(self.response_received).addErrback(self.download_error)
-        
-        if not reactor.running:
-            reactor.run()
-
-    def attempt_update(self):
-        # load the update check file
-        try:
-            versions = json.load(open(self.common.paths['file']['update_check']))
-            latest_version = None
-
-            end = '-Linux'
-            for version in versions:
-                if str(version).find(end) != -1:
-                    latest_version = str(version)
-
-            if latest_version:
-                self.common.settings['latest_version'] = latest_version[:-len(end)]
-                self.common.settings['last_update_check_timestamp'] = int(time.time())
-                self.common.save_settings()
-                self.common.build_paths(self.common.settings['latest_version'])
-                self.start_launcher()
-
-            else:
-                # failed to find the latest version
-                self.set_gui('error', _("Error checking for updates."), [], False)
-        
-        except:
-            # not a valid JSON object
-            self.set_gui('error', _("Error checking for updates."), [], False)
-
-        # now start over
-        self.clear_ui()
-        self.build_ui()
-
-    def verify(self):
-        # initialize the progress bar
-        self.progressbar.set_fraction(0) 
-        self.progressbar.set_text(_('Verifying Signature'))
-        self.progressbar.show()
-
-        p = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.common.paths['dir']['gnupg_homedir'], '--verify', self.common.paths['file']['tarball_sig']])
-        self.pulse_until_process_exits(p)
-        
-        if p.returncode == 0:
-            self.run_task()
-        else:
-            self.set_gui('task', _("SIGNATURE VERIFICATION FAILED!\n\nYou might be under attack, or there might just be a networking problem. Click Start try the download again."), ['start_over'], False)
-            self.clear_ui()
-            self.build_ui()
-
-            if not reactor.running:
-                reactor.run()
-
-    def extract(self):
-        # initialize the progress bar
-        self.progressbar.set_fraction(0) 
-        self.progressbar.set_text(_('Installing'))
-        self.progressbar.show()
-        self.refresh_gtk()
-
-        # make sure this file is a tarfile
-        if tarfile.is_tarfile(self.common.paths['file']['tarball']):
-          tf = tarfile.open(self.common.paths['file']['tarball'])
-          tf.extractall(self.common.paths['dir']['tbb'])
-        else:
-            self.set_gui('task', _("Tor Browser Launcher doesn't understand the file format of {0}"), ['start_over'], False)
-            self.clear_ui()
-            self.build_ui()
-
-        # installation is finished, so save installed_version
-        self.common.settings['installed_version'] = self.common.settings['latest_version']
-        self.common.save_settings()
-
-        self.run_task()
-
-    def run(self, run_next_task = True):
-        subprocess.Popen([self.common.paths['file']['start']])
-        if run_next_task:
-            self.run_task()
-
-    # make the progress bar pulse until process p (a Popen object) finishes
-    def pulse_until_process_exits(self, p):
-        while p.poll() == None:
-            time.sleep(0.01)
-            self.progressbar.pulse()
-            self.refresh_gtk()
-
-    # start over and download TBB again
-    def start_over(self):
-        self.label.set_text(_("Downloading Tor Browser Bundle over again."))
-        self.gui_tasks = ['download_tarball', 'download_tarball_sig', 'verify', 'extract', 'run']
-        self.gui_task_i = 0
-        self.start(None)
-   
-    # refresh gtk
-    def refresh_gtk(self):
-        while gtk.events_pending():
-            gtk.main_iteration(False)
-
-    # exit
-    def delete_event(self, widget, event, data=None):
-        return False
-    def destroy(self, widget, data=None):
-        if hasattr(self, 'file_download'):
-            self.file_download.close()
-        if reactor.running:
-            reactor.stop()
-
-if __name__ == "__main__":
-    tor_browser_launcher_version = '0.0.2'
-
-    print _('Tor Browser Launcher')
-    print _('By Micah Lee, licensed under GPLv3')
-    print _('version {0}').format(tor_browser_launcher_version)
-    print 'https://github.com/micahflee/torbrowser-launcher'
-
-    common = TBLCommon()
-
-    # is torbrowser-launcher already running?
-    tbl_pid = common.get_pid(common.paths['file']['tbl_bin'], True)
-    if tbl_pid:
-        print _('Tor Browser Launcher is already running (pid {0}), bringing to front').format(tbl_pid)
-        common.bring_window_to_front(tbl_pid)
-        sys.exit()
-
-    if '-settings' in sys.argv:
-        # settings mode
-        app = TBLSettings(common)
-
-    else:
-        # launcher mode
-        app = TBLLauncher(common)
-
+import torbrowser_launcher
+torbrowser_launcher.main()