22from os import environ , chdir
33from os .path import isdir , isfile , join , abspath
44from time import sleep
5- from selenium import webdriver
5+ from http . client import CannotSendRequest
66from selenium .webdriver .support .ui import WebDriverWait
77from selenium .webdriver .support import expected_conditions as EC
88from selenium .webdriver .common .by import By
9- from selenium .common . exceptions import WebDriverException
9+ from selenium .webdriver . firefox . service import Service
1010from selenium .webdriver .firefox .webdriver import WebDriver as FirefoxDriver
1111from selenium .webdriver .firefox .options import Options
12+ from selenium .common .exceptions import WebDriverException
1213import tbselenium .common as cm
1314from tbselenium .utils import prepend_to_env_var , is_busy
1415from tbselenium .tbbinary import TBBinary
15- from tbselenium .exceptions import (TBDriverConfigError , TBDriverPortError ,
16- TBDriverPathError )
16+ from tbselenium .exceptions import (
17+ TBDriverConfigError , TBDriverPortError , TBDriverPathError )
1718
18- try :
19- from httplib import CannotSendRequest
20- except ImportError :
21- from http .client import CannotSendRequest
2219
2320DEFAULT_BANNED_PORTS = "9050,9051,9150,9151"
2421
@@ -38,42 +35,83 @@ def __init__(self,
3835 pref_dict = {},
3936 socks_port = None ,
4037 control_port = None ,
41- extensions = None ,
38+ extensions = [] ,
4239 default_bridge_type = "" ,
43- capabilities = None ,
44- headless = False ):
45-
40+ headless = False ,
41+ options = None ,
42+ use_custom_profile = False
43+ ):
44+
45+ # use_custom_profile: whether to launch from and *write to* the given
46+ # profile
47+ # False: copy the profile to a tempdir; remove the temp folder on quit
48+ # True: use the given profile without copying. This can be used to keep
49+ # a stateful profile across different launches of the Tor Browser.
50+ # It uses firefox's `-profile`` command line parameter under the hood
51+
52+ self .use_custom_profile = use_custom_profile
4653 self .tor_cfg = tor_cfg
54+
4755 self .setup_tbb_paths (tbb_path , tbb_fx_binary_path ,
4856 tbb_profile_path , tor_data_dir )
49- self .profile = webdriver .FirefoxProfile (self .tbb_profile_path )
50- self .install_extensions (extensions )
57+ self .options = Options () if options is None else options
58+ install_noscript = False
59+
60+ USE_DEPRECATED_PROFILE_METHOD = True
61+ if self .use_custom_profile :
62+ # launch from and write to this custom profile
63+ self .options .add_argument ("-profile" )
64+ self .options .add_argument (self .tbb_profile_path )
65+ elif USE_DEPRECATED_PROFILE_METHOD :
66+ # launch from this custom profile
67+ self .options .profile = self .tbb_profile_path
68+ else :
69+ # Launch with no profile at all. This should be used with caution.
70+ # NoScript does not come installed on browsers launched by this
71+ # method, so we install it ourselves
72+ install_noscript = True
73+
5174 self .init_ports (tor_cfg , socks_port , control_port )
5275 self .init_prefs (pref_dict , default_bridge_type )
53- self .setup_capabilities (capabilities )
5476 self .export_env_vars ()
55- self .binary = self .get_tb_binary (logfile = tbb_logfile_path )
56- self .binary .add_command_line_options ('--class' , '"Tor Browser"' )
57- options = Options ()
77+ # TODO:
78+ # self.binary = self.get_tb_binary(logfile=tbb_logfile_path)
79+ if use_custom_profile :
80+ tbb_service = Service (
81+ executable_path = executable_path ,
82+ log_path = tbb_logfile_path ,
83+ service_args = ["--marionette-port" , "2828" ]
84+ )
85+ else :
86+ tbb_service = Service (
87+ executable_path = executable_path ,
88+ log_path = tbb_logfile_path
89+ )
90+ self .options .binary = self .tbb_fx_binary_path
91+ self .options .add_argument ('--class' )
92+ self .options .add_argument ('"Tor Browser"' )
5893 if headless :
59- options .set_headless ()
94+ self .options .headless = True
95+
6096 super (TorBrowserDriver , self ).__init__ (
61- firefox_profile = self .profile ,
62- firefox_binary = self .binary ,
63- capabilities = self .capabilities ,
64- timeout = cm .TB_INIT_TIMEOUT ,
65- service_log_path = tbb_logfile_path ,
97+ service = tbb_service ,
6698 executable_path = executable_path ,
67- options = options )
99+ options = self .options ,
100+ )
68101 self .is_running = True
102+ self .install_extensions (extensions , install_noscript )
103+ self .temp_profile_dir = self .capabilities ["moz:profile" ]
69104 sleep (1 )
70105
71- def install_extensions (self , extensions ):
72- """Install the given extension to the profile we are launching."""
73- if extensions is None :
74- return
106+ def install_extensions (self , extensions , install_noscript ):
107+ """Install the given extensions to the profile we are launching."""
108+ if install_noscript :
109+ no_script_xpi = join (
110+ self .tbb_path , cm .DEFAULT_TBB_NO_SCRIPT_XPI_PATH )
111+ extensions .append (no_script_xpi )
112+
75113 for extension in extensions :
76- self .profile . add_extension (extension )
114+ self .install_addon (extension )
77115
78116 def init_ports (self , tor_cfg , socks_port , control_port ):
79117 """Check SOCKS port and Tor config inputs."""
@@ -174,8 +212,8 @@ def add_ports_to_fx_banned_ports(self, socks_port, control_port):
174212 """
175213 if socks_port in cm .KNOWN_SOCKS_PORTS :
176214 return
177- tb_prefs = self .profile . default_preferences
178- set_pref = self .profile .set_preference
215+ tb_prefs = self .options . preferences
216+ set_pref = self .options .set_preference
179217
180218 for port_ban_pref in cm .PORT_BAN_PREFS :
181219 banned_ports = tb_prefs .get (port_ban_pref , DEFAULT_BANNED_PORTS )
@@ -188,7 +226,7 @@ def set_tb_prefs_for_using_system_tor(self, control_port):
188226
189227 We set these prefs for running with Tor started with Stem as well.
190228 """
191- set_pref = self .profile .set_preference
229+ set_pref = self .options .set_preference
192230 # Prevent Tor Browser running its own Tor process
193231 set_pref ('extensions.torlauncher.start_tor' , False )
194232 # TODO: investigate whether these prefs are up to date or not
@@ -206,11 +244,15 @@ def set_tb_prefs_for_using_system_tor(self, control_port):
206244 set_pref ('extensions.torlauncher.loglevel' , 2 )
207245 set_pref ('extensions.torlauncher.logmethod' , 0 )
208246 set_pref ('extensions.torlauncher.prompt_at_startup' , False )
247+ # disable XPI signature checking
248+ set_pref ('xpinstall.signatures.required' , False )
249+ set_pref ('xpinstall.whitelist.required' , False )
209250
210251 def init_prefs (self , pref_dict , default_bridge_type ):
211252 self .add_ports_to_fx_banned_ports (self .socks_port , self .control_port )
212- set_pref = self .profile .set_preference
253+ set_pref = self .options .set_preference
213254 set_pref ('browser.startup.page' , "0" )
255+ set_pref ('torbrowser.settings.quickstart.enabled' , True )
214256 set_pref ('browser.startup.homepage' , 'about:newtab' )
215257 set_pref ('extensions.torlauncher.prompt_at_startup' , 0 )
216258 # load strategy normal is equivalent to "onload"
@@ -233,7 +275,7 @@ def init_prefs(self, pref_dict, default_bridge_type):
233275 # pref_dict overwrites above preferences
234276 for pref_name , pref_val in pref_dict .items ():
235277 set_pref (pref_name , pref_val )
236- self .profile .update_preferences ()
278+ # self.profile.update_preferences()
237279
238280 def export_env_vars (self ):
239281 """Setup LD_LIBRARY_PATH and HOME environment variables.
@@ -249,22 +291,6 @@ def export_env_vars(self):
249291 # Add "TBB_DIR/Browser" to the PATH, see issue #10.
250292 prepend_to_env_var ("PATH" , self .tbb_browser_dir )
251293
252- def setup_capabilities (self , caps ):
253- """Setup the required webdriver capabilities."""
254- if caps is None :
255- self .capabilities = {
256- "marionette" : True ,
257- "capabilities" : {
258- "alwaysMatch" : {
259- "moz:firefoxOptions" : {
260- "log" : {"level" : "info" }
261- }
262- }
263- }
264- }
265- else :
266- self .capabilities = caps
267-
268294 def get_tb_binary (self , logfile = None ):
269295 """Return FirefoxBinary pointing to the TBB's firefox binary."""
270296 tbb_logfile = open (logfile , 'a+' ) if logfile else None
@@ -280,13 +306,13 @@ def clean_up_profile_dirs(self):
280306 """Remove temporary profile directories.
281307 Only called when WebDriver.quit() is interrupted
282308 """
283- tempfolder = self .profile .tempfolder
284- profile_path = self .profile .path
309+ if self .use_custom_profile :
310+ # don't remove the profile if we are writing into it
311+ # i.e. stateful mode
312+ return
285313
286- if tempfolder and isdir (tempfolder ):
287- shutil .rmtree (tempfolder )
288- if isdir (profile_path ):
289- shutil .rmtree (profile_path )
314+ if self .temp_profile_dir and isdir (self .temp_profile_dir ):
315+ shutil .rmtree (self .temp_profile_dir )
290316
291317 def quit (self ):
292318 """Quit the driver. Clean up if the parent's quit fails."""
@@ -295,11 +321,10 @@ def quit(self):
295321 super (TorBrowserDriver , self ).quit ()
296322 except (CannotSendRequest , AttributeError , WebDriverException ):
297323 try : # Clean up if webdriver.quit() throws
298- if self . w3c :
324+ if hasattr ( self , "service" ) :
299325 self .service .stop ()
300- if hasattr (self , "binary" ):
301- self .binary .kill ()
302- if hasattr (self , "profile" ):
326+ if hasattr (self , "options" ) and hasattr (
327+ self .options , "profile" ):
303328 self .clean_up_profile_dirs ()
304329 except Exception as e :
305330 print ("[tbselenium] Exception while quitting: %s" % e )
0 commit comments