summaryrefslogtreecommitdiffstats
path: root/features/step_definitions/browser.rb
blob: fac23b79ac951b34370308429849dc7ce8266d6b (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
Then /^I see the (Unsafe|I2P) Browser start notification and wait for it to close$/ do |browser_type|
  robust_notification_wait("#{browser_type}BrowserStartNotification.png", 60)
end

Then /^the (Unsafe|I2P) Browser has started$/ do |browser_type|
  case browser_type
  when 'Unsafe'
    @screen.wait("UnsafeBrowserHomepage.png", 360)
  when 'I2P'
    step 'the I2P router console is displayed in I2P Browser'
  end
end

When /^I start the (Unsafe|I2P) Browser(?: through the GNOME menu)?$/ do |browser_type|
  step "I start \"#{browser_type} Browser\" via the GNOME \"Internet\" applications menu"
end

When /^I successfully start the (Unsafe|I2P) Browser$/ do |browser_type|
  step "I start the #{browser_type} Browser"
  step "I see and accept the Unsafe Browser start verification" unless browser_type == 'I2P'
  step "I see the #{browser_type} Browser start notification and wait for it to close"
  step "the #{browser_type} Browser has started"
end

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

Then /^I see the (Unsafe|I2P) Browser stop notification$/ do |browser_type|
  robust_notification_wait("#{browser_type}BrowserStopNotification.png", 60)
end

def xul_application_info(application)
  binary = $vm.execute_successfully(
    'echo ${TBB_INSTALL}/firefox', :libs => 'tor-browser'
  ).stdout.chomp
  address_bar_image = "BrowserAddressBar.png"
  unused_tbb_libs = ['libnssdbm3.so']
  case application
  when "Tor Browser"
    user = LIVE_USER
    cmd_regex = "#{binary} .* -profile /home/#{user}/\.tor-browser/profile\.default"
    chroot = ""
    new_tab_button_image = "TorBrowserNewTabButton.png"
  when "Unsafe Browser"
    user = "clearnet"
    cmd_regex = "#{binary} .* -profile /home/#{user}/\.unsafe-browser/profile\.default"
    chroot = "/var/lib/unsafe-browser/chroot"
    new_tab_button_image = "UnsafeBrowserNewTabButton.png"
  when "I2P Browser"
    user = "i2pbrowser"
    cmd_regex = "#{binary} .* -profile /home/#{user}/\.i2p-browser/profile\.default"
    chroot = "/var/lib/i2p-browser/chroot"
    new_tab_button_image = "I2PBrowserNewTabButton.png"
  when "Tor Launcher"
    user = "tor-launcher"
    # We do not enable AppArmor confinement for the Tor Launcher.
    binary = "#{binary}-unconfined"
    tor_launcher_install = $vm.execute_successfully(
      'echo ${TOR_LAUNCHER_INSTALL}', :libs => 'tor-browser'
    ).stdout.chomp
    cmd_regex = "#{binary}\s+-app #{tor_launcher_install}/application\.ini.*"
    chroot = ""
    new_tab_button_image = nil
    address_bar_image = nil
    # The standalone Tor Launcher uses fewer libs than the full
    # browser.
    unused_tbb_libs.concat(["libfreebl3.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,
    :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)
  open_address = Proc.new do
    @screen.click(info[:address_bar_image])
    # This static here since we have no reliable visual indicators
    # that we can watch to know when typing is "safe".
    sleep 5
    # 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
  open_address.call
  if browser == "Tor Browser"
    recovery_on_failure = Proc.new do
      @screen.type(Sikuli::Key.ESC)
      @screen.waitVanish('BrowserReloadButton.png', 3)
      open_address.call
    end
    retry_tor(recovery_on_failure) do
      @screen.wait('BrowserReloadButton.png', 120)
    end
  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 = 'Aktuelle Seite neu laden'
  else
    browser_name = 'Tor Browser'
    reload_action = 'Reload current page'
  end
  expected_title = "#{title} - #{browser_name}"
  app = Dogtail::Application.new('Firefox')
  app.child(expected_title, roleName: 'frame').wait(60)
  # The 'Reload current page' 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.
  app.child(reload_action, roleName: 'push button').wait(60)
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.chomp
  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(30, :msg => "The #{browser} chroot '#{info[:chroot]}' was " \
                      "not removed") do
    !$vm.execute("test -d '#{info[:chroot]}'").success?
  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('BrowserDownloadFileToDialog.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(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 Tor Browser$/ do
  title = 'Tails - Privacy for anyone anywhere'
  step "\"#{title}\" has loaded in the Tor 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|
  firefox = Dogtail::Application.new('Firefox')
  page = firefox.child("Problem loading page", roleName: "document frame")
  # Important to wait here since children() won't retry but return the
  # immediate results
  page.wait
  headers = page.children(roleName: "heading")
  found = headers.any? { |heading| heading.text == error }
  raise "Could not find the '#{error}' error in the Tor Browser" unless found
end