Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file contains the tests for detecting extension's ad injection in | 5 // This file contains the tests for detecting extension's ad injection in |
| 6 // Chrome. This contains many different, independent tests, but it is all run | 6 // Chrome. This contains many different, independent tests, but it is all run |
| 7 // as a "single" browser test. The reason for this is that we want to do many | 7 // as a "single" browser test. The reason for this is that we want to do many |
| 8 // short tests for ad injection, and the set-up/tear-down time for a browsertest | 8 // short tests for ad injection, and the set-up/tear-down time for a browsertest |
| 9 // implementation of each would be prohibitive. | 9 // implementation of each would be prohibitive. |
| 10 // See also chrome/browser/extensions/activity_log/ad_injection_browsertest.cc | 10 // See also chrome/browser/extensions/activity_log/ad_injection_browsertest.cc |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 // 10 | 2 | 57.945s | 26.580s | 4.950s | | 24 // 10 | 2 | 57.945s | 26.580s | 4.950s | |
| 25 // 100 | 2 | N/A | N/A | N/A | | 25 // 100 | 2 | N/A | N/A | N/A | |
| 26 // ---------------------------------------------------------- | 26 // ---------------------------------------------------------- |
| 27 | 27 |
| 28 // This html block is just designed to be a massive playground for ad injectors, | 28 // This html block is just designed to be a massive playground for ad injectors, |
| 29 // where they can let loose and have fun. | 29 // where they can let loose and have fun. |
| 30 // We use this to populate our page at the start of every test. | 30 // We use this to populate our page at the start of every test. |
| 31 var kBodyHtml = | 31 var kBodyHtml = |
| 32 '<iframe id="ad-iframe" src="http://www.known-ads.adnetwork"></iframe>' + | 32 '<iframe id="ad-iframe" src="http://www.known-ads.adnetwork"></iframe>' + |
| 33 '<iframe id="non-ad-iframe" src="http://www.not-ads.adnetwork"></iframe>' + | 33 '<iframe id="non-ad-iframe" src="http://www.not-ads.adnetwork"></iframe>' + |
| 34 '<embed id="ad-embed" src="http://www.known-ads.adnetwork"><embed>' + | |
| 35 '<embed id="non-ad-embed" src="http://www.not-ads.adnetwork"><embed>' + | |
| 36 '<a id="ad-anchor" href="http://www.known-ads.adnetwork"></a>' + | 34 '<a id="ad-anchor" href="http://www.known-ads.adnetwork"></a>' + |
| 37 '<a id="non-ad-anchor" href="http://www.not-ads.adnetwork"></a>' + | 35 '<a id="non-ad-anchor" href="http://www.not-ads.adnetwork"></a>' + |
| 38 '<div id="empty-div"></div>'; | 36 '<div id="empty-div"></div>'; |
| 39 | 37 |
| 40 /** | 38 /** |
| 41 * The AdInjectorTest infrastructure. Basically, this allows the test to follow | 39 * The AdInjectorTest infrastructure. Basically, this allows the test to follow |
| 42 * a simple iteration cycle: | 40 * a simple iteration cycle: |
| 43 * - Signal the C++ test that we're going to do page setup, and we shouldn't | 41 * - Signal the C++ test that we're going to do page setup, and we shouldn't |
| 44 * record any ad-injector events (as some of the page setup could qualify). | 42 * record any ad-injector events (as some of the page setup could qualify). |
| 45 * - Do the page setup, which involves creating a 'playground' for ad injectors | 43 * - Do the page setup, which involves creating a 'playground' for ad injectors |
| 46 * of iframes, embeds, etc. See also ad_injectors.html. We do this set up for | 44 * of iframes, etc. See also ad_injectors.html. We do this set up for each |
| 47 * each test, so that none of the tests conflicts with each other. | 45 * test, so that none of the tests conflicts with each other. |
| 48 * - Signal that we are done with page setup, and should start recording events. | 46 * - Signal that we are done with page setup, and should start recording events. |
| 49 * - Run the next test. | 47 * - Run the next test. |
| 50 * - Signal that the test is done, and we should check for the result. | 48 * - Signal that the test is done, and we should check for the result. |
| 51 * | 49 * |
| 52 * This cycle repeats, and should be done synchronously so that we don't end up | 50 * This cycle repeats, and should be done synchronously so that we don't end up |
| 53 * recording events which we shouldn't, and can attribute each event to its | 51 * recording events which we shouldn't, and can attribute each event to its |
| 54 * cause. | 52 * cause. |
| 55 * @constructor | 53 * @constructor |
| 56 */ | 54 */ |
| 57 function AdInjectorTest(functions) { | 55 function AdInjectorTest(functions) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 var kIframeAdTemplate = document.createElement('iframe'); | 171 var kIframeAdTemplate = document.createElement('iframe'); |
| 174 kIframeAdTemplate.src = kAdNetwork; | 172 kIframeAdTemplate.src = kAdNetwork; |
| 175 | 173 |
| 176 /** | 174 /** |
| 177 * @return An iframe element which will count as ad injection in the tests. | 175 * @return An iframe element which will count as ad injection in the tests. |
| 178 */ | 176 */ |
| 179 var getIframeAd = function() { | 177 var getIframeAd = function() { |
| 180 return kIframeAdTemplate.cloneNode(true); | 178 return kIframeAdTemplate.cloneNode(true); |
| 181 }; | 179 }; |
| 182 | 180 |
| 183 // Creates an embed ad, like so: | |
| 184 // <embed src="http://www.known-ads.adnetwork"></embed> | |
| 185 var kEmbedAdTemplate = document.createElement('embed'); | |
| 186 kEmbedAdTemplate.src = kAdNetwork; | |
| 187 | |
| 188 /** | |
| 189 * @return An embed element which will count as ad injection in the tests. | |
| 190 */ | |
| 191 var getEmbedAd = function() { | |
| 192 return kEmbedAdTemplate.cloneNode(true); | |
| 193 }; | |
| 194 | |
| 195 // Creates an anchor ad, like so: | 181 // Creates an anchor ad, like so: |
| 196 // <a href="http://www.known-ads.adnetwork"></a> | 182 // <a href="http://www.known-ads.adnetwork"></a> |
| 197 var kAnchorAdTemplate = document.createElement('a'); | 183 var kAnchorAdTemplate = document.createElement('a'); |
| 198 kAnchorAdTemplate.href = kAdNetwork; | 184 kAnchorAdTemplate.href = kAdNetwork; |
| 199 | 185 |
| 200 /** | 186 /** |
| 201 * @return An anchor ('a') element which will count as ad injection in the | 187 * @return An anchor ('a') element which will count as ad injection in the |
| 202 * tests. | 188 * tests. |
| 203 */ | 189 */ |
| 204 var getAnchorAd = function() { | 190 var getAnchorAd = function() { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 234 * All test functions must be synchronous. | 220 * All test functions must be synchronous. |
| 235 * @type {Array.<Function>} | 221 * @type {Array.<Function>} |
| 236 */ | 222 */ |
| 237 var functions = []; | 223 var functions = []; |
| 238 | 224 |
| 239 // Add a bunch of elements, but nothing that looks like ad injection (no | 225 // Add a bunch of elements, but nothing that looks like ad injection (no |
| 240 // elements with an external source, no modifying existing sources). | 226 // elements with an external source, no modifying existing sources). |
| 241 functions.push(function NoAdInjection() { | 227 functions.push(function NoAdInjection() { |
| 242 var div = document.createElement('div'); | 228 var div = document.createElement('div'); |
| 243 var iframe = document.createElement('iframe'); | 229 var iframe = document.createElement('iframe'); |
| 244 var embed = document.createElement('embed'); | |
| 245 var anchor = document.createElement('anchor'); | 230 var anchor = document.createElement('anchor'); |
| 246 var span = document.createElement('span'); | 231 var span = document.createElement('span'); |
| 247 span.textContent = 'Hello, world'; | 232 span.textContent = 'Hello, world'; |
| 248 div.appendChild(iframe); | 233 div.appendChild(iframe); |
| 249 div.appendChild(embed); | |
| 250 div.appendChild(anchor); | 234 div.appendChild(anchor); |
| 251 div.appendChild(span); | 235 div.appendChild(span); |
| 252 document.body.appendChild(div); | 236 document.body.appendChild(div); |
| 253 return NO_AD_INJECTION; | 237 return NO_AD_INJECTION; |
| 254 }); | 238 }); |
| 255 | 239 |
| 256 // Add a new iframe with an AdNetwork source by creating the element and | 240 // Add a new iframe with an AdNetwork source by creating the element and |
| 257 // appending it. | 241 // appending it. |
| 258 functions.push(function NewIframeAdNetwork() { | 242 functions.push(function NewIframeAdNetwork() { |
| 259 document.body.appendChild(getIframeAd()); | 243 document.body.appendChild(getIframeAd()); |
| 260 return INJECTION_NEW_AD; | 244 return INJECTION_NEW_AD; |
| 261 }); | 245 }); |
| 262 | 246 |
| 263 // Add a new iframe which does not serve ads. We should not record anything. | 247 // Add a new iframe which does not serve ads. We should not record anything. |
| 264 functions.push(function NewIframeLikelyAdNetwork() { | 248 functions.push(function NewIframeLikelyAdNetwork() { |
| 265 var frame = document.createElement('iframe'); | 249 var frame = document.createElement('iframe'); |
| 266 document.body.appendChild(frame).src = kMaybeAdNetwork; | 250 document.body.appendChild(frame).src = kMaybeAdNetwork; |
| 267 return INJECTION_LIKELY_NEW_AD; | 251 return INJECTION_LIKELY_NEW_AD; |
| 268 }); | 252 }); |
| 269 | 253 |
| 270 // Modify an iframe which is currently in the DOM, switching the src to an | 254 // Modify an iframe which is currently in the DOM, switching the src to an |
| 271 // ad network. | 255 // ad network. |
| 272 functions.push(function ModifyExistingIframeToAdNetwork() { | 256 functions.push(function ModifyExistingIframeToAdNetwork1() { |
| 273 var frame = $('non-ad-iframe'); | 257 var frame = $('non-ad-iframe'); |
| 274 frame.src = kAdNetwork; | 258 frame.src = kAdNetwork; |
| 275 return INJECTION_NEW_AD; | 259 return INJECTION_NEW_AD; |
| 276 }); | 260 }); |
| 277 | 261 |
| 278 // Add a new embed element which serves ads. | 262 functions.push(function ModifyExistingIframeToAdNetwork2() { |
| 279 functions.push(function NewEmbedAdNetwork() { | 263 var frame = $('non-ad-iframe'); |
| 280 document.body.appendChild(getEmbedAd()); | 264 frame.setAttribute('src', kAdNetwork); |
| 281 return INJECTION_NEW_AD; | 265 return INJECTION_NEW_AD; |
| 282 }); | 266 }); |
| 283 | 267 |
| 284 // Add a new embed element which does not serve ads. We should not record | |
| 285 // anything. | |
| 286 functions.push(function NewEmbedLikelyAdNetwork() { | |
| 287 var embed = document.createElement('embed'); | |
| 288 document.body.appendChild(embed).src = kMaybeAdNetwork; | |
| 289 return INJECTION_LIKELY_NEW_AD; | |
| 290 }); | |
| 291 | |
| 292 // Modify an embed which is currently in the DOM, switching the src to an | |
| 293 // ad network. | |
| 294 functions.push(function ModifyExistingEmbedToAdNetwork() { | |
| 295 var embed = $('non-ad-embed'); | |
| 296 embed.src = kAdNetwork; | |
| 297 return INJECTION_NEW_AD; | |
| 298 }); | |
| 299 | |
| 300 // Add a new anchor element which serves ads. | 268 // Add a new anchor element which serves ads. |
| 301 functions.push(function NewAnchorAd() { | 269 functions.push(function NewAnchorAd() { |
| 302 document.body.appendChild(getAnchorAd()); | 270 document.body.appendChild(getAnchorAd()); |
| 303 return INJECTION_NEW_AD; | 271 return INJECTION_NEW_AD; |
| 304 }); | 272 }); |
| 305 | 273 |
| 306 functions.push(function NewAnchorLikelyAd() { | 274 functions.push(function NewAnchorLikelyAd() { |
| 307 var anchor = document.createElement('a'); | 275 var anchor = document.createElement('a'); |
| 308 document.body.appendChild(anchor).href = kMaybeAdNetwork; | 276 document.body.appendChild(anchor).href = kMaybeAdNetwork; |
| 309 return INJECTION_LIKELY_NEW_AD; | 277 return INJECTION_LIKELY_NEW_AD; |
| 310 }); | 278 }); |
| 311 | 279 |
| 312 // Test that an extension adding an element is not considered likely ad | 280 // Test that an extension adding an element is not considered likely ad |
| 313 // injection if the element has a local resource. | 281 // injection if the element has a local resource. |
| 314 functions.push(function LocalResourceNotConsideredAd() { | 282 functions.push(function LocalResourceNotConsideredAd() { |
| 315 var anchor = document.createElement('a'); | 283 var anchor = document.createElement('a'); |
| 316 document.body.appendChild(anchor).href = chrome.extension.getURL('foo.html'); | 284 document.body.appendChild(anchor).href = chrome.extension.getURL('foo.html'); |
| 317 return NO_AD_INJECTION; | 285 return NO_AD_INJECTION; |
| 318 }); | 286 }); |
| 319 | 287 |
| 320 // Test that an extension adding an element with the same host as the current | 288 // Test that an extension adding an element with the same host as the current |
| 321 // page is not considered ad injection. | 289 // page is not considered ad injection. |
| 322 functions.push(function SamePageUrlNotConsideredAd() { | 290 functions.push(function SamePageUrlNotConsideredAd() { |
| 323 var anchor = document.createElement('a'); | 291 var anchor = document.createElement('a'); |
| 324 // This source is something like 'http://127.0.0.1:49725/foo.html'. | 292 // This source is something like 'http://127.0.0.1:49725/foo.html'. |
| 325 document.body.appendChild(anchor).href = document.URL + 'foo.html'; | 293 document.body.appendChild(anchor).href = document.URL + 'foo.html'; |
| 326 return NO_AD_INJECTION; | 294 return NO_AD_INJECTION; |
| 327 }); | 295 }); |
| 328 | 296 |
| 329 | 297 functions.push(function ModifyExistingAnchorToAdNetwork1() { |
| 330 functions.push(function ModifyExistingAnchorToAdNetwork() { | |
| 331 var anchor = $('non-ad-anchor'); | 298 var anchor = $('non-ad-anchor'); |
| 332 anchor.href = kAdNetwork; | 299 anchor.href = kAdNetwork; |
| 333 return INJECTION_NEW_AD; | 300 return INJECTION_NEW_AD; |
| 334 }); | 301 }); |
| 335 | 302 |
| 303 functions.push(function ModifyExistingAnchorToAdNetwork2() { | |
| 304 var anchor = $('non-ad-anchor'); | |
| 305 anchor.setAttribute('href', kAdNetwork); | |
| 306 return INJECTION_NEW_AD; | |
| 307 }); | |
| 308 | |
| 336 // Add a new element which has a nested ad, to ensure we do a deep check of | 309 // Add a new element which has a nested ad, to ensure we do a deep check of |
| 337 // elements appended to the dom. | 310 // elements appended to the dom. |
| 338 functions.push(function NewNestedAd() { | 311 functions.push(function NewNestedAd() { |
| 339 document.body.appendChild(getNestedAd()); | 312 document.body.appendChild(getNestedAd()); |
| 340 return INJECTION_NEW_AD; | 313 return INJECTION_NEW_AD; |
| 341 }); | 314 }); |
| 342 | 315 |
| 343 // Switch an existing embed ad to a new ad network. | |
| 344 functions.push(function ReplaceEmbedAd() { | |
| 345 $('ad-embed').src = kAdNetwork2; | |
| 346 return INJECTION_REPLACED_AD; | |
| 347 }); | |
| 348 | |
| 349 // Switch an existing iframe ad to a new ad network. | 316 // Switch an existing iframe ad to a new ad network. |
| 350 functions.push(function ReplaceIframeAd() { | 317 functions.push(function ReplaceIframeAd1() { |
| 351 $('ad-iframe').src = kAdNetwork2; | 318 $('ad-iframe').src = kAdNetwork2; |
| 352 return INJECTION_REPLACED_AD; | 319 return INJECTION_REPLACED_AD; |
| 353 }); | 320 }); |
| 354 | 321 |
| 322 functions.push(function ReplaceIframeAd2() { | |
| 323 $('ad-iframe').setAttribute('src', kAdNetwork2); | |
| 324 return INJECTION_REPLACED_AD; | |
| 325 }); | |
| 326 | |
| 355 // Switch an existing anchor ad to a new ad network. | 327 // Switch an existing anchor ad to a new ad network. |
| 356 functions.push(function ReplaceAnchorAd() { | 328 functions.push(function ReplaceAnchorAd1() { |
| 357 $('ad-anchor').href = kAdNetwork2; | 329 $('ad-anchor').href = kAdNetwork2; |
| 358 return INJECTION_REPLACED_AD; | 330 return INJECTION_REPLACED_AD; |
| 359 }); | 331 }); |
| 360 | 332 |
| 333 functions.push(function ReplaceAnchorAd2() { | |
| 334 $('ad-anchor').setAttribute('href', kAdNetwork2); | |
| 335 return INJECTION_REPLACED_AD; | |
| 336 }); | |
| 337 | |
| 361 // Remove an existing embed ad by setting it's src to a non-ad network. | 338 // Remove an existing embed ad by setting it's src to a non-ad network. |
|
Devlin
2014/07/17 15:31:52
nit: update comment.
pmarch
2014/07/17 16:35:46
Done.
| |
| 362 functions.push(function RemoveAdBySettingSrc() { | 339 functions.push(function RemoveAdBySettingSrc() { |
| 363 $('ad-embed').src = kMaybeAdNetwork; | 340 $('ad-iframe').src = kMaybeAdNetwork; |
| 364 return INJECTION_REMOVED_AD; | 341 return INJECTION_REMOVED_AD; |
| 365 }); | 342 }); |
| 366 | 343 |
| 367 // Ensure that we flag actions that look a lot like ad injection, even if we're | 344 // Ensure that we flag actions that look a lot like ad injection, even if we're |
| 368 // not sure. | 345 // not sure. |
| 369 functions.push(function LikelyReplacedAd() { | 346 functions.push(function LikelyReplacedAd() { |
| 370 // Switching from one valid url src to another valid url src is very | 347 // Switching from one valid url src to another valid url src is very |
| 371 // suspicious behavior, and should be relatively rare. This helps us determine | 348 // suspicious behavior, and should be relatively rare. This helps us determine |
| 372 // the effectiveness of our ad network recognition. | 349 // the effectiveness of our ad network recognition. |
| 373 $('non-ad-embed').src = 'http://www.thismightbeanadnetwork.ads'; | 350 $('non-ad-iframe').src = 'http://www.thismightbeanadnetwork.ads'; |
| 374 return INJECTION_LIKELY_REPLACED_AD; | 351 return INJECTION_LIKELY_REPLACED_AD; |
| 375 }); | 352 }); |
| 376 | 353 |
| 377 // Verify that we do not enter the javascript world when we check for ad | 354 // Verify that we do not enter the javascript world when we check for ad |
| 378 // injection. | 355 // injection. |
| 379 functions.push(function VerifyNoAccess() { | 356 functions.push(function VerifyNoAccess() { |
| 380 var frame = document.createElement('iframe'); | 357 var frame = document.createElement('iframe'); |
| 381 frame.__defineGetter__('src', function() { | 358 frame.__defineGetter__('src', function() { |
| 382 throw new Error('Forbidden access into javascript execution!'); | 359 throw new Error('Forbidden access into javascript execution!'); |
| 383 return kAdNetwork; | 360 return kAdNetwork; |
| 384 }); | 361 }); |
| 385 return NO_AD_INJECTION; | 362 return NO_AD_INJECTION; |
| 386 }); | 363 }); |
| 387 | 364 |
| 388 // TODO(rdevlin.cronin): We are not covering every case yet. Fix this. | 365 // TODO(rdevlin.cronin): We are not covering every case yet. Fix this. |
| 389 // See crbug.com/357204. | 366 // See crbug.com/357204. |
| 390 | 367 |
| 391 // Kick off the tests. | 368 // Kick off the tests. |
| 392 var test = new AdInjectorTest(functions); | 369 var test = new AdInjectorTest(functions); |
| 393 test.runNextFunction(); | 370 test.runNextFunction(); |
| OLD | NEW |