join-leave-ad-interest-group-in-fenced-frame.https.window.js (14719B)
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-4 8 // META: variant=?5-8 9 // META: variant=?9-last 10 11 "use strict"; 12 13 // These are separate from the other join-leave tests because these all create 14 // and navigate fenced frames, which is much slower than just joining/leaving 15 // interest groups, and running the occasional auction. Most tests use a 16 // buyer with an origin of OTHER_ORIGIN1, so it has a distinct origin from the 17 // seller and publisher. 18 19 // Creates a tracker URL that's requested when a call succeeds in a fenced 20 // frame. 21 function createSuccessURL(uuid, origin = document.location.origin) { 22 return createTrackerURL(origin, uuid, "track_get", "success"); 23 } 24 25 // Creates a tracker URL that's requested when a call fails in a fenced frame, with 26 // the expected exception. 27 function createExceptionURL(uuid, origin = document.location.origin) { 28 return createTrackerURL(origin, uuid, "track_get", "exception"); 29 } 30 31 // Creates a tracker URL that's requested when joinAdInterestGroup() or 32 // leaveAdInterestGroup() fails with an exception other than the one that's 33 // expected. 34 function createBadExceptionURL(uuid, origin = document.location.origin) { 35 return createTrackerURL(origin, uuid, "track_get", "bad_exception"); 36 } 37 38 // Creates render URL that calls "navigator.leaveAdInterestGroup()" when 39 // loaded, with no arguments. It then fetches a URL depending on whether it 40 // threw an exception. No exception should ever be thrown when this is run 41 // in an ad URL, so only fetch the "bad exception" URL on error. 42 function createNoArgsTryLeaveRenderURL(uuid, origin = document.location.origin) { 43 return createRenderURL( 44 uuid, 45 `async function TryLeave() { 46 try { 47 await navigator.leaveAdInterestGroup(); 48 await fetch("${createSuccessURL(uuid, origin)}"); 49 } catch (e) { 50 await fetch("${createBadExceptionURL(uuid, origin)}"); 51 } 52 } 53 54 TryLeave();`, 55 /*signalsParams=*/null, 56 origin); 57 } 58 59 subsetTest(promise_test, async test => { 60 const uuid = generateUuid(test); 61 62 // Interest group that an ad fenced frame attempts to join. The join should 63 // fail. 64 let interestGroupJoinedInFrame = createInterestGroupForOrigin( 65 uuid, document.location.origin, {name: 'group2'}); 66 67 // Create a render URL that tries to join "interestGroupJoinedInFrame". 68 const renderURL = createRenderURL( 69 uuid, 70 `async function TryJoin() { 71 try { 72 await navigator.joinAdInterestGroup( 73 ${JSON.stringify(interestGroupJoinedInFrame)}); 74 await fetch("${createSuccessURL(uuid)}"); 75 } catch (e) { 76 if (e instanceof DOMException && e.name === "NotAllowedError") { 77 await fetch("${createExceptionURL(uuid)}"); 78 } else { 79 await fetch("${createBadExceptionURL(uuid)}"); 80 } 81 } 82 } 83 84 TryJoin();`); 85 86 await joinInterestGroup(test, uuid, {ads: [{ renderURL: renderURL}]}); 87 88 await runBasicFledgeAuctionAndNavigate(test, uuid); 89 90 // This should wait until the leave call has thrown an exception. 91 await waitForObservedRequests( 92 uuid, 93 [createBidderReportURL(uuid), createSellerReportURL(uuid), createExceptionURL(uuid)]); 94 95 // Leave the initial interest group. 96 await leaveInterestGroup(); 97 98 // Check the interest group was not successfully joined in the fenced frame 99 // by running an auction, to make sure the thrown exception accurately 100 // indicates the group wasn't joined. 101 await runBasicFledgeTestExpectingNoWinner(test, uuid); 102 }, 'joinAdInterestGroup() in ad fenced frame.'); 103 104 subsetTest(promise_test, async test => { 105 const uuid = generateUuid(test); 106 107 // Create a render URL that tries to leave the default test interest group by 108 // name. Even a though a render URL can leave its own interest group by using 109 // the 0-argument version of leaveAdInterestGroup(), it can't leave its own 110 // interest group by using the 1-argument version, so this should fail. 111 const renderURL = createRenderURL( 112 uuid, 113 `async function TryLeave() { 114 try { 115 await navigator.leaveAdInterestGroup( 116 {owner: "${window.location.origin}", name: "${DEFAULT_INTEREST_GROUP_NAME}"}); 117 await fetch("${createSuccessURL(uuid)}"); 118 } catch (e) { 119 if (e instanceof DOMException && e.name === "NotAllowedError") { 120 await fetch("${createExceptionURL(uuid)}"); 121 } else { 122 await fetch("${createBadExceptionURL(uuid)}"); 123 } 124 } 125 } 126 127 TryLeave();`); 128 129 await joinInterestGroup( 130 test, uuid, 131 {ads: [{ renderURL: renderURL}]}); 132 133 await runBasicFledgeAuctionAndNavigate(test, uuid); 134 135 // This should wait until the leave call has thrown an exception. 136 await waitForObservedRequests( 137 uuid, 138 [createBidderReportURL(uuid), createSellerReportURL(uuid), createExceptionURL(uuid)]); 139 140 // Check the interest group was not left. 141 await runBasicFledgeTestExpectingWinner(test, uuid); 142 }, 'leaveAdInterestGroup() in ad fenced frame, specify an interest group.'); 143 144 subsetTest(promise_test, async test => { 145 const uuid = generateUuid(test); 146 147 const bidder_origin = OTHER_ORIGIN1; 148 const render_url_origin = window.location.origin; 149 150 await joinCrossOriginInterestGroup( 151 test, uuid, bidder_origin, 152 {ads: [{ renderURL: createNoArgsTryLeaveRenderURL(uuid, render_url_origin) }]}); 153 154 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 155 156 // Leaving the interest group should claim to succeed, to avoid leaking 157 // whether or not the buyer was same-origin or to the fenced frame. 158 await waitForObservedRequests( 159 uuid, 160 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 161 createSuccessURL(uuid, render_url_origin)]); 162 163 // Check the interest group was not actually left. 164 await runBasicFledgeTestExpectingWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 165 }, 'leaveAdInterestGroup() in non-buyer origin ad fenced frame, no parameters.'); 166 167 subsetTest(promise_test, async test => { 168 const uuid = generateUuid(test); 169 170 const bidder_origin = OTHER_ORIGIN1; 171 const render_url_origin = OTHER_ORIGIN1; 172 173 // Use a different origin for the buyer, to make sure that's the origin 174 // that matters. 175 await joinCrossOriginInterestGroup( 176 test, uuid, bidder_origin, 177 {ads: [{ renderURL: createNoArgsTryLeaveRenderURL(uuid, render_url_origin) }]}); 178 179 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 180 181 // This should wait until the leave call has completed. 182 await waitForObservedRequests( 183 uuid, 184 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 185 createSuccessURL(uuid, render_url_origin)]); 186 187 // Check the interest group was actually left. 188 await runBasicFledgeTestExpectingNoWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 189 }, 'leaveAdInterestGroup() in buyer origin ad fenced frame, no parameters.'); 190 191 subsetTest(promise_test, async test => { 192 const uuid = generateUuid(test); 193 194 const bidder_origin = OTHER_ORIGIN1; 195 const render_url_origin = OTHER_ORIGIN1; 196 const iframe_origin = OTHER_ORIGIN1; 197 198 // Create a render URL which, in an iframe, loads the common "try leave" 199 // render URL from the buyer's origin (which isn't technically being used as 200 // a render URL, in this case). 201 const renderURL = createRenderURL( 202 uuid, 203 `let iframe = document.createElement("iframe"); 204 iframe.permissions = "join-ad-interest-group"; 205 iframe.src = "${createNoArgsTryLeaveRenderURL(uuid, iframe_origin)}"; 206 document.body.appendChild(iframe);`, 207 /*signalsParams=*/null, 208 render_url_origin); 209 210 await joinCrossOriginInterestGroup( 211 test, uuid, bidder_origin, 212 {ads: [{ renderURL: renderURL }]}); 213 214 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 215 216 // This should wait until the leave call has completed. 217 await waitForObservedRequests( 218 uuid, 219 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 220 createSuccessURL(uuid, iframe_origin)]); 221 222 // Check the interest group was actually left. 223 await runBasicFledgeTestExpectingNoWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 224 }, 'leaveAdInterestGroup() in same-origin iframe inside buyer origin ad fenced frame, no parameters.'); 225 226 subsetTest(promise_test, async test => { 227 const uuid = generateUuid(test); 228 229 const bidder_origin = OTHER_ORIGIN1; 230 const render_url_origin = OTHER_ORIGIN1; 231 const iframe_origin = document.location.origin; 232 233 // Create a render URL which, in an iframe, loads the common "try leave" 234 // render URL from an origin other than the buyer's origin. 235 const renderURL = createRenderURL( 236 uuid, 237 `let iframe = document.createElement("iframe"); 238 iframe.permissions = "join-ad-interest-group"; 239 iframe.src = "${createNoArgsTryLeaveRenderURL(uuid, iframe_origin)}"; 240 document.body.appendChild(iframe);`, 241 /*signalsParams=*/null, 242 render_url_origin); 243 244 await joinCrossOriginInterestGroup( 245 test, uuid, bidder_origin, 246 {ads: [{ renderURL: renderURL }]}); 247 248 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 249 250 // Leaving the interest group should claim to succeed, to avoid leaking 251 // whether or not the buyer was same-origin or to the iframe. 252 await waitForObservedRequests( 253 uuid, 254 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 255 createSuccessURL(uuid, iframe_origin)]); 256 257 // Check the interest group was not actually left. 258 await runBasicFledgeTestExpectingWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 259 }, 'leaveAdInterestGroup() in cross-origin iframe inside buyer origin ad fenced frame, no parameters.'); 260 261 subsetTest(promise_test, async test => { 262 const uuid = generateUuid(test); 263 264 const bidder_origin = OTHER_ORIGIN1; 265 const render_url_origin = document.location.origin; 266 const iframe_origin = document.location.origin; 267 268 // Create a render URL which, in an iframe, loads the common "try leave" 269 // render URL from an origin other than the buyer's origin (which isn't 270 // technically being used as a render URL, in this case). 271 const renderURL = createRenderURL( 272 uuid, 273 `let iframe = document.createElement("iframe"); 274 iframe.permissions = "join-ad-interest-group"; 275 iframe.src = "${createNoArgsTryLeaveRenderURL(uuid, iframe_origin)}"; 276 document.body.appendChild(iframe);`, 277 /*signalsParams=*/null, 278 render_url_origin); 279 280 await joinCrossOriginInterestGroup( 281 test, uuid, bidder_origin, 282 {ads: [{ renderURL: renderURL }]}); 283 284 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 285 286 // Leaving the interest group should claim to succeed, to avoid leaking 287 // whether or not the buyer was same-origin or to the fenced frame. 288 await waitForObservedRequests( 289 uuid, 290 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 291 createSuccessURL(uuid, iframe_origin)]); 292 293 // Check the interest group was not actually left. 294 await runBasicFledgeTestExpectingWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 295 }, 'leaveAdInterestGroup() in same-origin iframe inside non-buyer origin ad fenced frame, no parameters.'); 296 297 subsetTest(promise_test, async test => { 298 const uuid = generateUuid(test); 299 300 const bidder_origin = OTHER_ORIGIN1; 301 const render_url_origin = document.location.origin; 302 const iframe_origin = OTHER_ORIGIN1; 303 304 // Create a render URL which, in an iframe, loads the common "try leave" 305 // render URL from the buyer's origin (which isn't technically being used as 306 // a render URL, in this case). 307 const renderURL = createRenderURL( 308 uuid, 309 `let iframe = document.createElement("iframe"); 310 iframe.permissions = "join-ad-interest-group"; 311 iframe.src = "${createNoArgsTryLeaveRenderURL(uuid, iframe_origin)}"; 312 document.body.appendChild(iframe);`, 313 /*signalsParams=*/null, 314 render_url_origin); 315 316 await joinCrossOriginInterestGroup( 317 test, uuid, bidder_origin, 318 {ads: [{ renderURL: renderURL }]}); 319 320 await runBasicFledgeAuctionAndNavigate(test, uuid, {interestGroupBuyers : [bidder_origin]}); 321 // Leaving the interest group should succeed. 322 await waitForObservedRequests( 323 uuid, 324 [ createBidderReportURL(uuid), createSellerReportURL(uuid), 325 createSuccessURL(uuid, iframe_origin)]); 326 327 // Check the interest group was left. 328 await runBasicFledgeTestExpectingNoWinner(test, uuid, {interestGroupBuyers : [bidder_origin]}); 329 }, 'leaveAdInterestGroup() in cross-origin buyer iframe inside non-buyer origin ad fenced frame, no parameters.'); 330 331 subsetTest(promise_test, async test => { 332 const uuid = generateUuid(test); 333 334 // Render URL that loads the first ad component in a nested fenced frame. 335 let loadFirstComponentAdURL = 336 createRenderURL( 337 uuid, 338 `let fencedFrame = document.createElement("fencedframe"); 339 fencedFrame.mode = "opaque-ads"; 340 fencedFrame.config = window.fence.getNestedConfigs()[0]; 341 document.body.appendChild(fencedFrame);`, 342 /*signalsParams=*/null, 343 OTHER_ORIGIN1); 344 345 await joinInterestGroup( 346 test, uuid, 347 // Interest group that makes a bid with a component ad. The render URL 348 // will open the component ad in a fenced frame, and the component ad 349 // URL is the common URL that tries to leave the ad's current interest 350 // group, reporting the result to a tracker URL. 351 { biddingLogicURL: createBiddingScriptURL( 352 { generateBid: `return { 353 bid: 1, 354 render: interestGroup.ads[0].renderURL, 355 adComponents: [interestGroup.adComponents[0].renderURL] 356 };` }), 357 ads: [{ renderURL: loadFirstComponentAdURL }], 358 adComponents: [{ renderURL: createNoArgsTryLeaveRenderURL(uuid) }]}); 359 360 await runBasicFledgeAuctionAndNavigate(test, uuid); 361 362 // Leaving the interest group should claim to succeed, to avoid leaking 363 // whether or not the buyer was same-origin or to the fenced frame. 364 await waitForObservedRequests( 365 uuid, 366 [createSellerReportURL(uuid), createSuccessURL(uuid)]); 367 368 // Check the interest group was left. 369 await runBasicFledgeTestExpectingNoWinner(test, uuid); 370 }, 'leaveAdInterestGroup() in component ad fenced frame, no parameters.');