browser_wpi_base.js (8402B)
1 // This test is fission-only! Make that clear before continuing, to avoid 2 // confusing failures. 3 ok( 4 Services.appinfo.fissionAutostart, 5 "this test requires fission to function!" 6 ); 7 8 requestLongerTimeout(2); 9 10 const WebContentIsolationStrategy = { 11 IsolateNothing: 0, 12 IsolateEverything: 1, 13 IsolateHighValue: 2, 14 }; 15 16 const COM_ORIGIN = "https://example.com"; 17 const ORG_ORIGIN = "https://example.org"; 18 const MOZ_ORIGIN = "https://www.mozilla.org"; 19 20 // Helper for building document-builder.sjs URLs which have specific headers & 21 // HTML content. 22 function documentURL(origin, headers, html) { 23 let params = new URLSearchParams(); 24 params.append("html", html.trim()); 25 for (const [key, value] of Object.entries(headers)) { 26 params.append("headers", `${key}:${value}`); 27 } 28 return `${origin}/document-builder.sjs?${params.toString()}`; 29 } 30 31 async function testTreeRemoteTypes(name, testpage) { 32 // Use document-builder.sjs to build up the expected document tree. 33 function buildURL(path, page) { 34 let html = `<h1>${path}</h1>`; 35 for (let i = 0; i < page.children.length; ++i) { 36 const inner = buildURL(`${path}[${i}]`, page.children[i]); 37 html += `<iframe src=${JSON.stringify(inner)}></iframe>`; 38 } 39 return documentURL(page.origin, page.headers, html); 40 } 41 const url = buildURL(name, testpage); 42 43 // Load the tab and confirm that properties of the loaded documents match 44 // expectation. 45 await BrowserTestUtils.withNewTab(url, async browser => { 46 let stack = [ 47 { 48 path: name, 49 bc: browser.browsingContext, 50 ...testpage, 51 }, 52 ]; 53 54 while (stack.length) { 55 const { path, bc, remoteType, children, origin } = stack.pop(); 56 is( 57 Services.scriptSecurityManager.createContentPrincipal( 58 bc.currentWindowGlobal.documentURI, 59 {} 60 ).originNoSuffix, 61 origin, 62 `Frame ${path} has expected originNoSuffix` 63 ); 64 is( 65 bc.currentWindowGlobal.domProcess.remoteType, 66 remoteType, 67 `Frame ${path} has expected remote type` 68 ); 69 is( 70 bc.children.length, 71 children.length, 72 `Frame ${path} has the expected number of children` 73 ); 74 for (let i = 0; i < bc.children.length; ++i) { 75 stack.push({ 76 path: `${path}[${i}]`, 77 bc: bc.children[i], 78 ...children[i], 79 }); 80 } 81 } 82 }); 83 } 84 85 function mkTestPage({ 86 comRemoteType, 87 orgRemoteType, 88 mozRemoteType, 89 topOrigin, 90 topHeaders = {}, 91 frameHeaders = {}, 92 }) { 93 const topRemoteType = { 94 [COM_ORIGIN]: comRemoteType, 95 [ORG_ORIGIN]: orgRemoteType, 96 [MOZ_ORIGIN]: mozRemoteType, 97 }[topOrigin]; 98 99 const innerChildren = [ 100 { 101 origin: COM_ORIGIN, 102 headers: frameHeaders, 103 remoteType: comRemoteType, 104 children: [], 105 }, 106 { 107 origin: ORG_ORIGIN, 108 headers: frameHeaders, 109 remoteType: orgRemoteType, 110 children: [], 111 }, 112 { 113 origin: MOZ_ORIGIN, 114 headers: frameHeaders, 115 remoteType: mozRemoteType, 116 children: [], 117 }, 118 ]; 119 120 return { 121 origin: topOrigin, 122 headers: topHeaders, 123 remoteType: topRemoteType, 124 children: [ 125 { 126 origin: COM_ORIGIN, 127 headers: frameHeaders, 128 remoteType: comRemoteType, 129 children: [...innerChildren], 130 }, 131 { 132 origin: ORG_ORIGIN, 133 headers: frameHeaders, 134 remoteType: orgRemoteType, 135 children: [...innerChildren], 136 }, 137 { 138 origin: MOZ_ORIGIN, 139 headers: frameHeaders, 140 remoteType: mozRemoteType, 141 children: [...innerChildren], 142 }, 143 ], 144 }; 145 } 146 147 const heuristics = [ 148 { 149 name: "coop", 150 setup_com: async expected => { 151 // Set the COOP header, and load 152 await testTreeRemoteTypes( 153 "com_set_coop", 154 mkTestPage({ 155 topOrigin: COM_ORIGIN, 156 topHeaders: { "Cross-Origin-Opener-Policy": "same-origin" }, 157 comRemoteType: expected.com_high, 158 orgRemoteType: expected.org_normal, 159 mozRemoteType: expected.moz_normal, 160 }) 161 ); 162 }, 163 run_extra_test: async expected => { 164 // Load with both the COOP and COEP headers set. 165 await testTreeRemoteTypes( 166 "com_coop_coep", 167 mkTestPage({ 168 topOrigin: COM_ORIGIN, 169 topHeaders: { 170 "Cross-Origin-Opener-Policy": "same-origin", 171 "Cross-Origin-Embedder-Policy": "require-corp", 172 }, 173 frameHeaders: { 174 "Cross-Origin-Embedder-Policy": "require-corp", 175 "Cross-Origin-Resource-Policy": "cross-origin", 176 }, 177 comRemoteType: expected.com_coop_coep, 178 orgRemoteType: expected.org_coop_coep, 179 mozRemoteType: expected.moz_coop_coep, 180 }) 181 ); 182 }, 183 }, 184 { 185 name: "hasSavedLogin", 186 setup_com: async () => { 187 // add .com to the password manager 188 let LoginInfo = new Components.Constructor( 189 "@mozilla.org/login-manager/loginInfo;1", 190 Ci.nsILoginInfo, 191 "init" 192 ); 193 await Services.logins.addLoginAsync( 194 new LoginInfo(COM_ORIGIN, "", null, "username", "password", "", "") 195 ); 196 197 // Init login detection service to trigger fetching logins 198 let loginDetection = Cc[ 199 "@mozilla.org/login-detection-service;1" 200 ].createInstance(Ci.nsILoginDetectionService); 201 loginDetection.init(); 202 203 await TestUtils.waitForCondition(() => { 204 let x = loginDetection.isLoginsLoaded(); 205 return x; 206 }, "waiting for loading logins from the password manager"); 207 }, 208 }, 209 { 210 name: "isLoggedIn", 211 setup_com: async () => { 212 let p = new Promise(resolve => { 213 Services.obs.addObserver(function obs() { 214 Services.obs.removeObserver( 215 obs, 216 "passwordmgr-form-submission-detected" 217 ); 218 resolve(); 219 }, "passwordmgr-form-submission-detected"); 220 }); 221 222 const TEST_URL = documentURL( 223 COM_ORIGIN, 224 {}, 225 `<form> 226 <input value="username"> 227 <input type="password" value="password"> 228 <input type="submit"> 229 </form>` 230 ); 231 232 // submit the form to simulate the login behavior 233 await BrowserTestUtils.withNewTab(TEST_URL, async browser => { 234 await SpecialPowers.spawn(browser, [], async () => { 235 content.document.querySelector("form").submit(); 236 }); 237 }); 238 await p; 239 }, 240 }, 241 ]; 242 243 async function do_tests(expected) { 244 for (let heuristic of heuristics) { 245 info(`Starting ${heuristic.name} test`); 246 // Clear all site-specific data, as we don't want to have any high-value site 247 // permissions from any previous iterations. 248 Services.logins.removeAllLogins(); 249 await new Promise(resolve => 250 Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve) 251 ); 252 253 // Loads for basic URLs with no special headers set. 254 await testTreeRemoteTypes( 255 "basic_com", 256 mkTestPage({ 257 topOrigin: COM_ORIGIN, 258 comRemoteType: expected.com_normal, 259 orgRemoteType: expected.org_normal, 260 mozRemoteType: expected.moz_normal, 261 }) 262 ); 263 264 await testTreeRemoteTypes( 265 "basic_org", 266 mkTestPage({ 267 topOrigin: ORG_ORIGIN, 268 comRemoteType: expected.com_normal, 269 orgRemoteType: expected.org_normal, 270 mozRemoteType: expected.moz_normal, 271 }) 272 ); 273 274 info(`Setting up ${heuristic.name} test`); 275 await heuristic.setup_com(expected); 276 277 // Load again after the heuristic is triggered 278 info(`Running ${heuristic.name} tests after setup`); 279 await testTreeRemoteTypes( 280 `com_after_${heuristic.name}`, 281 mkTestPage({ 282 topOrigin: COM_ORIGIN, 283 comRemoteType: expected.com_high, 284 orgRemoteType: expected.org_normal, 285 mozRemoteType: expected.moz_normal, 286 }) 287 ); 288 289 // Load again with a .org toplevel 290 await testTreeRemoteTypes( 291 `org_after_${heuristic.name}`, 292 mkTestPage({ 293 topOrigin: ORG_ORIGIN, 294 comRemoteType: expected.com_high, 295 orgRemoteType: expected.org_normal, 296 mozRemoteType: expected.moz_normal, 297 }) 298 ); 299 300 // Run heuristic dependent tests 301 if (heuristic.run_extra_test) { 302 info(`Running extra tests for ${heuristic.name}`); 303 await heuristic.run_extra_test(expected); 304 } 305 } 306 }