browser_permission_delegate_geo.js (9004B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const ORIGIN = "https://example.com"; 7 const CROSS_SUBFRAME_PAGE = 8 getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) + 9 "temporary_permissions_subframe.html"; 10 11 const CROSS_FRAME_PAGE = 12 getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) + 13 "temporary_permissions_frame.html"; 14 15 const PromptResult = { 16 ALLOW: "allow", 17 DENY: "deny", 18 PROMPT: "prompt", 19 }; 20 21 var Perms = Services.perms; 22 var uri = NetUtil.newURI(ORIGIN); 23 var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {}); 24 25 async function checkNotificationBothOrigins( 26 firstPartyOrigin, 27 thirdPartyOrigin 28 ) { 29 // Notification is shown, check label and deny to clean 30 let popuphidden = BrowserTestUtils.waitForEvent( 31 PopupNotifications.panel, 32 "popuphidden" 33 ); 34 35 let notification = PopupNotifications.panel.firstElementChild; 36 // Check the label of the notificaiton should be the first party 37 is( 38 PopupNotifications.getNotification("geolocation").options.name, 39 firstPartyOrigin, 40 "Use first party's origin" 41 ); 42 43 // Check the second name of the notificaiton should be the third party 44 is( 45 PopupNotifications.getNotification("geolocation").options.secondName, 46 thirdPartyOrigin, 47 "Use third party's origin" 48 ); 49 50 // Check remember checkbox is hidden 51 let checkbox = notification.checkbox; 52 ok(!!checkbox, "checkbox is present"); 53 ok(checkbox.hidden, "checkbox is not visible"); 54 ok(!checkbox.checked, "checkbox not checked"); 55 56 EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {}); 57 await popuphidden; 58 } 59 60 async function checkGeolocation(browser, frameId, expect) { 61 let isPrompt = expect == PromptResult.PROMPT; 62 let waitForPrompt; 63 if (isPrompt) { 64 waitForPrompt = BrowserTestUtils.waitForEvent( 65 PopupNotifications.panel, 66 "popupshown" 67 ); 68 } 69 70 await SpecialPowers.spawn( 71 browser, 72 [{ frameId, expect, isPrompt }], 73 async args => { 74 let frame = content.document.getElementById(args.frameId); 75 76 let waitForNoPrompt = new Promise(resolve => { 77 function onMessage(event) { 78 // Check the result right here because there's no notification 79 Assert.equal( 80 event.data, 81 args.expect, 82 "Correct expectation for third party" 83 ); 84 content.window.removeEventListener("message", onMessage); 85 resolve(); 86 } 87 88 if (!args.isPrompt) { 89 content.window.addEventListener("message", onMessage); 90 } 91 }); 92 93 await content.SpecialPowers.spawn(frame, [], async () => { 94 const { E10SUtils } = ChromeUtils.importESModule( 95 "resource://gre/modules/E10SUtils.sys.mjs" 96 ); 97 98 E10SUtils.wrapHandlingUserInput(this.content, true, function () { 99 let frameDoc = this.content.document; 100 frameDoc.getElementById("geo").click(); 101 }); 102 }); 103 104 if (!args.isPrompt) { 105 await waitForNoPrompt; 106 } 107 } 108 ); 109 110 if (isPrompt) { 111 await waitForPrompt; 112 } 113 } 114 115 add_setup(async function () { 116 await new Promise(r => { 117 SpecialPowers.pushPrefEnv( 118 { 119 set: [ 120 ["test.wait300msAfterTabSwitch", true], 121 ["dom.security.featurePolicy.header.enabled", true], 122 ["dom.security.featurePolicy.webidl.enabled", true], 123 // This is the amount of time before the repeating 124 // NetworkGeolocationProvider timer is stopped. 125 // It needs to be less than 5000ms, or the timer will be 126 // reported as left behind by the test. 127 ["geo.timeout", 4000], 128 ], 129 }, 130 r 131 ); 132 }); 133 }); 134 135 // Test that temp blocked permissions in first party affect the third party 136 // iframe. 137 add_task(async function testUseTempPermissionsFirstParty() { 138 await BrowserTestUtils.withNewTab( 139 CROSS_SUBFRAME_PAGE, 140 async function (browser) { 141 SitePermissions.setForPrincipal( 142 principal, 143 "geo", 144 SitePermissions.BLOCK, 145 SitePermissions.SCOPE_TEMPORARY, 146 browser 147 ); 148 149 await checkGeolocation(browser, "frame", PromptResult.DENY); 150 151 SitePermissions.removeFromPrincipal(principal, "geo", browser); 152 } 153 ); 154 }); 155 156 // Test that persistent permissions in first party affect the third party 157 // iframe. 158 add_task(async function testUsePersistentPermissionsFirstParty() { 159 await BrowserTestUtils.withNewTab( 160 CROSS_SUBFRAME_PAGE, 161 async function (browser) { 162 async function checkPermission(aPermission, aExpect) { 163 PermissionTestUtils.add(uri, "geo", aPermission); 164 await checkGeolocation(browser, "frame", aExpect); 165 166 if (aExpect == PromptResult.PROMPT) { 167 // Notification is shown, check label and deny to clean 168 let popuphidden = BrowserTestUtils.waitForEvent( 169 PopupNotifications.panel, 170 "popuphidden" 171 ); 172 173 let notification = PopupNotifications.panel.firstElementChild; 174 // Check the label of the notificaiton should be the first party 175 is( 176 PopupNotifications.getNotification("geolocation").options.name, 177 uri.host, 178 "Use first party's origin" 179 ); 180 181 EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {}); 182 183 await popuphidden; 184 SitePermissions.removeFromPrincipal(null, "geo", browser); 185 } 186 187 PermissionTestUtils.remove(uri, "geo"); 188 } 189 190 await checkPermission(Perms.PROMPT_ACTION, PromptResult.PROMPT); 191 await checkPermission(Perms.DENY_ACTION, PromptResult.DENY); 192 await checkPermission(Perms.ALLOW_ACTION, PromptResult.ALLOW); 193 } 194 ); 195 }); 196 197 // Test that we do not prompt for maybe unsafe permission delegation if the 198 // origin of the page is the original src origin. 199 add_task(async function testPromptInMaybeUnsafePermissionDelegation() { 200 await BrowserTestUtils.withNewTab( 201 CROSS_SUBFRAME_PAGE, 202 async function (browser) { 203 // Persistent allow top level origin 204 PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION); 205 206 await checkGeolocation(browser, "frameAllowsAll", PromptResult.ALLOW); 207 208 SitePermissions.removeFromPrincipal(null, "geo", browser); 209 PermissionTestUtils.remove(uri, "geo"); 210 } 211 ); 212 }); 213 214 // Test that we should prompt if we are in unsafe permission delegation and 215 // change location to origin which is not explicitly trusted. The prompt popup 216 // should include both first and third party origin. 217 add_task(async function testPromptChangeLocationUnsafePermissionDelegation() { 218 await BrowserTestUtils.withNewTab( 219 CROSS_SUBFRAME_PAGE, 220 async function (browser) { 221 // Persistent allow top level origin 222 PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION); 223 224 let iframe = await SpecialPowers.spawn(browser, [], () => { 225 return content.document.getElementById("frameAllowsAll") 226 .browsingContext; 227 }); 228 229 let otherURI = 230 "https://test1.example.com/browser/browser/base/content/test/permissions/permissions.html"; 231 let loaded = BrowserTestUtils.browserLoaded(browser, true, otherURI); 232 await SpecialPowers.spawn(iframe, [otherURI], async function (_otherURI) { 233 content.location = _otherURI; 234 }); 235 await loaded; 236 237 await checkGeolocation(browser, "frameAllowsAll", PromptResult.PROMPT); 238 await checkNotificationBothOrigins(uri.host, "test1.example.com"); 239 240 SitePermissions.removeFromPrincipal(null, "geo", browser); 241 PermissionTestUtils.remove(uri, "geo"); 242 } 243 ); 244 }); 245 246 // If we are in unsafe permission delegation and the origin is explicitly 247 // trusted in ancestor chain. Do not need prompt 248 add_task(async function testExplicitlyAllowedInChain() { 249 await BrowserTestUtils.withNewTab(CROSS_FRAME_PAGE, async function (browser) { 250 // Persistent allow top level origin 251 PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION); 252 253 let iframeAncestor = await SpecialPowers.spawn(browser, [], () => { 254 return content.document.getElementById("frameAncestor").browsingContext; 255 }); 256 257 let iframe = await SpecialPowers.spawn(iframeAncestor, [], () => { 258 return content.document.getElementById("frameAllowsAll").browsingContext; 259 }); 260 261 // Change location to check that we actually look at the ancestor chain 262 // instead of just considering the "same origin as src" rule. 263 let otherURI = 264 "https://test2.example.com/browser/browser/base/content/test/permissions/permissions.html"; 265 let loaded = BrowserTestUtils.browserLoaded(browser, true, otherURI); 266 await SpecialPowers.spawn(iframe, [otherURI], async function (_otherURI) { 267 content.location = _otherURI; 268 }); 269 await loaded; 270 271 await checkGeolocation( 272 iframeAncestor, 273 "frameAllowsAll", 274 PromptResult.ALLOW 275 ); 276 277 PermissionTestUtils.remove(uri, "geo"); 278 }); 279 });