service-worker-request-visibility.https.window.js (5918B)
1 // META: script=/resources/testdriver.js 2 // META: script=/resources/testdriver-vendor.js 3 // META: script=/common/utils.js 4 // META: script=resources/fledge-util.sub.js 5 // META: script=/common/subset-tests.js 6 // META: timeout=long 7 // META: variant=?1-last 8 9 "use strict"; 10 11 const SERVICE_WORKER_SCRIPT = "resources/service-worker-helper.js"; 12 13 // List of URL fragments that uniquely identify private requests. 14 // These are used to detect if a service worker has inadvertently 15 // accessed any of these private requests, which should not be visible to it. 16 const PRIVATE_REQUEST_FILE_NAMES = [ 17 'trusted-bidding-signals.py', 18 'update-url.py', // This requires another test, since it takes a while, 19 // see TODO file for more info. 20 'wasm-helper.py', 21 'bidding-logic.py', 22 'decision-logic.py', 23 'trusted-scoring-signals.py', 24 'trusted-bidding-signals.py', 25 'bidder_report', 26 'seller_report' 27 ]; 28 29 // List of URL fragments that uniquely identify public requests. 30 // These are used to verify that a service worker can correctly 31 // access and intercept these public requests as expected. 32 const PUBLIC_REQUEST_FILE_NAMES = [ 33 'direct-from-seller-signals.py', 34 ]; 35 36 const COMPLETE_TEST_URL = 'complete-test' 37 38 const CURRENT_SCOPE = "/fledge/tentative/" 39 40 async function registerAndActivateServiceWorker(test) { 41 // Unregister existing service worker (if any) 42 const existingRegistration = await navigator.serviceWorker.getRegistration(CURRENT_SCOPE); 43 if (existingRegistration) { 44 await existingRegistration.unregister(); 45 } 46 47 // Register new service worker 48 var newRegistration = await navigator.serviceWorker.register(`./${SERVICE_WORKER_SCRIPT}`, { scope: CURRENT_SCOPE }); 49 50 test.add_cleanup(async () => { 51 await newRegistration.unregister(); 52 }); 53 54 await navigator.serviceWorker.ready; 55 56 // Wait for the page to be controlled by the service worker. 57 // This is needed as navigator.serviceWorker.ready does not 58 // guarantee that the page is being controlled. 59 // See https://github.com/slightlyoff/ServiceWorker/issues/799. 60 await new Promise(resolve => { 61 if (navigator.serviceWorker.controller) { 62 resolve(); 63 } else { 64 navigator.serviceWorker.addEventListener('controllerchange', resolve); 65 } 66 }); 67 68 // Validate the service worker 69 if (!navigator.serviceWorker.controller.scriptURL.includes(SERVICE_WORKER_SCRIPT)) { 70 throw new Error('Failed to register service worker'); 71 } 72 } 73 74 async function setUpServiceWorkerAndGetBroadcastChannel(test) { 75 await registerAndActivateServiceWorker(test); 76 return new BroadcastChannel("requests-test"); 77 } 78 79 // Waits for a service worker to observe specific URL filenames via a BroadcastChannel. 80 // Resolves when all expected URL filenames are seen. 81 function awaitServiceWorkerURLPromise(broadcastChannel, expectedURLFileNames, 82 unexpectedURLFileNames) { 83 const seenURLs = new Set(); 84 return new Promise((resolve, reject) => { 85 broadcastChannel.addEventListener('message', (event) => { 86 var url = event.data.url; 87 var fileName = url.substring(url.lastIndexOf('/') + 1); 88 if (expectedURLFileNames.includes(fileName)) { 89 seenURLs.add(fileName); 90 } 91 if (unexpectedURLFileNames.includes(fileName)) { 92 reject(`unexpected result: ${fileName}`); 93 } 94 // Resolve when all `expectedURLs` have been seen. 95 if (seenURLs.size === expectedURLFileNames.length) { 96 resolve(); 97 } 98 }); 99 }); 100 } 101 102 // Tests that public requests are seen by the service worker. 103 // Specifically anything that contains: 104 // - 'direct-from-seller-signals.py' 105 106 // This test works by having the service worker send a message over 107 // the broadcastChannel, if it sees a request that contains any of 108 // the following strings above, it will send a 'passed' result and 109 // also change the variable 'finish_test', to true, so that guarantees 110 // that the request was seen before we complete the test. 111 subsetTest(promise_test, async test => { 112 const broadcastChannel = await setUpServiceWorkerAndGetBroadcastChannel(test); 113 let finishTest = awaitServiceWorkerURLPromise( 114 broadcastChannel, 115 PUBLIC_REQUEST_FILE_NAMES, 116 PRIVATE_REQUEST_FILE_NAMES); 117 118 await fetchDirectFromSellerSignals({ 'Buyer-Origin': window.location.origin }); 119 await finishTest; 120 }, "Make sure service workers do see public requests."); 121 122 // Tests that private requests are not seen by the service worker. 123 // Specifically anything that contains: 124 // - 'resources/trusted-bidding-signals.py' 125 // - 'resources/trusted-scoring-signals.py' 126 // - 'wasm-helper.py' 127 // - 'bidding-logic.py' 128 // - 'decision-logic.py' 129 // - 'seller_report' 130 // - 'bidder_report' 131 132 // This test works by having the service worker send a message 133 // over the broadcastChannel, if it sees a request that contains 134 // any of the following strings above, it will send a 'failed' 135 // result which will cause assert_false case to fail. 136 subsetTest(promise_test, async test => { 137 const uuid = generateUuid(test); 138 const broadcastChannel = await setUpServiceWorkerAndGetBroadcastChannel(test); 139 140 let finishTest = awaitServiceWorkerURLPromise( 141 broadcastChannel, 142 /*expectedURLFileNames=*/[COMPLETE_TEST_URL], 143 PRIVATE_REQUEST_FILE_NAMES) 144 145 let interestGroupOverrides = { 146 biddingWasmHelperURL: `${RESOURCE_PATH}wasm-helper.py`, 147 trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL, 148 trustedScoringSignalsURL: TRUSTED_SCORING_SIGNALS_URL, 149 }; 150 151 await joinInterestGroup(test, uuid, interestGroupOverrides); 152 await runBasicFledgeAuctionAndNavigate(test, uuid); 153 // By verifying that these requests are observed we can assume 154 // none of the other requests were seen by the service-worker. 155 await waitForObservedRequests( 156 uuid, 157 [createBidderReportURL(uuid), createSellerReportURL(uuid)]); 158 159 // We use this fetch to complete the test. 160 await fetch(COMPLETE_TEST_URL); 161 await finishTest; 162 }, "Make sure service workers do not see private requests");