| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "base/run_loop.h" | 
|  | 6 #include "base/stringprintf.h" | 
|  | 7 #include "chrome/browser/extensions/blacklist.h" | 
|  | 8 #include "chrome/browser/extensions/extension_browsertest.h" | 
|  | 9 #include "chrome/browser/extensions/extension_service.h" | 
|  | 10 #include "chrome/browser/extensions/extension_system.h" | 
|  | 11 #include "chrome/browser/ui/browser.h" | 
|  | 12 #include "chrome/common/chrome_notification_types.h" | 
|  | 13 #include "chrome/common/extensions/extension.h" | 
|  | 14 #include "chrome/common/extensions/extension_constants.h" | 
|  | 15 #include "content/public/browser/notification_details.h" | 
|  | 16 #include "content/public/browser/notification_observer.h" | 
|  | 17 #include "content/public/browser/notification_registrar.h" | 
|  | 18 #include "content/public/browser/notification_source.h" | 
|  | 19 | 
|  | 20 namespace extensions { | 
|  | 21 | 
|  | 22 namespace { | 
|  | 23 | 
|  | 24 // Records notifications, but only for extensions with specific IDs. | 
|  | 25 class FilteringNotificationObserver : public content::NotificationObserver { | 
|  | 26  public: | 
|  | 27   FilteringNotificationObserver( | 
|  | 28       content::NotificationSource source, | 
|  | 29       const std::set<std::string>& extension_ids) | 
|  | 30       : extension_ids_(extension_ids) { | 
|  | 31     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, source); | 
|  | 32     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, source); | 
|  | 33     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, source); | 
|  | 34   } | 
|  | 35 | 
|  | 36   // Checks then clears notifications for our extensions. | 
|  | 37   testing::AssertionResult CheckNotifications(chrome::NotificationType type) { | 
|  | 38     return CheckNotifications(std::vector<chrome::NotificationType>(1, type)); | 
|  | 39   } | 
|  | 40 | 
|  | 41   // Checks then clears notifications for our extensions. | 
|  | 42   testing::AssertionResult CheckNotifications(chrome::NotificationType t1, | 
|  | 43                                               chrome::NotificationType t2) { | 
|  | 44     std::vector<chrome::NotificationType> types; | 
|  | 45     types.push_back(t1); | 
|  | 46     types.push_back(t2); | 
|  | 47     return CheckNotifications(types); | 
|  | 48   } | 
|  | 49 | 
|  | 50   // Checks then clears notifications for our extensions. | 
|  | 51   testing::AssertionResult CheckNotifications(chrome::NotificationType t1, | 
|  | 52                                               chrome::NotificationType t2, | 
|  | 53                                               chrome::NotificationType t3) { | 
|  | 54     std::vector<chrome::NotificationType> types; | 
|  | 55     types.push_back(t1); | 
|  | 56     types.push_back(t2); | 
|  | 57     types.push_back(t3); | 
|  | 58     return CheckNotifications(types); | 
|  | 59   } | 
|  | 60 | 
|  | 61   // Checks then clears notifications for our extensions. | 
|  | 62   testing::AssertionResult CheckNotifications(chrome::NotificationType t1, | 
|  | 63                                               chrome::NotificationType t2, | 
|  | 64                                               chrome::NotificationType t3, | 
|  | 65                                               chrome::NotificationType t4, | 
|  | 66                                               chrome::NotificationType t5, | 
|  | 67                                               chrome::NotificationType t6) { | 
|  | 68     std::vector<chrome::NotificationType> types; | 
|  | 69     types.push_back(t1); | 
|  | 70     types.push_back(t2); | 
|  | 71     types.push_back(t3); | 
|  | 72     types.push_back(t4); | 
|  | 73     types.push_back(t5); | 
|  | 74     types.push_back(t6); | 
|  | 75     return CheckNotifications(types); | 
|  | 76   } | 
|  | 77 | 
|  | 78  private: | 
|  | 79   // content::NotificationObserver implementation. | 
|  | 80   virtual void Observe(int type, | 
|  | 81                        const content::NotificationSource& source, | 
|  | 82                        const content::NotificationDetails& details) OVERRIDE { | 
|  | 83     switch (type) { | 
|  | 84       case chrome::NOTIFICATION_EXTENSION_INSTALLED: { | 
|  | 85         const Extension* extension = | 
|  | 86             content::Details<const Extension>(details).ptr(); | 
|  | 87         if (extension_ids_.count(extension->id())) | 
|  | 88           notifications_.push_back(static_cast<chrome::NotificationType>(type)); | 
|  | 89         break; | 
|  | 90       } | 
|  | 91 | 
|  | 92       case chrome::NOTIFICATION_EXTENSION_LOADED: { | 
|  | 93         const Extension* extension = | 
|  | 94             content::Details<const Extension>(details).ptr(); | 
|  | 95         if (extension_ids_.count(extension->id())) | 
|  | 96           notifications_.push_back(static_cast<chrome::NotificationType>(type)); | 
|  | 97         break; | 
|  | 98       } | 
|  | 99 | 
|  | 100       case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | 
|  | 101         UnloadedExtensionInfo* reason = | 
|  | 102             content::Details<UnloadedExtensionInfo>(details).ptr(); | 
|  | 103         if (extension_ids_.count(reason->extension->id())) { | 
|  | 104           notifications_.push_back(static_cast<chrome::NotificationType>(type)); | 
|  | 105           // The only way that extensions are unloaded in these tests is | 
|  | 106           // by blacklisting. | 
|  | 107           EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST, | 
|  | 108                     reason->reason); | 
|  | 109         } | 
|  | 110         break; | 
|  | 111       } | 
|  | 112 | 
|  | 113       default: | 
|  | 114         NOTREACHED(); | 
|  | 115         break; | 
|  | 116     } | 
|  | 117   } | 
|  | 118 | 
|  | 119   // Checks then clears notifications for our extensions. | 
|  | 120   testing::AssertionResult CheckNotifications( | 
|  | 121       const std::vector<chrome::NotificationType>& types) { | 
|  | 122     testing::AssertionResult result = (notifications_ == types) ? | 
|  | 123         testing::AssertionSuccess() : | 
|  | 124         testing::AssertionFailure() << "Expected " << Str(types) << ", " << | 
|  | 125                                        "Got " << Str(notifications_); | 
|  | 126     notifications_.clear(); | 
|  | 127     return result; | 
|  | 128   } | 
|  | 129 | 
|  | 130   std::string Str(const std::vector<chrome::NotificationType>& types) { | 
|  | 131     std::string str = "["; | 
|  | 132     bool needs_comma = false; | 
|  | 133     for (std::vector<chrome::NotificationType>::const_iterator it = | 
|  | 134          types.begin(); it != types.end(); ++it) { | 
|  | 135       if (needs_comma) | 
|  | 136         str += ","; | 
|  | 137       needs_comma = true; | 
|  | 138       str += base::StringPrintf("%d", *it); | 
|  | 139     } | 
|  | 140     return str + "]"; | 
|  | 141   } | 
|  | 142 | 
|  | 143   const std::set<std::string> extension_ids_; | 
|  | 144 | 
|  | 145   std::vector<chrome::NotificationType> notifications_; | 
|  | 146 | 
|  | 147   content::NotificationRegistrar registrar_; | 
|  | 148 }; | 
|  | 149 | 
|  | 150 // Stores the paths to CRX files of extensions, and the extension's ID. | 
|  | 151 // Use arbitrary extensions; we're just testing blacklisting behavior. | 
|  | 152 class CrxInfo { | 
|  | 153  public: | 
|  | 154   CrxInfo(const std::string& path, const std::string& id) | 
|  | 155       : path_(path), id_(id) {} | 
|  | 156 | 
|  | 157   const std::string& path() { return path_; } | 
|  | 158   const std::string& id() { return id_; } | 
|  | 159 | 
|  | 160  private: | 
|  | 161   const std::string path_; | 
|  | 162   const std::string id_; | 
|  | 163 }; | 
|  | 164 | 
|  | 165 }  // namespace | 
|  | 166 | 
|  | 167 class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest { | 
|  | 168  public: | 
|  | 169   ExtensionBlacklistBrowserTest() | 
|  | 170       : info_a_("install/install.crx", "ogdbpbegnmindpdjfafpmpicikegejdj"), | 
|  | 171         info_b_("autoupdate/v1.crx",   "ogjcoiohnmldgjemafoockdghcjciccf"), | 
|  | 172         info_c_("hosted_app.crx",      "kbmnembihfiondgfjekmnmcbddelicoi") {} | 
|  | 173 | 
|  | 174   virtual ~ExtensionBlacklistBrowserTest() {} | 
|  | 175 | 
|  | 176  protected: | 
|  | 177   // Returns whether |extension| is strictly safe: in one of ExtensionService's | 
|  | 178   // non-blacklisted extension sets, and not in its blacklisted extensions. | 
|  | 179   testing::AssertionResult IsSafe(const Extension* extension) { | 
|  | 180     std::string id = extension->id(); | 
|  | 181     int include_mask =  ExtensionService::INCLUDE_EVERYTHING & | 
|  | 182                        ~ExtensionService::INCLUDE_BLACKLISTED; | 
|  | 183     if (!extension_service()->GetExtensionById(id, include_mask)) | 
|  | 184       return testing::AssertionFailure() << id << " is safe"; | 
|  | 185     return IsInValidState(extension); | 
|  | 186   } | 
|  | 187 | 
|  | 188   // Returns whether |extension| is strictly blacklisted: in ExtensionService's | 
|  | 189   // blacklist, and not in any of its other extension sets. | 
|  | 190   testing::AssertionResult IsBlacklisted(const Extension* extension) { | 
|  | 191     std::string id = extension->id(); | 
|  | 192     if (!extension_service()->blacklisted_extensions()->Contains(id)) | 
|  | 193       return testing::AssertionFailure() << id << " is not blacklisted"; | 
|  | 194     return IsInValidState(extension); | 
|  | 195   } | 
|  | 196 | 
|  | 197   std::set<std::string> GetTestExtensionIDs() { | 
|  | 198     std::set<std::string> extension_ids; | 
|  | 199     extension_ids.insert(info_a_.id()); | 
|  | 200     extension_ids.insert(info_b_.id()); | 
|  | 201     extension_ids.insert(info_c_.id()); | 
|  | 202     return extension_ids; | 
|  | 203   } | 
|  | 204 | 
|  | 205   Blacklist* blacklist() { | 
|  | 206     return ExtensionSystem::Get(profile())->blacklist(); | 
|  | 207   } | 
|  | 208 | 
|  | 209   CrxInfo info_a_; | 
|  | 210   CrxInfo info_b_; | 
|  | 211   CrxInfo info_c_; | 
|  | 212 | 
|  | 213  private: | 
|  | 214   // Returns whether |extension| is either installed or blacklisted, but | 
|  | 215   // neither both nor neither. | 
|  | 216   testing::AssertionResult IsInValidState(const Extension* extension) { | 
|  | 217     std::string id = extension->id(); | 
|  | 218     bool is_blacklisted = | 
|  | 219         extension_service()->blacklisted_extensions()->Contains(id); | 
|  | 220     int safe_mask =  ExtensionService::INCLUDE_EVERYTHING & | 
|  | 221                      ~ExtensionService::INCLUDE_BLACKLISTED; | 
|  | 222     bool is_safe = extension_service()->GetExtensionById(id, safe_mask) != NULL; | 
|  | 223     if (is_blacklisted && is_safe) { | 
|  | 224       return testing::AssertionFailure() << | 
|  | 225           id << " is both safe and in blacklisted_extensions"; | 
|  | 226     } | 
|  | 227     if (!is_blacklisted && !is_safe) { | 
|  | 228       return testing::AssertionFailure() << | 
|  | 229           id << " is neither safe nor in blacklisted_extensions"; | 
|  | 230     } | 
|  | 231     return testing::AssertionSuccess(); | 
|  | 232   } | 
|  | 233 }; | 
|  | 234 | 
|  | 235 // Stage 1: blacklisting when there weren't any extensions installed when the | 
|  | 236 // browser started. | 
|  | 237 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) { | 
|  | 238   FilteringNotificationObserver notifications( | 
|  | 239       content::NotificationService::AllSources(), GetTestExtensionIDs()); | 
|  | 240 | 
|  | 241   scoped_refptr<const Extension> extension_a = | 
|  | 242       InstallExtension(test_data_dir_.AppendASCII(info_a_.path()), 1); | 
|  | 243   scoped_refptr<const Extension> extension_b = | 
|  | 244       InstallExtension(test_data_dir_.AppendASCII(info_b_.path()), 1); | 
|  | 245   scoped_refptr<const Extension> extension_c = | 
|  | 246       InstallExtension(test_data_dir_.AppendASCII(info_c_.path()), 1); | 
|  | 247 | 
|  | 248   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 249       chrome::NOTIFICATION_EXTENSION_INSTALLED, | 
|  | 250       chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 251       chrome::NOTIFICATION_EXTENSION_INSTALLED, | 
|  | 252       chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 253       chrome::NOTIFICATION_EXTENSION_INSTALLED, | 
|  | 254       chrome::NOTIFICATION_EXTENSION_LOADED)); | 
|  | 255 | 
|  | 256   ASSERT_TRUE(extension_a); | 
|  | 257   ASSERT_TRUE(extension_b); | 
|  | 258   ASSERT_EQ(info_a_.id(), extension_a->id()); | 
|  | 259   ASSERT_EQ(info_b_.id(), extension_b->id()); | 
|  | 260   ASSERT_EQ(info_c_.id(), extension_c->id()); | 
|  | 261 | 
|  | 262   std::vector<std::string> empty_vector; | 
|  | 263   std::vector<std::string> vector_a(1, info_a_.id()); | 
|  | 264   std::vector<std::string> vector_b(1, info_b_.id()); | 
|  | 265   std::vector<std::string> vector_c(1, info_c_.id()); | 
|  | 266   std::vector<std::string> vector_ab(1, info_a_.id()); | 
|  | 267   vector_ab.push_back(info_b_.id()); | 
|  | 268   std::vector<std::string> vector_bc(1, info_b_.id()); | 
|  | 269   vector_bc.push_back(info_c_.id()); | 
|  | 270   std::vector<std::string> vector_abc(1, info_a_.id()); | 
|  | 271   vector_abc.push_back(info_b_.id()); | 
|  | 272   vector_abc.push_back(info_c_.id()); | 
|  | 273 | 
|  | 274   EXPECT_TRUE(IsSafe(extension_a)); | 
|  | 275   EXPECT_TRUE(IsSafe(extension_b)); | 
|  | 276   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 277 | 
|  | 278   // Blacklist a and b. | 
|  | 279   blacklist()->SetFromUpdater(vector_ab, "1"); | 
|  | 280   base::RunLoop().RunUntilIdle(); | 
|  | 281 | 
|  | 282   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 283   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 284   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 285   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 286       chrome::NOTIFICATION_EXTENSION_UNLOADED, | 
|  | 287       chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 288 | 
|  | 289   // Un-blacklist a. | 
|  | 290   blacklist()->SetFromUpdater(vector_b, "2"); | 
|  | 291   base::RunLoop().RunUntilIdle(); | 
|  | 292 | 
|  | 293   EXPECT_TRUE(IsSafe(extension_a)); | 
|  | 294   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 295   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 296   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 297       chrome::NOTIFICATION_EXTENSION_LOADED)); | 
|  | 298 | 
|  | 299   // Blacklist a then switch with c. | 
|  | 300   blacklist()->SetFromUpdater(vector_ab, "3"); | 
|  | 301   base::RunLoop().RunUntilIdle(); | 
|  | 302 | 
|  | 303   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 304   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 305   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 306   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 307       chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 308 | 
|  | 309   blacklist()->SetFromUpdater(vector_bc, "4"); | 
|  | 310   base::RunLoop().RunUntilIdle(); | 
|  | 311 | 
|  | 312   EXPECT_TRUE(IsSafe(extension_a)); | 
|  | 313   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 314   EXPECT_TRUE(IsBlacklisted(extension_c)); | 
|  | 315   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 316       chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 317       chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 318 | 
|  | 319   // Add a to blacklist. | 
|  | 320   blacklist()->SetFromUpdater(vector_abc, "5"); | 
|  | 321   base::RunLoop().RunUntilIdle(); | 
|  | 322 | 
|  | 323   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 324   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 325   EXPECT_TRUE(IsBlacklisted(extension_c)); | 
|  | 326   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 327       chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 328 | 
|  | 329   // Clear blacklist. | 
|  | 330   blacklist()->SetFromUpdater(empty_vector, "6"); | 
|  | 331   base::RunLoop().RunUntilIdle(); | 
|  | 332 | 
|  | 333   EXPECT_TRUE(IsSafe(extension_a)); | 
|  | 334   EXPECT_TRUE(IsSafe(extension_b)); | 
|  | 335   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 336   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 337       chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 338       chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 339       chrome::NOTIFICATION_EXTENSION_LOADED)); | 
|  | 340 | 
|  | 341   // Add a and b back again for the next test. | 
|  | 342   blacklist()->SetFromUpdater(vector_ab, "7"); | 
|  | 343   base::RunLoop().RunUntilIdle(); | 
|  | 344 | 
|  | 345   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 346   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 347   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 348   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 349       chrome::NOTIFICATION_EXTENSION_UNLOADED, | 
|  | 350       chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 351 } | 
|  | 352 | 
|  | 353 // Stage 2: blacklisting with extensions A and B having been installed, | 
|  | 354 // with A actually in the blacklist. | 
|  | 355 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) { | 
|  | 356   FilteringNotificationObserver notifications( | 
|  | 357       content::Source<Profile>(profile()), GetTestExtensionIDs()); | 
|  | 358 | 
|  | 359   scoped_refptr<const Extension> extension_a = | 
|  | 360       extension_service()->blacklisted_extensions()->GetByID(info_a_.id()); | 
|  | 361   ASSERT_TRUE(extension_a); | 
|  | 362 | 
|  | 363   scoped_refptr<const Extension> extension_b = | 
|  | 364       extension_service()->blacklisted_extensions()->GetByID(info_b_.id()); | 
|  | 365   ASSERT_TRUE(extension_b); | 
|  | 366 | 
|  | 367   scoped_refptr<const Extension> extension_c = | 
|  | 368       extension_service()->extensions()->GetByID(info_c_.id()); | 
|  | 369   ASSERT_TRUE(extension_c); | 
|  | 370 | 
|  | 371   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 372   EXPECT_TRUE(IsBlacklisted(extension_b)); | 
|  | 373   EXPECT_TRUE(IsSafe(extension_c)); | 
|  | 374 | 
|  | 375   // Make sure that we can still blacklist c and unblacklist b. | 
|  | 376   std::vector<std::string> vector_ac(1, extension_a->id()); | 
|  | 377   vector_ac.push_back(extension_c->id()); | 
|  | 378   blacklist()->SetFromUpdater(vector_ac, "8"); | 
|  | 379   base::RunLoop().RunUntilIdle(); | 
|  | 380 | 
|  | 381   EXPECT_TRUE(IsBlacklisted(extension_a)); | 
|  | 382   EXPECT_TRUE(IsSafe(extension_b)); | 
|  | 383   EXPECT_TRUE(IsBlacklisted(extension_c)); | 
|  | 384   EXPECT_TRUE(notifications.CheckNotifications( | 
|  | 385         chrome::NOTIFICATION_EXTENSION_LOADED, | 
|  | 386         chrome::NOTIFICATION_EXTENSION_UNLOADED)); | 
|  | 387 } | 
|  | 388 | 
|  | 389 }  // namespace extensions | 
| OLD | NEW | 
|---|