browser_temporary_permissions_expiry.js (6158B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 /* eslint-disable mozilla/no-arbitrary-setTimeout */ 4 5 "use strict"; 6 7 const ORIGIN = "https://example.com"; 8 const PERMISSIONS_PAGE = 9 getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) + 10 "permissions.html"; 11 12 // Ignore promise rejection caused by clicking Deny button. 13 const { PromiseTestUtils } = ChromeUtils.importESModule( 14 "resource://testing-common/PromiseTestUtils.sys.mjs" 15 ); 16 PromiseTestUtils.allowMatchingRejectionsGlobally(/The request is not allowed/); 17 18 const EXPIRE_TIME_MS = 100; 19 const TIMEOUT_MS = 500; 20 21 const EXPIRE_TIME_CUSTOM_MS = 1000; 22 const TIMEOUT_CUSTOM_MS = 1500; 23 24 const kVREnabled = SpecialPowers.getBoolPref("dom.vr.enabled"); 25 26 // Test that temporary permissions can be re-requested after they expired 27 // and that the identity block is updated accordingly. 28 add_task(async function testTempPermissionRequestAfterExpiry() { 29 await SpecialPowers.pushPrefEnv({ 30 set: [ 31 ["privacy.temporary_permission_expire_time_ms", EXPIRE_TIME_MS], 32 ["media.navigator.permission.fake", true], 33 ["dom.vr.always_support_vr", true], 34 ], 35 }); 36 37 let principal = 38 Services.scriptSecurityManager.createContentPrincipalFromOrigin(ORIGIN); 39 let ids = ["geo", "camera"]; 40 41 if (kVREnabled) { 42 ids.push("xr"); 43 } 44 45 for (let id of ids) { 46 await BrowserTestUtils.withNewTab( 47 PERMISSIONS_PAGE, 48 async function (browser) { 49 let blockedIcon = gPermissionPanel._identityPermissionBox.querySelector( 50 `.blocked-permission-icon[data-permission-id='${id}']` 51 ); 52 53 SitePermissions.setForPrincipal( 54 principal, 55 id, 56 SitePermissions.BLOCK, 57 SitePermissions.SCOPE_TEMPORARY, 58 browser 59 ); 60 61 Assert.deepEqual( 62 SitePermissions.getForPrincipal(principal, id, browser), 63 { 64 state: SitePermissions.BLOCK, 65 scope: SitePermissions.SCOPE_TEMPORARY, 66 } 67 ); 68 69 ok( 70 blockedIcon.hasAttribute("showing"), 71 "blocked permission icon is shown" 72 ); 73 74 await new Promise(c => setTimeout(c, TIMEOUT_MS)); 75 76 Assert.deepEqual( 77 SitePermissions.getForPrincipal(principal, id, browser), 78 { 79 state: SitePermissions.UNKNOWN, 80 scope: SitePermissions.SCOPE_PERSISTENT, 81 } 82 ); 83 84 let popupshown = BrowserTestUtils.waitForEvent( 85 PopupNotifications.panel, 86 "popupshown" 87 ); 88 89 // Request a permission; 90 await BrowserTestUtils.synthesizeMouseAtCenter(`#${id}`, {}, browser); 91 92 await popupshown; 93 94 ok( 95 !blockedIcon.hasAttribute("showing"), 96 "blocked permission icon is not shown" 97 ); 98 99 let popuphidden = BrowserTestUtils.waitForEvent( 100 PopupNotifications.panel, 101 "popuphidden" 102 ); 103 104 let notification = PopupNotifications.panel.firstElementChild; 105 EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {}); 106 107 await popuphidden; 108 109 SitePermissions.removeFromPrincipal(principal, id, browser); 110 } 111 ); 112 } 113 }); 114 115 /** 116 * Test whether the identity UI shows the permission granted state. 117 * 118 * @param {boolean} state - true = Shows permission granted, false otherwise. 119 */ 120 async function testIdentityPermissionGrantedState(state) { 121 let hasAttribute; 122 let msg = `Identity permission box ${ 123 state ? "shows" : "does not show" 124 } granted permissions.`; 125 await TestUtils.waitForCondition(() => { 126 hasAttribute = 127 gPermissionPanel._identityPermissionBox.hasAttribute("hasPermissions"); 128 return hasAttribute == state; 129 }, msg); 130 is(hasAttribute, state, msg); 131 } 132 133 // Test that temporary permissions can have custom expiry time and the identity 134 // block is updated correctly on expiry. 135 add_task(async function testTempPermissionCustomExpiry() { 136 const TEST_ID = "geo"; 137 // Set a default expiry time which is lower than the custom one we'll set. 138 await SpecialPowers.pushPrefEnv({ 139 set: [["privacy.temporary_permission_expire_time_ms", EXPIRE_TIME_MS]], 140 }); 141 142 await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async browser => { 143 Assert.deepEqual( 144 SitePermissions.getForPrincipal(null, TEST_ID, browser), 145 { 146 state: SitePermissions.UNKNOWN, 147 scope: SitePermissions.SCOPE_PERSISTENT, 148 }, 149 "Permission not set initially" 150 ); 151 152 await testIdentityPermissionGrantedState(false); 153 154 // Set permission with custom expiry time. 155 SitePermissions.setForPrincipal( 156 null, 157 "geo", 158 SitePermissions.ALLOW, 159 SitePermissions.SCOPE_TEMPORARY, 160 browser, 161 EXPIRE_TIME_CUSTOM_MS 162 ); 163 164 await testIdentityPermissionGrantedState(true); 165 166 // We've set the permission, start the timer promise. 167 let timeout = new Promise(resolve => 168 setTimeout(resolve, TIMEOUT_CUSTOM_MS) 169 ); 170 171 Assert.deepEqual( 172 SitePermissions.getForPrincipal(null, TEST_ID, browser), 173 { 174 state: SitePermissions.ALLOW, 175 scope: SitePermissions.SCOPE_TEMPORARY, 176 }, 177 "We should see the temporary permission we just set." 178 ); 179 180 // Wait for half of the expiry time. 181 await new Promise(resolve => 182 setTimeout(resolve, EXPIRE_TIME_CUSTOM_MS / 2) 183 ); 184 Assert.deepEqual( 185 SitePermissions.getForPrincipal(null, TEST_ID, browser), 186 { 187 state: SitePermissions.ALLOW, 188 scope: SitePermissions.SCOPE_TEMPORARY, 189 }, 190 "Temporary permission should not have expired yet." 191 ); 192 193 // Wait until permission expiry. 194 await timeout; 195 196 // Identity permission section should have updated by now. It should do this 197 // without relying on side-effects of the SitePermissions getter. 198 await testIdentityPermissionGrantedState(false); 199 200 Assert.deepEqual( 201 SitePermissions.getForPrincipal(null, TEST_ID, browser), 202 { 203 state: SitePermissions.UNKNOWN, 204 scope: SitePermissions.SCOPE_PERSISTENT, 205 }, 206 "Permission should have expired" 207 ); 208 }); 209 });