browser_abort_visibility.js (8464B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const TEST_URL = 8 "https://example.com/browser/dom/webauthn/tests/browser/tab_webauthn_result.html"; 9 10 add_task(async function test_setup() { 11 return SpecialPowers.pushPrefEnv({ 12 set: [ 13 ["security.webauth.webauthn_enable_softtoken", false], 14 ["security.webauth.webauthn_enable_usbtoken", true], 15 ], 16 }); 17 }); 18 add_task(test_switch_tab); 19 add_task(test_new_window_make); 20 add_task(test_new_window_get); 21 add_task(test_minimize_make); 22 add_task(test_minimize_get); 23 24 async function assertStatus(tab, expected) { 25 let actual = await SpecialPowers.spawn( 26 tab.linkedBrowser, 27 [], 28 async function () { 29 info("visbility state: " + content.document.visibilityState); 30 info("active: " + content.browsingContext.isActive); 31 return content.document.getElementById("status").value; 32 } 33 ); 34 is(actual, expected, "webauthn request " + expected); 35 } 36 37 async function waitForStatus(tab, expected) { 38 /* eslint-disable no-shadow */ 39 await SpecialPowers.spawn( 40 tab.linkedBrowser, 41 [[expected]], 42 async function (expected) { 43 return ContentTaskUtils.waitForCondition(() => { 44 info( 45 "expecting " + 46 expected + 47 ", visbility state: " + 48 content.document.visibilityState 49 ); 50 info( 51 "expecting " + 52 expected + 53 ", active: " + 54 content.browsingContext.isActive 55 ); 56 return content.document.getElementById("status").value == expected; 57 }); 58 } 59 ); 60 /* eslint-enable no-shadow */ 61 62 await assertStatus(tab, expected); 63 } 64 65 function startMakeCredentialRequest(tab) { 66 return SpecialPowers.spawn(tab.linkedBrowser, [], async function () { 67 const cose_alg_ECDSA_w_SHA256 = -7; 68 69 let publicKey = { 70 rp: { id: content.document.domain, name: "none" }, 71 user: { 72 id: new Uint8Array(), 73 name: "none", 74 displayName: "none", 75 }, 76 challenge: content.crypto.getRandomValues(new Uint8Array(16)), 77 timeout: 5000, // the minimum timeout is actually 15 seconds 78 pubKeyCredParams: [{ type: "public-key", alg: cose_alg_ECDSA_w_SHA256 }], 79 }; 80 81 let status = content.document.getElementById("status"); 82 83 info( 84 "Attempting to create credential for origin: " + 85 content.document.nodePrincipal.origin 86 ); 87 content.navigator.credentials 88 .create({ publicKey }) 89 .then(() => { 90 status.value = "completed"; 91 }) 92 .catch(() => { 93 status.value = "aborted"; 94 }); 95 96 status.value = "pending"; 97 }); 98 } 99 100 function startGetAssertionRequest(tab) { 101 return SpecialPowers.spawn(tab.linkedBrowser, [], async function () { 102 let newCredential = { 103 type: "public-key", 104 id: content.crypto.getRandomValues(new Uint8Array(16)), 105 transports: ["usb"], 106 }; 107 108 let publicKey = { 109 challenge: content.crypto.getRandomValues(new Uint8Array(16)), 110 timeout: 5000, // the minimum timeout is actually 15 seconds 111 rpId: content.document.domain, 112 allowCredentials: [newCredential], 113 }; 114 115 let status = content.document.getElementById("status"); 116 117 info( 118 "Attempting to get credential for origin: " + 119 content.document.nodePrincipal.origin 120 ); 121 content.navigator.credentials 122 .get({ publicKey }) 123 .then(() => { 124 status.value = "completed"; 125 }) 126 .catch(ex => { 127 info("aborted: " + ex); 128 status.value = "aborted"; 129 }); 130 131 status.value = "pending"; 132 }); 133 } 134 135 // Test that MakeCredential() and GetAssertion() requests 136 // are aborted when the current tab loses its focus. 137 async function test_switch_tab() { 138 // Create a new tab for the MakeCredential() request. 139 let tab_create = await BrowserTestUtils.openNewForegroundTab( 140 gBrowser, 141 TEST_URL 142 ); 143 144 // Start the request. 145 await startMakeCredentialRequest(tab_create); 146 await assertStatus(tab_create, "pending"); 147 148 // Open another tab and switch to it. The first will lose focus. 149 let tab_get = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); 150 await assertStatus(tab_create, "pending"); 151 152 // Start a GetAssertion() request in the second tab, the first is aborted 153 await startGetAssertionRequest(tab_get); 154 await waitForStatus(tab_create, "aborted"); 155 await assertStatus(tab_get, "pending"); 156 157 // Start a second request in the second tab. It should abort. 158 await startGetAssertionRequest(tab_get); 159 await waitForStatus(tab_get, "aborted"); 160 161 // Close tabs. 162 BrowserTestUtils.removeTab(tab_create); 163 BrowserTestUtils.removeTab(tab_get); 164 } 165 166 function waitForWindowActive(win, active) { 167 return Promise.all([ 168 BrowserTestUtils.waitForEvent(win, active ? "focus" : "blur"), 169 BrowserTestUtils.waitForEvent(win, active ? "activate" : "deactivate"), 170 ]); 171 } 172 173 async function test_new_window_make() { 174 // Create a new tab for the MakeCredential() request. 175 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); 176 177 // Start a MakeCredential request. 178 await startMakeCredentialRequest(tab); 179 await assertStatus(tab, "pending"); 180 181 let windowGonePromise = waitForWindowActive(window, false); 182 // Open a new window. The tab will lose focus. 183 let win = await BrowserTestUtils.openNewBrowserWindow(); 184 await windowGonePromise; 185 await assertStatus(tab, "pending"); 186 187 let windowBackPromise = waitForWindowActive(window, true); 188 await BrowserTestUtils.closeWindow(win); 189 await windowBackPromise; 190 191 // Close tab. 192 await BrowserTestUtils.removeTab(tab); 193 } 194 195 async function test_new_window_get() { 196 // Create a new tab for the GetAssertion() request. 197 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); 198 199 // Start a GetAssertion request. 200 await startGetAssertionRequest(tab); 201 await assertStatus(tab, "pending"); 202 203 let windowGonePromise = waitForWindowActive(window, false); 204 // Open a new window. The tab will lose focus. 205 let win = await BrowserTestUtils.openNewBrowserWindow(); 206 await windowGonePromise; 207 await assertStatus(tab, "pending"); 208 209 let windowBackPromise = waitForWindowActive(window, true); 210 await BrowserTestUtils.closeWindow(win); 211 await windowBackPromise; 212 213 // Close tab. 214 BrowserTestUtils.removeTab(tab); 215 } 216 217 async function test_minimize_make() { 218 // Minimizing windows doesn't supported in headless mode. 219 if (Services.env.get("MOZ_HEADLESS")) { 220 return; 221 } 222 223 // Create a new window for the MakeCredential() request. 224 let win = await BrowserTestUtils.openNewBrowserWindow(); 225 let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); 226 227 // Start a MakeCredential request. 228 await startMakeCredentialRequest(tab); 229 await assertStatus(tab, "pending"); 230 231 // Minimize the window. 232 let windowGonePromise = waitForWindowActive(win, false); 233 win.minimize(); 234 await assertStatus(tab, "pending"); 235 await windowGonePromise; 236 237 // Restore the window. 238 await new Promise(resolve => SimpleTest.waitForFocus(resolve, win)); 239 await assertStatus(tab, "pending"); 240 241 // Close window and wait for main window to be focused again. 242 let windowBackPromise = waitForWindowActive(window, true); 243 await BrowserTestUtils.removeTab(tab); 244 await BrowserTestUtils.closeWindow(win); 245 await windowBackPromise; 246 } 247 248 async function test_minimize_get() { 249 // Minimizing windows doesn't supported in headless mode. 250 if (Services.env.get("MOZ_HEADLESS")) { 251 return; 252 } 253 254 // Create a new window for the GetAssertion() request. 255 let win = await BrowserTestUtils.openNewBrowserWindow(); 256 let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); 257 258 // Start a GetAssertion request. 259 await startGetAssertionRequest(tab); 260 await assertStatus(tab, "pending"); 261 262 // Minimize the window. 263 let windowGonePromise = waitForWindowActive(win, false); 264 win.minimize(); 265 await assertStatus(tab, "pending"); 266 await windowGonePromise; 267 268 // Restore the window. 269 await new Promise(resolve => SimpleTest.waitForFocus(resolve, win)); 270 await assertStatus(tab, "pending"); 271 272 // Close window and wait for main window to be focused again. 273 let windowBackPromise = waitForWindowActive(window, true); 274 await BrowserTestUtils.removeTab(tab); 275 await BrowserTestUtils.closeWindow(win); 276 await windowBackPromise; 277 }