#!/usr/bin/env python
+
+import gettext
+gettext.install('torbrowser-launcher', '/usr/share/torbrowser-launcher/locale')
+
from twisted.internet import gtk2reactor
gtk2reactor.install()
from twisted.internet import reactor
pygtk.require('2.0')
import gtk
-import os, sys, subprocess, locale, urllib2, gobject, time, pickle, json
+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
self.build_paths()
self.mkdir(self.paths['dir']['download'])
self.mkdir(self.paths['dir']['tbb'])
+ self.init_gnupg()
# allow buttons to have icons
try:
if self.load_settings():
self.build_paths(self.settings['latest_version'])
+ # is tbb already running and we just need to open a new firefox?
+ if self.settings['installed_version']:
+ vidalia_pid = None
+ firefox_pid = None
+ for p in psutil.process_iter():
+ try:
+ if p.exe == self.paths['file']['vidalia_bin']:
+ vidalia_pid = p.pid
+ if p.exe == self.paths['file']['firefox_bin']:
+ firefox_pid = p.pid
+ except:
+ pass
+
+ if vidalia_pid and not firefox_pid:
+ print _('Vidalia is already open, but Firefox is closed. Launching new Firefox.')
+ subprocess.Popen([self.paths['file']['firefox_bin'], '-no-remote', '-profile', self.paths['file']['firefox_profile']])
+ return
+ elif vidalia_pid and firefox_pid:
+ print _('Vidalia and Firefox are already open, bringing them to focus')
+
+ # figure out the window ids of vidalia and firefox
+ vidalia_win_id = None
+ firefox_win_id = None
+ p = subprocess.Popen(['wmctrl', '-l', '-p'], stdout=subprocess.PIPE)
+ for line in p.stdout.readlines():
+ line_split = line.split()
+ win_id = line_split[0]
+ win_pid = int(line_split[2])
+ if win_pid == vidalia_pid:
+ vidalia_win_id = win_id
+ if win_pid == firefox_pid:
+ firefox_win_id = win_id
+
+ # bring firefox to front, then vidalia
+ if firefox_win_id:
+ subprocess.call(['wmctrl', '-i', '-a', firefox_win_id])
+ if vidalia_win_id:
+ subprocess.call(['wmctrl', '-i', '-a', vidalia_win_id])
+
+ return
+
# how long was it since the last update check?
# 86400 seconds = 24 hours
current_timestamp = int(time.time())
if current_timestamp - self.settings['last_update_check_timestamp'] >= 86400:
# check for update
print 'Checking for update'
- self.set_gui('task', "Checking for Tor Browser 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'
+ print _('Checked for update within 24 hours, skipping')
self.start_launcher()
else:
- self.set_gui('error', "Error loading settings. Delete ~/.torbrowser and try again.", [])
+ self.set_gui('error', _("Error loading settings. Delete ~/.torbrowser and try again."), [])
if self.launch_gui:
# set up the window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
- self.window.set_title("Tor Browser")
+ self.window.set_title(_("Tor Browser"))
+ self.window.set_icon_from_file(self.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)
# build the rest of the UI
self.build_ui()
- reactor.run()
# download or run TBB
def start_launcher(self):
self.launch_gui = False
elif self.settings['installed_version'] < self.settings['latest_version']:
# there is a tbb upgrade available
- self.set_gui('task', "Your Tor Browser is out of date.",
+ self.set_gui('task', _("Your Tor Browser is out of date."),
['download_tarball',
'download_tarball_sig',
'verify',
'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?", [])
+ 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.paths['file']['tarball']) and os.path.isfile(self.paths['file']['tarball_sig']):
# start the gui with verify
- self.set_gui('task', "Installing Tor Browser.",
+ self.set_gui('task', _("Installing Tor Browser."),
['verify',
'extract',
'run'])
# first run
else:
- self.set_gui('task', "Downloading and installing Tor Browser.",
+ self.set_gui('task', _("Downloading and installing Tor Browser."),
['download_tarball',
'download_tarball_sig',
'verify',
try:
os.mkdir(homedir, 0700)
except:
- self.set_gui('error', "Error creating %s" % homedir, [], False)
+ self.set_gui('error', _("Error creating {0}").format(homedir), [], False)
if not os.access(homedir, os.W_OK):
- self.set_gui('error', "%s is not writable" % homedir, [], False)
+ self.set_gui('error', _("{0} is not writable").format(homedir), [], False)
tbb_data = '%s/.torbrowser' % homedir
'data': tbb_data,
'download': tbb_data+'/download',
'tbb': tbb_data+'/tbb/'+self.architecture,
- 'gpg': tbb_data+'/gpgtmp'
+ 'gnupg_homedir': tbb_data+'/gnupg_homedir'
},
'file': {
'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',
- 'verify': '/usr/share/torbrowser-launcher/verify.sh',
- 'torproject_pem': '/usr/share/torbrowser-launcher/torproject.pem'
+ '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'
},
'url': {
'update_check': 'https://check.torproject.org/RecommendedTBBVersions'
try:
if os.path.exists(path) == False:
os.makedirs(path, 0700)
+ return True
except:
- self.set_gui('error', "Cannot create directory %s" % path, [], False)
+ 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', "%s is not writable" % path, [], False)
+ 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']])
+ p2 = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['dir']['gnupg_homedir'], '--import', self.paths['file']['sebastian_key']])
+ # wait for keys to import before moving on
+ p1.wait()
+ p2.wait()
# there are different GUIs that might appear, this sets which one we want
def set_gui(self, gui, message, tasks, autostart=True):
self.window.show()
if self.gui_autostart:
- self.start(None)
+ self.start(None)
# start button clicked, begin tasks
def start(self, widget, data=None):
self.gui_task_i += 1
if task == 'download_update_check':
- print 'Downloading '+self.paths['url']['update_check']
+ print _('Downloading'), self.paths['url']['update_check']
self.download('update check', self.paths['url']['update_check'], self.paths['file']['update_check'])
if task == 'attempt_update':
- print 'Checking to see if update it needed'
+ print _('Checking to see if update it needed')
self.attempt_update()
elif task == 'download_tarball':
- print 'Downloading '+self.paths['url']['tarball']
+ print _('Downloading'), self.paths['url']['tarball']
self.download('tarball', self.paths['url']['tarball'], self.paths['file']['tarball'])
elif task == 'download_tarball_sig':
- print 'Downloading '+self.paths['url']['tarball_sig']
+ print _('Downloading'), self.paths['url']['tarball_sig']
self.download('signature', self.paths['url']['tarball_sig'], self.paths['file']['tarball_sig'])
elif task == 'verify':
- print 'Verifying signature'
+ print _('Verifying signature')
self.verify()
elif task == 'extract':
- print 'Extracting '+self.paths['filename']['tarball']
+ print _('Extracting'), self.paths['filename']['tarball']
self.extract()
elif task == 'run':
- print 'Running '+self.paths['file']['start']
+ print _('Running'), self.paths['file']['start']
self.run()
elif task == 'start_over':
- print 'Starting download over again'
+ print _('Starting download over again')
self.start_over()
def response_received(self, response):
amount = amount / float(size)
break
- self.progress.set_text('Downloaded %2.1f%% (%2.1f %s)' % ((percent * 100.0), amount, units))
+ 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()
+ print _('Finished receiving body:'), reason.getErrorMessage()
self.all_done(reason)
dl = FileDownloader(self.file_download, response.length, self.progressbar, self.response_finished)
## FIXME handle errors
def download_error(self, f):
- print "Download error", f
- self.set_gui('error', "Error starting download:\n\n%s\n\nAre you connected to the internet?" % f.value, [], False)
+ 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 '+name)
+ self.progressbar.set_text(_('Downloading {0}').format(name))
self.progressbar.show()
self.refresh_gtk()
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
else:
# failed to find the latest version
- self.set_gui('error', "Error checking for updates.", [], False)
+ self.set_gui('error', _("Error checking for updates."), [], False)
except:
# not a valid JSON object
- self.set_gui('error', "Error checking for updates.", [], False)
+ self.set_gui('error', _("Error checking for updates."), [], False)
# now start over
self.clear_ui()
def verify(self):
# initialize the progress bar
self.progressbar.set_fraction(0)
- self.progressbar.set_text('Verifying Signature')
+ self.progressbar.set_text(_('Verifying Signature'))
self.progressbar.show()
- p = subprocess.Popen([self.paths['file']['verify'], self.paths['dir']['gpg'], self.paths['file']['tarball_sig']], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ p = subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['dir']['gnupg_homedir'], '--verify', self.paths['file']['tarball_sig']])
self.pulse_until_process_exits(p)
-
- output = p.stdout.read()
- if 'Good signature' in output:
+ if p.returncode == 0:
self.run_task()
else:
- self.progressbar.hide()
- self.label.set_text("SIGNATURE VERIFICATION FAILED!\n\nYou might be under attack, or there might just be a networking problem. Click Start try the download again.")
- self.gui_tasks = ['start_over']
- self.gui_task_i = 0
- self.start_button.show()
- self.start_button.set_sensitive(True)
+ 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.set_text(_('Installing'))
self.progressbar.show()
+ self.refresh_gtk()
- p = subprocess.Popen(['tar', '-xf', self.paths['file']['tarball'], '-C', self.paths['dir']['tbb']], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- self.pulse_until_process_exits(p)
+ # make sure this file is a tarfile
+ if tarfile.is_tarfile(self.paths['file']['tarball']):
+ tf = tarfile.open(self.paths['file']['tarball'])
+ tf.extractall(self.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.settings['installed_version'] = self.settings['latest_version']
# start over and download TBB again
def start_over(self):
- self.label.set_text("Downloading Tor Browser Bundle over again.")
+ 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)
def destroy(self, widget, data=None):
if hasattr(self, 'file_download'):
self.file_download.close()
- reactor.stop()
+ if reactor.running:
+ reactor.stop()
if __name__ == "__main__":
tor_browser_launcher_version = '0.1'
- print 'Tor Browser Launcher'
- print 'version %s' % (tor_browser_launcher_version)
+ print _('Tor Browser Launcher')
+ print _('version {0}').format(tor_browser_launcher_version)
print 'https://github.com/micahflee/torbrowser-launcher'
app = TorBrowserLauncher()