]> git.lizzy.rs Git - torbrowser-launcher.git/blob - torbrowser_launcher/common.py
remove debug output that makes it look like something went wrong
[torbrowser-launcher.git] / torbrowser_launcher / common.py
1 """
2 Tor Browser Launcher
3 https://github.com/micahflee/torbrowser-launcher/
4
5 Copyright (c) 2013-2014 Micah Lee <micah@micahflee.com>
6
7 Permission is hereby granted, free of charge, to any person
8 obtaining a copy of this software and associated documentation
9 files (the "Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following
14 conditions:
15
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27 """
28
29 import os, sys, platform, subprocess, locale, pickle, psutil
30
31 import pygtk
32 pygtk.require('2.0')
33 import gtk
34
35 SHARE = os.getenv('TBL_SHARE', sys.prefix+'/share/torbrowser-launcher')
36
37 import gettext
38 gettext.install('torbrowser-launcher', os.path.join(SHARE, 'locale'))
39
40 from twisted.internet import gtk2reactor
41 gtk2reactor.install()
42
43 class Common:
44
45     def __init__(self, tbl_version):
46         print _('Initializing Tor Browser Launcher')
47         self.tbl_version = tbl_version
48
49         # initialize the app
50         self.default_mirror = 'https://dist.torproject.org/'
51         self.discover_arch_lang()
52         self.build_paths()
53         for d in self.paths['dirs']:
54             self.mkdir(self.paths['dirs'][d])
55         self.load_mirrors()
56         self.load_settings()
57         self.mkdir(self.paths['download_dir'])
58         self.mkdir(self.paths['tbb']['dir'])
59         self.init_gnupg()
60
61         # allow buttons to have icons
62         try:
63             gtk_settings = gtk.settings_get_default()
64             gtk_settings.props.gtk_button_images = True
65         except:
66             pass
67
68     # discover the architecture and language
69     def discover_arch_lang(self):
70         # figure out the architecture
71         self.architecture = 'x86_64' if '64' in platform.architecture()[0] else 'i686'
72
73         # figure out the language
74         available_languages = ['en-US', 'ar', 'de', 'es-ES', 'fa', 'fr', 'it', 'ko', 'nl', 'pl', 'pt-PT', 'ru', 'vi', 'zh-CN']
75         default_locale = locale.getdefaultlocale()[0]
76         if default_locale is None:
77             self.language = 'en-US'
78         else:
79             self.language = default_locale.replace('_', '-')
80             if self.language not in available_languages:
81                 self.language = self.language.split('-')[0]
82                 if self.language not in available_languages:
83                     for l in available_languages:
84                         if l[0:2] == self.language:
85                             self.language = l
86             # if language isn't available, default to english
87             if self.language not in available_languages:
88                 self.language = 'en-US'
89
90     # build all relevant paths
91     def build_paths(self, tbb_version=None):
92         homedir = os.getenv('HOME')
93         if not homedir:
94             homedir = '/tmp/.torbrowser-'+os.getenv('USER')
95             if not os.path.exists(homedir):
96                 try:
97                     os.mkdir(homedir, 0700)
98                 except:
99                     self.set_gui('error', _("Error creating {0}").format(homedir), [], False)
100         if not os.access(homedir, os.W_OK):
101             self.set_gui('error', _("{0} is not writable").format(homedir), [], False)
102
103         tbb_config = '{0}/.config/torbrowser'.format(homedir)
104         tbb_cache = '{0}/.cache/torbrowser'.format(homedir)
105         tbb_local = '{0}/.local/share/torbrowser'.format(homedir)
106         old_tbb_data = '{0}/.torbrowser'.format(homedir)
107
108         if tbb_version:
109             # tarball filename
110             if self.architecture == 'x86_64':
111                 arch = 'linux64'
112             else:
113                 arch = 'linux32'
114             tarball_filename = 'tor-browser-'+arch+'-'+tbb_version+'_'+self.language+'.tar.xz'
115
116             # tarball
117             self.paths['tarball_url'] = '{0}torbrowser/'+tbb_version+'/'+tarball_filename
118             self.paths['tarball_file'] = tbb_cache+'/download/'+tarball_filename
119             self.paths['tarball_filename'] = tarball_filename
120
121             # sig
122             self.paths['sha256_file'] = tbb_cache+'/download/sha256sums.txt'
123             self.paths['sha256_sig_file'] = tbb_cache+'/download/sha256sums.txt.asc'
124             self.paths['sha256_url'] = '{0}torbrowser/'+tbb_version+'/sha256sums.txt'
125             self.paths['sha256_sig_url'] = '{0}torbrowser/'+tbb_version+'/sha256sums.txt.asc'
126         else:
127             self.paths = {
128                 'dirs': {
129                     'config': tbb_config,
130                     'cache': tbb_cache,
131                     'local': tbb_local,
132                 },
133                 'old_data_dir': old_tbb_data,
134                 'tbl_bin': sys.argv[0],
135                 'icon_file': os.path.join(os.path.dirname(SHARE), 'pixmaps/torbrowser80.xpm'),
136                 'torproject_pem': os.path.join(SHARE, 'torproject.pem'),
137                 'signing_keys': [os.path.join(SHARE, 'erinn.asc'), os.path.join(SHARE, 'tor-browser-developers.asc')],
138                 'mirrors_txt': [os.path.join(SHARE, 'mirrors.txt'),
139                                 tbb_config+'/mirrors.txt'],
140                 'modem_sound': os.path.join(SHARE, 'modem.ogg'),
141                 'download_dir': tbb_cache+'/download',
142                 'gnupg_homedir': tbb_local+'/gnupg_homedir',
143                 'settings_file': tbb_config+'/settings',
144                 'update_check_url': 'https://www.torproject.org/projects/torbrowser/RecommendedTBBVersions',
145                 'update_check_file': tbb_cache+'/download/RecommendedTBBVersions',
146                 'tbb': {
147                     'dir': tbb_local+'/tbb/'+self.architecture,
148                     'start': tbb_local+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/start-tor-browser',
149                     'versions': tbb_local+'/tbb/'+self.architecture+'/tor-browser_'+self.language+'/Browser/TorBrowser/Docs/sources/versions',
150                 },
151             }
152
153     # create a directory
154     @staticmethod
155     def mkdir(path):
156         try:
157             if not os.path.exists(path):
158                 os.makedirs(path, 0700)
159                 return True
160         except:
161             print _("Cannot create directory {0}").format(path)
162             return False
163         if not os.access(path, os.W_OK):
164             print _("{0} is not writable").format(path)
165             return False
166         return True
167
168     # if gnupg_homedir isn't set up, set it up
169     def init_gnupg(self):
170         if not os.path.exists(self.paths['gnupg_homedir']):
171             print _('Creating GnuPG homedir'), self.paths['gnupg_homedir']
172             self.mkdir(self.paths['gnupg_homedir'])
173         self.import_keys()
174
175     # import gpg keys
176     def import_keys(self):
177         print _('Importing keys')
178         for key in self.paths['signing_keys']:
179             subprocess.Popen(['/usr/bin/gpg', '--homedir', self.paths['gnupg_homedir'], '--import', key]).wait()
180
181     # load mirrors
182     def load_mirrors(self):
183         self.mirrors = []
184         for srcfile in self.paths['mirrors_txt']:
185             if not os.path.exists(srcfile):
186                 continue
187             for mirror in open(srcfile, 'r').readlines():
188                 if mirror.strip() not in self.mirrors:
189                     self.mirrors.append(mirror.strip())
190
191     # load settings
192     def load_settings(self):
193         default_settings = {
194             'tbl_version': self.tbl_version,
195             'installed_version': False,
196             'latest_version': '0',
197             'update_over_tor': True,
198             'check_for_updates': False,
199             'modem_sound': False,
200             'last_update_check_timestamp': 0,
201             'mirror': self.default_mirror
202         }
203
204         if os.path.isfile(self.paths['settings_file']):
205             settings = pickle.load(open(self.paths['settings_file']))
206             resave = False
207
208             # settings migrations
209             if settings['tbl_version'] <= '0.1.0':
210                 print '0.1.0 migration'
211                 settings['installed_version'] = settings['installed_version']['stable']
212                 settings['latest_version'] = settings['latest_version']['stable']
213                 resave = True
214
215                 # make new tbb folder
216                 self.mkdir(self.paths['tbb']['dir'])
217                 old_tbb_dir = self.paths['old_data_dir']+'/tbb/stable/'+self.architecture+'/tor-browser_'+self.language
218                 new_tbb_dir = self.paths['tbb']['dir']+'/tor-browser_'+self.language
219                 if os.path.isdir(old_tbb_dir):
220                     os.rename(old_tbb_dir, new_tbb_dir)
221
222             # make sure settings file is up-to-date
223             for setting in default_settings:
224                 if setting not in settings:
225                     settings[setting] = default_settings[setting]
226                     resave = True
227
228             # make sure the version is current
229             if settings['tbl_version'] != self.tbl_version:
230                 settings['tbl_version'] = self.tbl_version
231                 resave = True
232
233             self.settings = settings
234             if resave:
235                 self.save_settings()
236
237         else:
238             self.settings = default_settings
239             self.save_settings()
240
241     # save settings
242     def save_settings(self):
243         pickle.dump(self.settings, open(self.paths['settings_file'], 'w'))
244         return True
245
246     # get the process id of a program
247     @staticmethod
248     def get_pid(bin_path, python=False):
249         pid = None
250
251         for p in psutil.process_iter():
252             try:
253                 if p.pid != os.getpid():
254                     exe = None
255                     if python:
256                         if len(p.cmdline) > 1:
257                             if 'python' in p.cmdline[0]:
258                                 exe = p.cmdline[1]
259                     else:
260                         if len(p.cmdline) > 0:
261                             exe = p.cmdline[0]
262
263                     if exe == bin_path:
264                         pid = p.pid
265
266             except:
267                 pass
268
269         return pid
270
271     # bring program's x window to front
272     @staticmethod
273     def bring_window_to_front(pid):
274         # figure out the window id
275         win_id = None
276         p = subprocess.Popen(['wmctrl', '-l', '-p'], stdout=subprocess.PIPE)
277         for line in p.stdout.readlines():
278             line_split = line.split()
279             cur_win_id = line_split[0]
280             cur_win_pid = int(line_split[2])
281             if cur_win_pid == pid:
282                 win_id = cur_win_id
283
284         # bring to front
285         if win_id:
286             subprocess.call(['wmctrl', '-i', '-a', win_id])