summaryrefslogtreecommitdiffstats
path: root/features/step_definitions/browser.rb
blob: cbf58ed623e5ca8f339e69920c494d573cd57643 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# coding: utf-8
When /^I start the Unsafe Browser(?: through the GNOME menu)?$/ do
  step "I start \"Unsafe Browser\" via GNOME Activities Overview"
end

When /^I successfully start the Unsafe Browser$/ do
  step "I start the Unsafe Browser"
  step "I see and accept the Unsafe Browser start verification"
  step "I see the \"Starting the Unsafe Browser...\" notification after at most 60 seconds"
  step "the Unsafe Browser has started"
end

When /^I close the (?:Tor|Unsafe) Browser$/ do
  @screen.type("q", Sikuli::KeyModifier.CTRL)
end

def xul_application_info(application)
  address_bar_image = "BrowserAddressBar.png"
  address_bar_selected_image = "BrowserAddressBarSelected.png"
  unused_tbb_libs = ['libnssdbm3.so', "libmozavcodec.so", "libmozavutil.so"]
  case application
  when "Tor Browser"
    user = LIVE_USER
    binary = $vm.execute_successfully(
      'echo ${TBB_INSTALL}/firefox.real', :libs => 'tor-browser'
    ).stdout
    cmd_regex = "#{binary} .* -profile /home/#{user}/\.tor-browser/profile\.default"
    chroot = ""
    browser_reload_button_image = "TorBrowserReloadButton.png"
    browser_stop_button_image = "TorBrowserStopButton.png"
    new_tab_button_image = "TorBrowserNewTabButton.png"
  when "Unsafe Browser"
    user = "clearnet"
    binary = $vm.execute_successfully(
      'echo ${TBB_INSTALL}/firefox.real', :libs => 'tor-browser'
    ).stdout
    cmd_regex = "#{binary} .* -profile /home/#{user}/\.unsafe-browser/profile\.default"
    chroot = "/var/lib/unsafe-browser/chroot"
    browser_reload_button_image = "UnsafeBrowserReloadButton.png"
    browser_stop_button_image = "UnsafeBrowserStopButton.png"
    new_tab_button_image = "UnsafeBrowserNewTabButton.png"
  when "Tor Launcher"
    user = "tor-launcher"
    # We do not enable AppArmor confinement for the Tor Launcher.
    binary = $vm.execute_successfully(
      'echo ${TBB_INSTALL}/firefox-unconfined', :libs => 'tor-browser'
    ).stdout
    tor_launcher_install = $vm.execute_successfully(
      'echo ${TOR_LAUNCHER_INSTALL}', :libs => 'tor-browser'
    ).stdout
    cmd_regex = "#{binary}\s+-app #{tor_launcher_install}/application\.ini.*"
    chroot = ""
    new_tab_button_image = nil
    address_bar_image = nil
    browser_reload_button_image = nil
    browser_stop_button_image = nil
    # The standalone Tor Launcher uses fewer libs than the full
    # browser.
    unused_tbb_libs.concat(["libfreebl3.so", "libfreeblpriv3.so", "libnssckbi.so", "libsoftokn3.so"])
  else
    raise "Invalid browser or XUL application: #{application}"
  end
  return {
    :user => user,
    :cmd_regex => cmd_regex,
    :chroot => chroot,
    :new_tab_button_image => new_tab_button_image,
    :address_bar_image => address_bar_image,
    :address_bar_selected_image => address_bar_selected_image,
    :browser_reload_button_image => browser_reload_button_image,
    :browser_stop_button_image => browser_stop_button_image,
    :unused_tbb_libs => unused_tbb_libs,
  }
end

When /^I open a new tab in the (.*)$/ do |browser|
  info = xul_application_info(browser)
  @screen.click(info[:new_tab_button_image])
  @screen.wait(info[:address_bar_image], 10)
end

When /^I open the address "([^"]*)" in the (.*)$/ do |address, browser|
  step "I open a new tab in the #{browser}"
  info = xul_application_info(browser)
  # The image only works for an empty address bar, which we have right
  # now, but now while doing retries. So let's record the coordinates
  # and just reuse them, which works as long as the window is not
  # moved or resized, which shouldn't happen.
  address_bar_match = @screen.find(info[:address_bar_image])
  address_bar_coordinates = [address_bar_match.getX, address_bar_match.getY]
  open_address = Proc.new do
    @screen.hide_cursor
    @screen.click_point(*address_bar_coordinates)
    # This image can easily get incorrectly matched, so we require
    # a pixel-by-pixel exact match, i.e. similarity = 1.0.
    pattern = Sikuli::Pattern.new(info[:address_bar_selected_image])
    pattern.similar(1.0)
    @screen.wait(pattern, 10)
    # Now we now the address bar is properly focused.
    # Remove any remains from previous attempts.
    @screen.type('a', Sikuli::KeyModifier.CTRL)
    @screen.type(Sikuli::Key.BACKSPACE)
    # The browser sometimes loses keypresses when suggestions are
    # shown, which we work around by pasting the address from the
    # clipboard, in one go.
    $vm.set_clipboard(address)
    @screen.type('v', Sikuli::KeyModifier.CTRL)
    @screen.type(Sikuli::Key.ENTER)
  end
  recovery_on_failure = Proc.new do
    @screen.type(Sikuli::Key.ESC)
    @screen.waitVanish(info[:browser_stop_button_image], 3)
    open_address.call
  end
  if browser == "Tor Browser"
    try_method = method(:try_tor)
  else
    try_method = Proc.new { |p, &b| try(attempts: 10, recovery_proc: p, &b) }
  end
  open_address.call
  try_method.call(recovery_on_failure) do
    @screen.waitVanish(info[:browser_stop_button_image], 120)
    @screen.wait(info[:browser_reload_button_image], 120)
  end
end

# This step is limited to the Tor Browser due to #7502 since dogtail
# uses the same interface.
Then /^"([^"]+)" has loaded in the Tor Browser$/ do |title|
  if @language == 'German'
    browser_name = 'Tor-Browser'
    reload_action = 'Neu laden'
  else
    browser_name = 'Tor Browser'
    reload_action = 'Reload'
  end
  expected_title = "#{title} - #{browser_name}"
  try(timeout: 60) { @torbrowser.child(expected_title, roleName: 'frame') }
  # The 'Reload' button (graphically shown as a looping arrow)
  # is only shown when a page has loaded, so once we see the
  # expected title *and* this button has appeared, then we can be sure
  # that the page has fully loaded.
  try(timeout: 60) { @torbrowser.child(reload_action, roleName: 'push button') }
end

Then /^the (.*) has no plugins installed$/ do |browser|
  step "I open the address \"about:plugins\" in the #{browser}"
  step "I see \"TorBrowserNoPlugins.png\" after at most 30 seconds"
end

def xul_app_shared_lib_check(pid, chroot, expected_absent_tbb_libs = [])
  absent_tbb_libs = []
  unwanted_native_libs = []
  tbb_libs = $vm.execute_successfully("ls -1 #{chroot}${TBB_INSTALL}/*.so",
                                      :libs => 'tor-browser').stdout.split
  firefox_pmap_info = $vm.execute("pmap --show-path #{pid}").stdout
  for lib in tbb_libs do
    lib_name = File.basename lib
    if not /\W#{lib}$/.match firefox_pmap_info
      absent_tbb_libs << lib_name
    end
    native_libs = $vm.execute_successfully(
                       "find /usr/lib /lib -name \"#{lib_name}\""
                                           ).stdout.split
    for native_lib in native_libs do
      if /\W#{native_lib}$"/.match firefox_pmap_info
        unwanted_native_libs << lib_name
      end
    end
  end
  absent_tbb_libs -= expected_absent_tbb_libs
  assert(absent_tbb_libs.empty? && unwanted_native_libs.empty?,
         "The loaded shared libraries for the firefox process are not the " +
         "way we expect them.\n" +
         "Expected TBB libs that are absent: #{absent_tbb_libs}\n" +
         "Native libs that we don't want: #{unwanted_native_libs}")
end

Then /^the (.*) uses all expected TBB shared libraries$/ do |application|
  info = xul_application_info(application)
  pid = $vm.execute_successfully("pgrep --uid #{info[:user]} --full --exact '#{info[:cmd_regex]}'").stdout
  assert(/\A\d+\z/.match(pid), "It seems like #{application} is not running")
  xul_app_shared_lib_check(pid, info[:chroot], info[:unused_tbb_libs])
end

Then /^the (.*) chroot is torn down$/ do |browser|
  info = xul_application_info(browser)
  try_for_success(
    timeout: 30,
    message: "The #{browser} chroot '#{info[:chroot]}' was not removed"
  ) do
    $vm.execute("test -d '#{info[:chroot]}'").failure?
  end
end

Then /^the (.*) runs as the expected user$/ do |browser|
  info = xul_application_info(browser)
  assert_vmcommand_success($vm.execute(
    "pgrep --full --exact '#{info[:cmd_regex]}'"),
    "The #{browser} is not running")
  assert_vmcommand_success($vm.execute(
    "pgrep --uid #{info[:user]} --full --exact '#{info[:cmd_regex]}'"),
    "The #{browser} is not running as the #{info[:user]} user")
end

When /^I download some file in the Tor Browser$/ do
  @some_file = 'tails-signing.key'
  some_url = "https://tails.boum.org/#{@some_file}"
  step "I open the address \"#{some_url}\" in the Tor Browser"
end

Then /^I get the browser download dialog$/ do
  @screen.wait('BrowserDownloadDialog.png', 60)
  @screen.wait('BrowserDownloadDialogSaveAsButton.png', 10)
end

When /^I save the file to the default Tor Browser download directory$/ do
  @screen.click('BrowserDownloadDialogSaveAsButton.png')
  @screen.wait('Gtk3SaveFileDialog.png', 10)
  @screen.type(Sikuli::Key.ENTER)
end

Then /^the file is saved to the default Tor Browser download directory$/ do
  assert_not_nil(@some_file)
  expected_path = "/home/#{LIVE_USER}/Tor Browser/#{@some_file}"
  try_for_success(timeout: 10) { $vm.file_exist?(expected_path) }
end

When /^I open Tails homepage in the (.+)$/ do |browser|
  step "I open the address \"https://tails.boum.org\" in the #{browser}"
end

Then /^Tails homepage loads in the Unsafe Browser$/ do
  @screen.wait('TailsHomepage.png', 60)
end

Then /^the Tor Browser shows the "([^"]+)" error$/ do |error|
  page = @torbrowser.child("Problem loading page - Tor Browser", roleName: "frame")
  headers = page.children(roleName: "heading")
  assert(
    headers.any? { |heading| heading.text == error },
    "Could not find the '#{error}' error in the Tor Browser"
  )
end

Then /^I can listen to an Ogg audio track in Tor Browser$/ do
  test_url = 'https://archive.org/download/MussorgskyPicturesAtAnExhibitionorch.Ravel/09Mussorgsky_PicturesAtAnExhibition-LimogesTheMarketPlace.ogg'
  info = xul_application_info('Tor Browser')
  open_test_url = Proc.new do
    step "I open the address \"#{test_url}\" in the Tor Browser"
  end
  recovery_on_failure = Proc.new do
    @screen.type(Sikuli::Key.ESC)
    @screen.waitVanish(info[:browser_stop_button_image], 3)
    open_test_url.call
  end
  step "no application is playing audio"
  open_test_url.call
  try_tor(recovery_on_failure) do
    step "1 application is playing audio after 30 seconds"
  end
end

Then /^I can watch a WebM video in Tor Browser$/ do
  test_url = 'https://tails.boum.org/lib/test_suite/test.webm'
  info = xul_application_info('Tor Browser')
  open_test_url = Proc.new do
    step "I open the address \"#{test_url}\" in the Tor Browser"
  end
  recovery_on_failure = Proc.new do
    @screen.type(Sikuli::Key.ESC)
    @screen.waitVanish(info[:browser_stop_button_image], 3)
    open_test_url.call
  end
  open_test_url.call
  try_tor(recovery_on_failure) do
    @screen.wait("TorBrowserSampleRemoteWebMVideoFrame.png", 30)
  end
end