#!/usr/bin/env python import os, sys, subprocess, locale, urllib2, gobject import pygtk pygtk.require('2.0') import gtk def download_chunk(base): # download 10kb a time chunk = base.dl_response.read(10240) base.dl_bytes_so_far += len(chunk) base.tarball_file.write(chunk) if not chunk: base.tarball_file.close() return False percent = float(base.dl_bytes_so_far) / base.dl_total_size base.progressbar.set_fraction(percent) percent = round(percent*100, 2) base.progressbar.set_text("Downloaded %d" % (percent) + '%') sys.stdout.write("Downloaded %d of %d bytes (%0.2f%%)\r" % (base.dl_bytes_so_far, base.dl_total_size, percent)) if base.dl_bytes_so_far >= base.dl_total_size: sys.stdout.write('\n') return True class TorBrowserLauncher: def __init__(self, current_tbb_version): # initialize the app self.current_tbb_version = current_tbb_version self.discover_arch_lang(); self.build_paths(); self.mkdirs(); launch_gui = True # is TBB already installed? if os.path.isfile(self.paths['file']['start']) and os.access(self.paths['file']['start'], os.X_OK): # does the version file exist? if os.path.isfile(self.paths['file']['version']): installed_tbb_version = open(self.paths['file']['version']).read().strip() if installed_tbb_version == current_tbb_version: # current version is tbb is installed, launch it subprocess.call([self.paths['file']['start']]) launch_gui = False elif installed_tbb_version < self.current_tbb_version: # there is a tbb upgrade available self.set_gui('task', "Your Tor Browser Launcher is out of date. Click Start to download the\nlatest version from https://www.torproject.org.", ['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\nyou have installed is newer than the current version?") else: # if tbb is installed but the version file doesn't exist, something is wrong self.set_gui('error', "Something is wrong. You have the Tor Browser Bundle\ninstalled, but the version file is missing.") # not installed else: # save the current version to the file open(self.paths['file']['version'], 'w').write(self.current_tbb_version) # are the tarball and sig already downloaded? if os.path.isfile(self.paths['file']['tarball']) and os.path.isfile(self.paths['file']['tarball_sig']): # start the gui with verify self.set_gui('task', "You already have Tor Browser Bundle downloaded, but\nit isn't installed yet.", ['verify', 'extract', 'run']) # first run else: self.set_gui('task', "The first time you run the Tor Browser Launcher you need to download\nthe Tor Browser Bundle. Click Start to download it now from\nhttps://www.torproject.org/.", ['download_tarball', 'download_tarball_sig', 'verify', 'extract', 'run']) if launch_gui: self.build_ui() gtk.main() # discover the architecture and language def discover_arch_lang(self): # figure out the architecture self.architecture = subprocess.check_output(['arch']).strip('\n') # figure out the language available_languages = ['en-US', 'ar', 'de', 'es-ES', 'fa', 'fr', 'it', 'ko', 'nl', 'pl', 'pt-PT', 'ru', 'vi', 'zh-CN'] self.language = locale.getdefaultlocale()[0].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_data = os.getenv('HOME')+'/.torbrowser' tarball_filename = 'tor-browser-gnu-linux-'+self.architecture+'-'+self.current_tbb_version+'-dev-'+self.language+'.tar.gz' self.paths = { 'dir': { 'data': tbb_data, 'download': tbb_data+'/download', 'tbb': tbb_data+'/tbb/'+self.architecture }, 'file': { 'version': tbb_data+'/version', 'start': tbb_data+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/start-tor-browser', 'tarball': tbb_data+'/download/'+tarball_filename, 'tarball_sig': tbb_data+'/download/'+tarball_filename+'.asc' }, 'url': { 'tarball': 'https://www.torproject.org/dist/torbrowser/linux/'+tarball_filename, 'tarball_sig': 'https://www.torproject.org/dist/torbrowser/linux/'+tarball_filename+'.asc' }, 'filename': { 'tarball': tarball_filename, 'tarball_sig': tarball_filename+'.asc' } } # create directories that don't exist def mkdirs(self): if os.path.exists(self.paths['dir']['download']) == False: os.makedirs(self.paths['dir']['download']) if os.path.exists(self.paths['dir']['tbb']) == False: os.makedirs(self.paths['dir']['tbb']) # there are different GUIs that might appear, this sets which one we want def set_gui(self, gui, message, tasks): self.gui = gui self.gui_message = message self.gui_task = tasks # build the application's UI def build_ui(self): self.timer = False self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_title("Tor Browser Launcher") self.window.set_border_width(10) self.window.connect("delete_event", self.delete_event) self.window.connect("destroy", self.destroy) self.box = gtk.VBox(False, 20) self.window.add(self.box) self.label = gtk.Label("The first time you run the Tor Browser Launcher you need to download the Tor Browser Bundle. Would you like to download it from the following URL now?") self.label.set_line_wrap(True) self.box.pack_start(self.label, True, True, 0) self.label.show() self.progressbar = gtk.ProgressBar(adjustment=None) self.progressbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT) self.box.pack_start(self.progressbar, True, True, 0) 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() self.download = gtk.Button("Download") self.download.connect("clicked", self.start_download, None) self.button_box.add(self.download) self.download.show() self.exit = gtk.Button("Exit") self.exit.connect("clicked", self.destroy, None) self.button_box.add(self.exit) self.exit.show() self.box.show() self.window.show(); def delete_event(self, widget, event, data=None): return False def destroy(self, widget, data=None): if self.timer: gobject.source_remove(self.timer) self.timer = False gtk.main_quit() def start_download(self, widget, data=None): print 'Starting to download '+self.tarball_url # disable the download button self.download.set_sensitive(False) # initialize the progress bar self.progressbar.set_fraction(0) self.progressbar.set_text('Downloaded 0%') self.progressbar.show() # start the download self.dl_response = urllib2.urlopen(self.tarball_url); self.dl_total_size = self.dl_response.info().getheader('Content-Length').strip() self.dl_total_size = int(self.dl_total_size) self.dl_bytes_so_far = 0 # set a timer to download more chunks self.timer = gobject.timeout_add(1, download_chunk, self) # open a file to write to self.tarball_file = open(self.tarball_path, 'w') if __name__ == "__main__": print 'Tor Browser Launcher' print 'https://github.com/micahflee/torbrowser-launcher' current_tbb_version = '2.3.25-2' app = TorBrowserLauncher(current_tbb_version)