/* import-globals-from storageAccessAPIHelpers.js */ PartitionedStorageHelper.runTest( "ServiceWorkers - disable partitioning", async (win3rdParty, win1stParty, allowed) => { // Partitioned serviceWorkers are disabled in third-party context. await win3rdParty.navigator.serviceWorker.register("empty.js").then( _ => { ok(allowed, "Success: ServiceWorker cannot be used!"); }, _ => { ok(!allowed, "Failed: ServiceWorker cannot be used!"); } ); await win1stParty.navigator.serviceWorker.register("empty.js").then( _ => { ok(true, "Success: ServiceWorker should be available!"); }, _ => { ok(false, "Failed: ServiceWorker should be available!"); } ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", false], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - enable partitioning", async (win3rdParty, win1stParty) => { // Partitioned serviceWorkers are enabled in third-party context. await win3rdParty.navigator.serviceWorker.register("empty.js").then( _ => { ok( true, "Success: ServiceWorker should be available in third parties." ); }, _ => { ok( false, "Failed: ServiceWorker should be available in third parties." ); } ); await win1stParty.navigator.serviceWorker.register("empty.js").then( _ => { ok(true, "Success: ServiceWorker should be available!"); }, _ => { ok(false, "Failed: ServiceWorker should be available!"); } ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - MatchAll", async (win3rdParty, win1stParty) => { if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker(win1stParty, "matchAll.js"); } let msgPromise = new Promise(resolve => { win1stParty.navigator.serviceWorker.addEventListener("message", msg => { resolve(msg.data); }); }); win1stParty.sw.postMessage(win3rdParty.location.href); let msg = await msgPromise; // The service worker will always be partitioned. So, the first party window // won't have control on the third-party window. is( false, msg, "We won't have the 3rd party window controlled regardless of StorageAccess." ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - Partition ScriptContext", async (win3rdParty, win1stParty) => { // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Set a script value to first-party service worker. let res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "SetScriptValue", value: "1stParty", } ); ok(res.result, "OK", "Set script value to first-party service worker."); // Set a script value to third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "SetScriptValue", value: "3rdParty", } ); ok(res.result, "OK", "Set script value to third-party service worker."); // Get and check script value from the first-party service worker. res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "GetScriptValue" } ); is( res.value, "1stParty", "The script value in first party window is correct" ); // Get and check script value from the third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "GetScriptValue" } ); is( res.value, "3rdParty", "The script value in third party window is correct" ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - Partition DOM Cache", async (win3rdParty, win1stParty) => { // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Set DOM cache to first-party service worker. let res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "SetCache", value: "1stParty", } ); ok(res.result, "OK", "Set cache to first-party service worker."); // Set DOM cache to third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "SetCache", value: "3rdParty", } ); ok(res.result, "OK", "Set cache to third-party service worker."); // Check DOM cache from the first-party service worker. res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "HasCache", value: "1stParty" } ); ok( res.value, "The '1stParty' cache storage should exist for the first-party window." ); res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "HasCache", value: "3rdParty" } ); ok( !res.value, "The '3rdParty' cache storage should not exist for the first-party window." ); // Check DOM cache from the third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "HasCache", value: "1stParty" } ); ok( !res.value, "The '1stParty' cache storage should not exist for the third-party window." ); res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "HasCache", value: "3rdParty" } ); ok( res.value, "The '3rdParty' cache storage should exist for the third-party window." ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - Partition IndexedDB", async (win3rdParty, win1stParty) => { // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Set indexedDB value to first-party service worker. let res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "SetIndexedDB", value: "1stParty", } ); ok(res.result, "OK", "Set cache to first-party service worker."); // Set indexedDB value to third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "SetIndexedDB", value: "3rdParty", } ); ok(res.result, "OK", "Set cache to third-party service worker."); // Get and check indexedDB value from the first-party service worker. res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "GetIndexedDB" } ); is( res.value, "1stParty", "The indexedDB value in first party window is correct" ); // Get and check indexedDB from the third-party service worker. res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "GetIndexedDB" } ); is( res.value, "3rdParty", "The indexedDB value in third party window is correct" ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - Partition Intercept", async (win3rdParty, win1stParty) => { // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Fetch a resource in the first-party window. await win1stParty.fetch("empty.js"); // Check that only the first-party service worker gets fetch event. let res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "GetFetchURL" } ); is( res.value, "https://not-tracking.example.com/browser/toolkit/components/antitracking/test/browser/empty.js", "The first-party service worker received fetch event." ); res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "GetFetchURL" } ); is( res.value, "", "The third-party service worker received no fetch event." ); // Fetch a resource in the third-party window. await win3rdParty.fetch("empty.js"); // Check if the fetch event only happens in third-party service worker. res = await sendAndWaitWorkerMessage( win1stParty.sw, win1stParty.navigator.serviceWorker, { type: "GetFetchURL" } ); is( res.value, "", "The first-party service worker received no fetch event." ); res = await sendAndWaitWorkerMessage( win3rdParty.sw, win3rdParty.navigator.serviceWorker, { type: "GetFetchURL" } ); is( res.value, "https://not-tracking.example.com/browser/toolkit/components/antitracking/test/browser/empty.js", "The third-party service worker received fetch event." ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); // Bug1743236 - Verify the content process won't crash if we create a dedicated // worker in a service worker controlled third-party page with Storage Access. PartitionedStorageHelper.runTest( "ServiceWorkers - Create Dedicated Worker", async (win3rdParty, win1stParty, allowed) => { // We only do this test when the storage access is granted. if (!allowed) { return; } // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Create a dedicated worker in first-party window. let firstPartyWorker = new win1stParty.Worker("dedicatedWorker.js"); // Post a message to the dedicated worker and wait until the message circles // back. await new Promise(resolve => { firstPartyWorker.addEventListener("message", msg => { if (msg.data == "1stParty") { resolve(); } }); firstPartyWorker.postMessage("1stParty"); }); // Create a dedicated worker in third-party window. let thirdPartyWorker = new win3rdParty.Worker("dedicatedWorker.js"); // Post a message to the dedicated worker and wait until the message circles // back. await new Promise(resolve => { thirdPartyWorker.addEventListener("message", msg => { if (msg.data == "3rdParty") { resolve(); } }); thirdPartyWorker.postMessage("3rdParty"); }); firstPartyWorker.terminate(); thirdPartyWorker.terminate(); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); // Bug1768193 - Verify the parent process won't crash if we create a shared // worker in a service worker controlled third-party page with Storage Access. PartitionedStorageHelper.runTest( "ServiceWorkers - Create Shared Worker", async (win3rdParty, win1stParty, allowed) => { // We only do this test when the storage access is granted. if (!allowed) { return; } // Register service worker for the first-party window. if (!win1stParty.sw) { win1stParty.sw = await registerServiceWorker( win1stParty, "serviceWorker.js" ); } // Register service worker for the third-party window. if (!win3rdParty.sw) { win3rdParty.sw = await registerServiceWorker( win3rdParty, "serviceWorker.js" ); } // Create a shared worker in third-party window. let thirdPartyWorker = new win3rdParty.SharedWorker("sharedWorker.js"); // Post a message to the dedicated worker and wait until the message circles // back. await new Promise(resolve => { thirdPartyWorker.port.onmessage = () => { resolve(); }; thirdPartyWorker.onerror = _ => { ok(false, "We should not be here"); resolve(); }; thirdPartyWorker.port.postMessage("count"); }); thirdPartyWorker.port.postMessage("close"); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ] ); PartitionedStorageHelper.runTest( "ServiceWorkers - Private Browsing with partitioning disabled", async (win3rdParty, win1stParty) => { // Partitioned serviceWorkers are disabled in third-party context. ok( !win3rdParty.navigator.serviceWorker, "ServiceWorker should not be available" ); ok( !win1stParty.navigator.serviceWorker, "ServiceWorker should not be available" ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", false], ], { runInPrivateWindow: true, } ); PartitionedStorageHelper.runTest( "ServiceWorkers - Private Browsing with partitioning enabled", async (win3rdParty, win1stParty) => { // Partitioned serviceWorkers are disabled in third-party context. ok( !win3rdParty.navigator.serviceWorker, "ServiceWorker should not be available" ); ok( !win1stParty.navigator.serviceWorker, "ServiceWorker should not be available" ); }, async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () => resolve() ); }); }, [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["privacy.partition.serviceWorkers", true], ], { runInPrivateWindow: true, } );