Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/firefox/profile.rb
1865 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
module Selenium
21
module WebDriver
22
module Firefox
23
class Profile
24
include ProfileHelper
25
26
VALID_PREFERENCE_TYPES = [TrueClass, FalseClass, Integer, Float, String].freeze
27
WEBDRIVER_PREFS = {
28
port: 'webdriver_firefox_port',
29
log_file: 'webdriver.log.file'
30
}.freeze
31
32
DEFAULT_PREFERENCES = {
33
'browser.newtabpage.enabled' => false,
34
'browser.startup.homepage' => 'about:blank',
35
'browser.usedOnWindows10.introURL' => 'about:blank',
36
'network.captive-portal-service.enabled' => false,
37
'security.csp.enable' => false
38
}.freeze
39
40
LOCK_FILES = %w[.parentlock parent.lock lock].freeze
41
42
attr_reader :name, :log_file
43
attr_writer :secure_ssl, :load_no_focus_lib
44
45
class << self
46
def ini
47
@ini ||= ProfilesIni.new
48
end
49
50
def from_name(name)
51
profile = ini[name]
52
return profile if profile
53
54
raise Error::WebDriverError, "unable to find profile named: #{name.inspect}"
55
end
56
57
def decoded(json)
58
JSON.parse(json)
59
end
60
end
61
62
#
63
# Create a new Profile instance
64
#
65
# @example User configured profile
66
#
67
# profile = Selenium::WebDriver::Firefox::Profile.new
68
# profile['network.proxy.http'] = 'localhost'
69
# profile['network.proxy.http_port'] = 9090
70
#
71
# driver = Selenium::WebDriver.for :firefox, :profile => profile
72
#
73
74
def initialize(model = nil)
75
@model = verify_model(model)
76
77
@additional_prefs = read_model_prefs
78
@extensions = {}
79
end
80
81
def layout_on_disk
82
profile_dir = @model ? create_tmp_copy(@model) : Dir.mktmpdir('webdriver-profile')
83
FileReaper << profile_dir
84
85
install_extensions(profile_dir)
86
delete_lock_files(profile_dir)
87
delete_extensions_cache(profile_dir)
88
update_user_prefs_in(profile_dir)
89
90
profile_dir
91
end
92
93
#
94
# Set a preference for this particular profile.
95
#
96
# @see http://kb.mozillazine.org/About:config_entries
97
# @see http://preferential.mozdev.org/preferences.html
98
#
99
100
def []=(key, value)
101
unless VALID_PREFERENCE_TYPES.any? { |e| value.is_a? e }
102
raise TypeError, "expected one of #{VALID_PREFERENCE_TYPES.inspect}, got #{value.inspect}:#{value.class}"
103
end
104
105
if value.is_a?(String) && Util.stringified?(value)
106
raise ArgumentError, "preference values must be plain strings: #{key.inspect} => #{value.inspect}"
107
end
108
109
@additional_prefs[key.to_s] = value
110
end
111
112
def port=(port)
113
self[WEBDRIVER_PREFS[:port]] = port
114
end
115
116
def log_file=(file)
117
@log_file = file
118
self[WEBDRIVER_PREFS[:log_file]] = file
119
end
120
121
#
122
# Add the extension (directory, .zip or .xpi) at the given path to the profile.
123
#
124
125
def add_extension(path, name = extension_name_for(path))
126
@extensions[name] = Extension.new(path)
127
end
128
129
def proxy=(proxy)
130
raise TypeError, "expected #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}" unless proxy.is_a? Proxy
131
132
case proxy.type
133
when :manual
134
self['network.proxy.type'] = 1
135
136
set_manual_proxy_preference 'ftp', proxy.ftp
137
set_manual_proxy_preference 'http', proxy.http
138
set_manual_proxy_preference 'ssl', proxy.ssl
139
set_manual_proxy_preference 'socks', proxy.socks
140
141
self['network.proxy.no_proxies_on'] = proxy.no_proxy || ''
142
when :pac
143
self['network.proxy.type'] = 2
144
self['network.proxy.autoconfig_url'] = proxy.pac
145
when :auto_detect
146
self['network.proxy.type'] = 4
147
else
148
raise ArgumentError, "unsupported proxy type #{proxy.type}"
149
end
150
end
151
152
alias as_json encoded
153
154
private
155
156
def set_manual_proxy_preference(key, value)
157
return unless value
158
159
host, port = value.to_s.split(':', 2)
160
161
self["network.proxy.#{key}"] = host
162
self["network.proxy.#{key}_port"] = Integer(port) if port
163
end
164
165
def install_extensions(directory)
166
destination = File.join(directory, 'extensions')
167
168
@extensions.each do |name, extension|
169
WebDriver.logger.debug({extension: name}.inspect, id: :firefox_profile)
170
extension.write_to(destination)
171
end
172
end
173
174
def read_model_prefs
175
return {} unless @model
176
177
read_user_prefs(File.join(@model, 'user.js'))
178
end
179
180
def delete_extensions_cache(directory)
181
FileUtils.rm_f File.join(directory, 'extensions.cache')
182
end
183
184
def delete_lock_files(directory)
185
LOCK_FILES.each do |name|
186
FileUtils.rm_f File.join(directory, name)
187
end
188
end
189
190
def extension_name_for(path)
191
File.basename(path, File.extname(path))
192
end
193
194
def update_user_prefs_in(directory)
195
path = File.join(directory, 'user.js')
196
prefs = read_user_prefs(path)
197
prefs.merge! self.class::DEFAULT_PREFERENCES
198
prefs.merge!(@additional_prefs)
199
200
# If the user sets the home page, we should also start up there
201
prefs['startup.homepage_welcome_url'] ||= prefs['browser.startup.homepage']
202
203
write_prefs prefs, path
204
end
205
206
def read_user_prefs(path)
207
prefs = {}
208
return prefs unless File.exist?(path)
209
210
File.read(path).split("\n").each do |line|
211
next unless line =~ /user_pref\("([^"]+)"\s*,\s*(.+?)\);/
212
213
key = Regexp.last_match(1)&.strip
214
value = Regexp.last_match(2)&.strip
215
216
# wrap the value in an array to make it a valid JSON string.
217
prefs[key] = JSON.parse("[#{value}]").first
218
end
219
220
prefs
221
end
222
223
def write_prefs(prefs, path)
224
File.open(path, 'w') do |file|
225
prefs.each do |key, value|
226
file.puts %{user_pref("#{key}", #{value.to_json});}
227
end
228
end
229
end
230
end
231
232
# Profile
233
end # Firefox
234
end # WebDriver
235
end # Selenium
236
237