test_permissions.js (9258B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const userAgentID = "2c43af06-ab6e-476a-adc4-16cbda54fb89"; 7 8 let db; 9 10 function run_test() { 11 do_get_profile(); 12 setPrefs({ 13 userAgentID, 14 }); 15 16 db = PushServiceWebSocket.newPushDB(); 17 registerCleanupFunction(() => { 18 return db.drop().then(_ => db.close()); 19 }); 20 21 run_next_test(); 22 } 23 24 let unregisterDefers = {}; 25 26 function promiseUnregister(keyID) { 27 return new Promise(r => (unregisterDefers[keyID] = r)); 28 } 29 30 function makePushPermission(url, capability) { 31 return { 32 QueryInterface: ChromeUtils.generateQI(["nsIPermission"]), 33 capability: Ci.nsIPermissionManager[capability], 34 expireTime: 0, 35 expireType: Ci.nsIPermissionManager.EXPIRE_NEVER, 36 principal: Services.scriptSecurityManager.createContentPrincipal( 37 Services.io.newURI(url), 38 {} 39 ), 40 type: "desktop-notification", 41 }; 42 } 43 44 function promiseObserverNotifications(topic, count) { 45 let notifiedScopes = []; 46 let subChangePromise = promiseObserverNotification(topic, (subject, data) => { 47 notifiedScopes.push(data); 48 return notifiedScopes.length == count; 49 }); 50 return subChangePromise.then(_ => notifiedScopes.sort()); 51 } 52 53 function promiseSubscriptionChanges(count) { 54 return promiseObserverNotifications( 55 PushServiceComponent.subscriptionChangeTopic, 56 count 57 ); 58 } 59 60 function promiseSubscriptionModifications(count) { 61 return promiseObserverNotifications( 62 PushServiceComponent.subscriptionModifiedTopic, 63 count 64 ); 65 } 66 67 function allExpired(...keyIDs) { 68 return Promise.all(keyIDs.map(keyID => db.getByKeyID(keyID))).then(records => 69 records.every(record => record.isExpired()) 70 ); 71 } 72 73 add_task(async function setUp() { 74 // Active registration; quota should be reset to 16. Since the quota isn't 75 // exposed to content, we shouldn't receive a subscription change event. 76 await putTestRecord(db, "active-allow", "https://example.info/page/1", 8); 77 78 // Expired registration; should be dropped. 79 await putTestRecord(db, "expired-allow", "https://example.info/page/2", 0); 80 81 // Active registration; should be expired when we change the permission 82 // to "deny". 83 await putTestRecord( 84 db, 85 "active-deny-changed", 86 "https://example.xyz/page/1", 87 16 88 ); 89 90 // Two active registrations for a visited site. These will expire when we 91 // add a "deny" permission. 92 await putTestRecord(db, "active-deny-added-1", "https://example.net/ham", 16); 93 await putTestRecord( 94 db, 95 "active-deny-added-2", 96 "https://example.net/green", 97 8 98 ); 99 100 // An already-expired registration for a visited site. We shouldn't send an 101 // `unregister` request for this one, but still receive an observer 102 // notification when we restore permissions. 103 await putTestRecord(db, "expired-deny-added", "https://example.net/eggs", 0); 104 105 // A registration that should not be affected by permission list changes 106 // because its quota is set to `Infinity`. 107 await putTestRecord(db, "never-expires", "app://chrome/only", Infinity); 108 109 // A registration that should be dropped when we clear the permission 110 // list. 111 await putTestRecord(db, "drop-on-clear", "https://example.edu/lonely", 16); 112 113 let handshakeDone; 114 let handshakePromise = new Promise(resolve => (handshakeDone = resolve)); 115 PushService.init({ 116 serverURI: "wss://push.example.org/", 117 db, 118 makeWebSocket(uri) { 119 return new MockWebSocket(uri, { 120 onHello() { 121 this.serverSendMsg( 122 JSON.stringify({ 123 messageType: "hello", 124 status: 200, 125 uaid: userAgentID, 126 }) 127 ); 128 handshakeDone(); 129 }, 130 onUnregister(request) { 131 let resolve = unregisterDefers[request.channelID]; 132 equal( 133 typeof resolve, 134 "function", 135 "Dropped unexpected channel ID " + request.channelID 136 ); 137 delete unregisterDefers[request.channelID]; 138 equal( 139 request.code, 140 202, 141 "Expected permission revoked unregister reason" 142 ); 143 resolve(); 144 this.serverSendMsg( 145 JSON.stringify({ 146 messageType: "unregister", 147 status: 200, 148 channelID: request.channelID, 149 }) 150 ); 151 }, 152 onACK() {}, 153 }); 154 }, 155 }); 156 await handshakePromise; 157 }); 158 159 add_task(async function test_permissions_allow_added() { 160 let subChangePromise = promiseSubscriptionChanges(1); 161 162 await PushService._onPermissionChange( 163 makePushPermission("https://example.info", "ALLOW_ACTION"), 164 "added" 165 ); 166 let notifiedScopes = await subChangePromise; 167 168 deepEqual( 169 notifiedScopes, 170 ["https://example.info/page/2"], 171 "Wrong scopes after adding allow" 172 ); 173 174 let record = await db.getByKeyID("active-allow"); 175 equal( 176 record.quota, 177 16, 178 "Should reset quota for active records after adding allow" 179 ); 180 181 record = await db.getByKeyID("expired-allow"); 182 ok(!record, "Should drop expired records after adding allow"); 183 }); 184 185 add_task(async function test_permissions_allow_deleted() { 186 let subModifiedPromise = promiseSubscriptionModifications(1); 187 188 let unregisterPromise = promiseUnregister("active-allow"); 189 190 await PushService._onPermissionChange( 191 makePushPermission("https://example.info", "ALLOW_ACTION"), 192 "deleted" 193 ); 194 195 await unregisterPromise; 196 197 let notifiedScopes = await subModifiedPromise; 198 deepEqual( 199 notifiedScopes, 200 ["https://example.info/page/1"], 201 "Wrong scopes modified after deleting allow" 202 ); 203 204 let record = await db.getByKeyID("active-allow"); 205 ok(record.isExpired(), "Should expire active record after deleting allow"); 206 }); 207 208 add_task(async function test_permissions_deny_added() { 209 let subModifiedPromise = promiseSubscriptionModifications(2); 210 211 let unregisterPromise = Promise.all([ 212 promiseUnregister("active-deny-added-1"), 213 promiseUnregister("active-deny-added-2"), 214 ]); 215 216 await PushService._onPermissionChange( 217 makePushPermission("https://example.net", "DENY_ACTION"), 218 "added" 219 ); 220 await unregisterPromise; 221 222 let notifiedScopes = await subModifiedPromise; 223 deepEqual( 224 notifiedScopes, 225 ["https://example.net/green", "https://example.net/ham"], 226 "Wrong scopes modified after adding deny" 227 ); 228 229 let isExpired = await allExpired("active-deny-added-1", "expired-deny-added"); 230 ok(isExpired, "Should expire all registrations after adding deny"); 231 }); 232 233 add_task(async function test_permissions_deny_deleted() { 234 await PushService._onPermissionChange( 235 makePushPermission("https://example.net", "DENY_ACTION"), 236 "deleted" 237 ); 238 239 let isExpired = await allExpired("active-deny-added-1", "expired-deny-added"); 240 ok(isExpired, "Should retain expired registrations after deleting deny"); 241 }); 242 243 add_task(async function test_permissions_allow_changed() { 244 let subChangePromise = promiseSubscriptionChanges(3); 245 246 await PushService._onPermissionChange( 247 makePushPermission("https://example.net", "ALLOW_ACTION"), 248 "changed" 249 ); 250 251 let notifiedScopes = await subChangePromise; 252 253 deepEqual( 254 notifiedScopes, 255 [ 256 "https://example.net/eggs", 257 "https://example.net/green", 258 "https://example.net/ham", 259 ], 260 "Wrong scopes after changing to allow" 261 ); 262 263 let droppedRecords = await Promise.all([ 264 db.getByKeyID("active-deny-added-1"), 265 db.getByKeyID("active-deny-added-2"), 266 db.getByKeyID("expired-deny-added"), 267 ]); 268 ok( 269 !droppedRecords.some(Boolean), 270 "Should drop all expired registrations after changing to allow" 271 ); 272 }); 273 274 add_task(async function test_permissions_deny_changed() { 275 let subModifiedPromise = promiseSubscriptionModifications(1); 276 277 let unregisterPromise = promiseUnregister("active-deny-changed"); 278 279 await PushService._onPermissionChange( 280 makePushPermission("https://example.xyz", "DENY_ACTION"), 281 "changed" 282 ); 283 284 await unregisterPromise; 285 286 let notifiedScopes = await subModifiedPromise; 287 deepEqual( 288 notifiedScopes, 289 ["https://example.xyz/page/1"], 290 "Wrong scopes modified after changing to deny" 291 ); 292 293 let record = await db.getByKeyID("active-deny-changed"); 294 ok(record.isExpired(), "Should expire active record after changing to deny"); 295 }); 296 297 add_task(async function test_permissions_clear() { 298 let subModifiedPromise = promiseSubscriptionModifications(3); 299 300 deepEqual( 301 await getAllKeyIDs(db), 302 ["active-allow", "active-deny-changed", "drop-on-clear", "never-expires"], 303 "Wrong records in database before clearing" 304 ); 305 306 let unregisterPromise = Promise.all([ 307 promiseUnregister("active-allow"), 308 promiseUnregister("active-deny-changed"), 309 promiseUnregister("drop-on-clear"), 310 ]); 311 312 await PushService._onPermissionChange(null, "cleared"); 313 314 await unregisterPromise; 315 316 let notifiedScopes = await subModifiedPromise; 317 deepEqual( 318 notifiedScopes, 319 [ 320 "https://example.edu/lonely", 321 "https://example.info/page/1", 322 "https://example.xyz/page/1", 323 ], 324 "Wrong scopes modified after clearing registrations" 325 ); 326 327 deepEqual( 328 await getAllKeyIDs(db), 329 ["never-expires"], 330 "Unrestricted registrations should not be dropped" 331 ); 332 });