| 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 15 matching lines...) Expand all Loading... |
| 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>' + | 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>' + | 35 '<embed id="non-ad-embed" src="http://www.not-ads.adnetwork"><embed>' + |
| 36 '<a id="ad-link" href="http://www.known-ads.adnetwork"></a>' + | 36 '<a id="ad-anchor" href="http://www.known-ads.adnetwork"></a>' + |
| 37 '<a id="non-ad-link" href="http://www.not-ads.adnetwork"></a>' + | 37 '<a id="non-ad-anchor" href="http://www.not-ads.adnetwork"></a>' + |
| 38 '<div id="empty-div"></div>'; | 38 '<div id="empty-div"></div>'; |
| 39 | 39 |
| 40 | |
| 41 | |
| 42 /** | 40 /** |
| 43 * The AdInjectorTest infrastructure. Basically, this allows the test to follow | 41 * The AdInjectorTest infrastructure. Basically, this allows the test to follow |
| 44 * a simple iteration cycle: | 42 * a simple iteration cycle: |
| 45 * - Signal the C++ test that we're going to do page setup, and we shouldn't | 43 * - Signal the C++ test that we're going to do page setup, and we shouldn't |
| 46 * record any ad-injector events (as some of the page setup could qualify). | 44 * record any ad-injector events (as some of the page setup could qualify). |
| 47 * - Do the page setup, which involves creating a 'playground' for ad injectors | 45 * - Do the page setup, which involves creating a 'playground' for ad injectors |
| 48 * of iframes, embeds, etc. See also ad_injectors.html. We do this set up for | 46 * of iframes, embeds, etc. See also ad_injectors.html. We do this set up for |
| 49 * each test, so that none of the tests conflicts with each other. | 47 * each test, so that none of the tests conflicts with each other. |
| 50 * - Signal that we are done with page setup, and should start recording events. | 48 * - Signal that we are done with page setup, and should start recording events. |
| 51 * - Run the next test. | 49 * - Run the next test. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 this.runNextFunction(); | 127 this.runNextFunction(); |
| 130 }.bind(this)); | 128 }.bind(this)); |
| 131 } | 129 } |
| 132 }; | 130 }; |
| 133 | 131 |
| 134 // Return values to signal the result of a test. Each test should return the | 132 // Return values to signal the result of a test. Each test should return the |
| 135 // appropriate value in order to indicate if an ad was injected, and, if so, | 133 // appropriate value in order to indicate if an ad was injected, and, if so, |
| 136 // what kind of injection. | 134 // what kind of injection. |
| 137 // These match the enum values in | 135 // These match the enum values in |
| 138 // chrome/browser/extensions/activity_log/activity_actions.h. | 136 // chrome/browser/extensions/activity_log/activity_actions.h. |
| 139 var NO_AD_INJECTION = 0; // The signal that there was no ad injection. | 137 // The signal that there was no ad injection. |
| 140 var INJECTION_NEW_AD = 1; // The signal that there was a new ad injected. | 138 var NO_AD_INJECTION = 0; |
| 141 var INJECTION_REMOVED_AD = 2; // The signal that an ad was removed. | 139 // The signal that there was a new ad injected. |
| 142 var INJECTION_REPLACED_AD = 3; // The signal that an ad was replaced. | 140 var INJECTION_NEW_AD = 1; |
| 141 // The signal that an ad was removed. |
| 142 var INJECTION_REMOVED_AD = 2; |
| 143 // The signal that an ad was replaced. |
| 144 var INJECTION_REPLACED_AD = 3; |
| 145 // The signal that an ad was likely injected, but we didn't detect it fully. |
| 146 var INJECTION_LIKELY_NEW_AD = 4; |
| 147 // The signal that an ad was likely replaced, but we didn't detect it fully. |
| 148 var INJECTION_LIKELY_REPLACED_AD = 5; |
| 143 | 149 |
| 144 /* The "ad network" url to use for tests. */ | 150 /* The "ad network" url to use for tests. */ |
| 145 var kAdNetwork = 'http://www.known-ads.adnetwork'; | 151 var kAdNetwork = 'http://www.known-ads.adnetwork'; |
| 152 var kAdNetwork2 = 'http://www.also-known-ads.adnetwork'; |
| 146 | 153 |
| 147 /* The "non ad network" url to use for tests. */ | 154 /* The "non ad network" url to use for tests. */ |
| 148 var kNonAdNetwork = 'http://www.not-ads.adnetwork'; | 155 var kMaybeAdNetwork = 'http://www.maybe-ads.adnetwork'; |
| 149 | 156 |
| 150 /* @return {?HTMLElement} The element with the given id. */ | 157 /* @return {?HTMLElement} The element with the given id. */ |
| 151 var $ = function(id) { return document.getElementById(id); } | 158 var $ = function(id) { return document.getElementById(id); } |
| 152 | 159 |
| 153 // The following is a collection of functions to "get" an HTML ad. We need to do | 160 // The following is a collection of functions to "get" an HTML ad. We need to do |
| 154 // this for internal counting in testing, because if we simply do: | 161 // this for internal counting in testing, because if we simply do: |
| 155 // var iframe = document.createElement('iframe'); | 162 // var iframe = document.createElement('iframe'); |
| 156 // iframe.src = kAdNetwork; | 163 // iframe.src = kAdNetwork; |
| 157 // document.body.appendChild(iframe); | 164 // document.body.appendChild(iframe); |
| 158 // We end up double counting ad injections. We count one for modifying the src | 165 // We end up double counting ad injections. We count one for modifying the src |
| (...skipping 19 matching lines...) Expand all Loading... |
| 178 var kEmbedAdTemplate = document.createElement('embed'); | 185 var kEmbedAdTemplate = document.createElement('embed'); |
| 179 kEmbedAdTemplate.src = kAdNetwork; | 186 kEmbedAdTemplate.src = kAdNetwork; |
| 180 | 187 |
| 181 /** | 188 /** |
| 182 * @return An embed element which will count as ad injection in the tests. | 189 * @return An embed element which will count as ad injection in the tests. |
| 183 */ | 190 */ |
| 184 var getEmbedAd = function() { | 191 var getEmbedAd = function() { |
| 185 return kEmbedAdTemplate.cloneNode(true); | 192 return kEmbedAdTemplate.cloneNode(true); |
| 186 }; | 193 }; |
| 187 | 194 |
| 188 // Creates a link ad, like so: | 195 // Creates an anchor ad, like so: |
| 189 // <a href="http://www.known-ads.adnetwork"></a> | 196 // <a href="http://www.known-ads.adnetwork"></a> |
| 190 var kLinkAdTemplate = document.createElement('a'); | 197 var kAnchorAdTemplate = document.createElement('a'); |
| 191 kLinkAdTemplate.href = kAdNetwork; | 198 kAnchorAdTemplate.href = kAdNetwork; |
| 192 | 199 |
| 193 /** | 200 /** |
| 194 * @return A link ('a') element which will count as ad injection in the tests. | 201 * @return An anchor ('a') element which will count as ad injection in the |
| 202 * tests. |
| 195 */ | 203 */ |
| 196 var getLinkAd = function() { | 204 var getAnchorAd = function() { |
| 197 return kLinkAdTemplate.cloneNode(true); | 205 return kAnchorAdTemplate.cloneNode(true); |
| 198 }; | 206 }; |
| 199 | 207 |
| 200 // This series constructs a nested ad, which looks like this: | 208 // This series constructs a nested ad, which looks like this: |
| 201 // <div> | 209 // <div> |
| 202 // <div> | 210 // <div> |
| 203 // <span></span> | 211 // <span></span> |
| 204 // <iframe src="http://www.known-ads.adnetwork"></iframe> | 212 // <iframe src="http://www.known-ads.adnetwork"></iframe> |
| 205 // </div> | 213 // </div> |
| 206 // </div> | 214 // </div> |
| 207 var div = document.createElement('div'); | 215 var div = document.createElement('div'); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 221 /* | 229 /* |
| 222 * The collection of functions to use for testing. | 230 * The collection of functions to use for testing. |
| 223 * In order to add a new test, simply append it to the collection of functions. | 231 * In order to add a new test, simply append it to the collection of functions. |
| 224 * All functions will be run in the test, and each will report its success or | 232 * All functions will be run in the test, and each will report its success or |
| 225 * failure independently of the others. | 233 * failure independently of the others. |
| 226 * All test functions must be synchronous. | 234 * All test functions must be synchronous. |
| 227 * @type {Array.<Function>} | 235 * @type {Array.<Function>} |
| 228 */ | 236 */ |
| 229 var functions = []; | 237 var functions = []; |
| 230 | 238 |
| 239 // Add a bunch of elements, but nothing that looks like ad injection (no |
| 240 // elements with an external source, no modifying existing sources). |
| 241 functions.push(function NoAdInjection() { |
| 242 var div = document.createElement('div'); |
| 243 var iframe = document.createElement('iframe'); |
| 244 var embed = document.createElement('embed'); |
| 245 var anchor = document.createElement('anchor'); |
| 246 var span = document.createElement('span'); |
| 247 span.textContent = 'Hello, world'; |
| 248 div.appendChild(iframe); |
| 249 div.appendChild(embed); |
| 250 div.appendChild(anchor); |
| 251 div.appendChild(span); |
| 252 document.body.appendChild(div); |
| 253 return NO_AD_INJECTION; |
| 254 }); |
| 255 |
| 231 // Add a new iframe with an AdNetwork source by creating the element and | 256 // Add a new iframe with an AdNetwork source by creating the element and |
| 232 // appending it. | 257 // appending it. |
| 233 functions.push(function NewIframeAdNetwork() { | 258 functions.push(function NewIframeAdNetwork() { |
| 234 document.body.appendChild(getIframeAd()); | 259 document.body.appendChild(getIframeAd()); |
| 235 return INJECTION_NEW_AD; | 260 return INJECTION_NEW_AD; |
| 236 }); | 261 }); |
| 237 | 262 |
| 238 // Add a new iframe which does not serve ads. We should not record anything. | 263 // Add a new iframe which does not serve ads. We should not record anything. |
| 239 functions.push(function NewIframeNonAdNetwork() { | 264 functions.push(function NewIframeLikelyAdNetwork() { |
| 240 var frame = document.createElement('iframe'); | 265 var frame = document.createElement('iframe'); |
| 241 frame.src = kNonAdNetwork; | 266 document.body.appendChild(frame).src = kMaybeAdNetwork; |
| 242 document.body.appendChild(frame); | 267 return INJECTION_LIKELY_NEW_AD; |
| 243 return NO_AD_INJECTION; | |
| 244 }); | 268 }); |
| 245 | 269 |
| 246 // Modify an iframe which is currently in the DOM, switching the src to an | 270 // Modify an iframe which is currently in the DOM, switching the src to an |
| 247 // ad network. | 271 // ad network. |
| 248 functions.push(function ModifyExistingIframeToAdNetwork() { | 272 functions.push(function ModifyExistingIframeToAdNetwork() { |
| 249 var frame = $('ad-iframe'); | 273 var frame = $('non-ad-iframe'); |
| 250 frame.src = kAdNetwork; | 274 frame.src = kAdNetwork; |
| 251 return INJECTION_NEW_AD; | 275 return INJECTION_NEW_AD; |
| 252 }); | 276 }); |
| 253 | 277 |
| 254 // Add a new embed element which serves ads. | 278 // Add a new embed element which serves ads. |
| 255 functions.push(function NewEmbedAdNetwork() { | 279 functions.push(function NewEmbedAdNetwork() { |
| 256 document.body.appendChild(getEmbedAd()); | 280 document.body.appendChild(getEmbedAd()); |
| 257 return INJECTION_NEW_AD; | 281 return INJECTION_NEW_AD; |
| 258 }); | 282 }); |
| 259 | 283 |
| 260 // Add a new embed element which does not serve ads. We should not record | 284 // Add a new embed element which does not serve ads. We should not record |
| 261 // anything. | 285 // anything. |
| 262 functions.push(function NewEmbedNonAdNetwork() { | 286 functions.push(function NewEmbedLikelyAdNetwork() { |
| 263 var embed = document.createElement('embed'); | 287 var embed = document.createElement('embed'); |
| 264 embed.src = kNonAdNetwork; | 288 document.body.appendChild(embed).src = kMaybeAdNetwork; |
| 265 document.body.appendChild(embed); | 289 return INJECTION_LIKELY_NEW_AD; |
| 266 return NO_AD_INJECTION; | |
| 267 }); | 290 }); |
| 268 | 291 |
| 269 // Modify an embed which is currently in the DOM, switching the src to an | 292 // Modify an embed which is currently in the DOM, switching the src to an |
| 270 // ad network. | 293 // ad network. |
| 271 functions.push(function ModifyExistingEmbedToAdNetwork() { | 294 functions.push(function ModifyExistingEmbedToAdNetwork() { |
| 272 var embed = $('ad-embed'); | 295 var embed = $('non-ad-embed'); |
| 273 embed.src = kAdNetwork; | 296 embed.src = kAdNetwork; |
| 274 return INJECTION_NEW_AD; | 297 return INJECTION_NEW_AD; |
| 275 }); | 298 }); |
| 276 | 299 |
| 277 // Add a new link element which serves ads. | 300 // Add a new anchor element which serves ads. |
| 278 functions.push(function NewLinkAd() { | 301 functions.push(function NewAnchorAd() { |
| 279 document.body.appendChild(getLinkAd()); | 302 document.body.appendChild(getAnchorAd()); |
| 280 return INJECTION_NEW_AD; | 303 return INJECTION_NEW_AD; |
| 281 }); | 304 }); |
| 282 | 305 |
| 306 functions.push(function NewAnchorLikelyAd() { |
| 307 var anchor = document.createElement('a'); |
| 308 document.body.appendChild(anchor).href = kMaybeAdNetwork; |
| 309 return INJECTION_LIKELY_NEW_AD; |
| 310 }); |
| 311 |
| 312 functions.push(function ModifyExistingAnchorToAdNetwork() { |
| 313 var anchor = $('non-ad-anchor'); |
| 314 anchor.href = kAdNetwork; |
| 315 return INJECTION_NEW_AD; |
| 316 }); |
| 317 |
| 283 // Add a new element which has a nested ad, to ensure we do a deep check of | 318 // Add a new element which has a nested ad, to ensure we do a deep check of |
| 284 // elements appended to the dom. | 319 // elements appended to the dom. |
| 285 functions.push(function NewNestedAd() { | 320 functions.push(function NewNestedAd() { |
| 286 document.body.appendChild(getNestedAd()); | 321 document.body.appendChild(getNestedAd()); |
| 287 return INJECTION_NEW_AD; | 322 return INJECTION_NEW_AD; |
| 288 }); | 323 }); |
| 289 | 324 |
| 325 // Switch an existing embed ad to a new ad network. |
| 326 functions.push(function ReplaceEmbedAd() { |
| 327 $('ad-embed').src = kAdNetwork2; |
| 328 return INJECTION_REPLACED_AD; |
| 329 }); |
| 330 |
| 331 // Switch an existing iframe ad to a new ad network. |
| 332 functions.push(function ReplaceIframeAd() { |
| 333 $('ad-iframe').src = kAdNetwork2; |
| 334 return INJECTION_REPLACED_AD; |
| 335 }); |
| 336 |
| 337 // Switch an existing anchor ad to a new ad network. |
| 338 functions.push(function ReplaceAnchorAd() { |
| 339 $('ad-anchor').href = kAdNetwork2; |
| 340 return INJECTION_REPLACED_AD; |
| 341 }); |
| 342 |
| 343 // Remove an existing embed ad by setting it's src to a non-ad network. |
| 344 functions.push(function RemoveAdBySettingSrc() { |
| 345 $('ad-embed').src = kMaybeAdNetwork; |
| 346 return INJECTION_REMOVED_AD; |
| 347 }); |
| 348 |
| 349 // Ensure that we flag actions that look a lot like ad injection, even if we're |
| 350 // not sure. |
| 351 functions.push(function LikelyReplacedAd() { |
| 352 // Switching from one valid url src to another valid url src is very |
| 353 // suspicious behavior, and should be relatively rare. This helps us determine |
| 354 // the effectiveness of our ad network recognition. |
| 355 $('non-ad-embed').src = 'http://www.thismightbeanadnetwork.ads'; |
| 356 return INJECTION_LIKELY_REPLACED_AD; |
| 357 }); |
| 358 |
| 290 // Verify that we do not enter the javascript world when we check for ad | 359 // Verify that we do not enter the javascript world when we check for ad |
| 291 // injection. | 360 // injection. |
| 292 functions.push(function VerifyNoAccess() { | 361 functions.push(function VerifyNoAccess() { |
| 293 var frame = document.createElement('iframe'); | 362 var frame = document.createElement('iframe'); |
| 294 frame.__defineGetter__('src', function() { | 363 frame.__defineGetter__('src', function() { |
| 295 throw new Error('Forbidden access into javascript execution!'); | 364 throw new Error('Forbidden access into javascript execution!'); |
| 296 return kAdNetwork; | 365 return kAdNetwork; |
| 297 }); | 366 }); |
| 298 return NO_AD_INJECTION; | 367 return NO_AD_INJECTION; |
| 299 }); | 368 }); |
| 300 | 369 |
| 301 // TODO(rdevlin.cronin): We are not covering every case yet. Fix this. | 370 // TODO(rdevlin.cronin): We are not covering every case yet. Fix this. |
| 302 // See crbug.com/357204. | 371 // See crbug.com/357204. |
| 303 | 372 |
| 304 // Kick off the tests. | 373 // Kick off the tests. |
| 305 var test = new AdInjectorTest(functions); | 374 var test = new AdInjectorTest(functions); |
| 306 test.runNextFunction(); | 375 test.runNextFunction(); |
| OLD | NEW |