blob: 3f57cb6b260e67646c219ee20383b57426ffa548 [file] [log] [blame]
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/run_loop.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_notification_observer.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
namespace extensions {
namespace {
// Stores the paths to CRX files of extensions, and the extension's ID.
// Use arbitrary extensions; we're just testing blacklisting behavior.
class CrxInfo {
public:
CrxInfo(const std::string& path, const std::string& id)
: path_(path), id_(id) {}
const std::string& path() { return path_; }
const std::string& id() { return id_; }
private:
const std::string path_;
const std::string id_;
};
} // namespace
class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest {
public:
ExtensionBlacklistBrowserTest()
: info_a_("install/install.crx", "ogdbpbegnmindpdjfafpmpicikegejdj"),
info_b_("autoupdate/v1.crx", "ogjcoiohnmldgjemafoockdghcjciccf"),
info_c_("hosted_app.crx", "kbmnembihfiondgfjekmnmcbddelicoi"),
// Just disable the safe browsing altogether.
// TODO(kalman): a different approach will be needed when the blacklist
// comes entirely from safe browsing.
scoped_blacklist_database_manager_(
scoped_refptr<SafeBrowsingDatabaseManager>(NULL)) {}
virtual ~ExtensionBlacklistBrowserTest() {}
protected:
// Returns whether |extension| is strictly safe: in one of ExtensionService's
// non-blacklisted extension sets, and not in its blacklisted extensions.
testing::AssertionResult IsSafe(const Extension* extension) {
std::string id = extension->id();
int include_mask = ExtensionService::INCLUDE_EVERYTHING &
~ExtensionService::INCLUDE_BLACKLISTED;
if (!extension_service()->GetExtensionById(id, include_mask))
return testing::AssertionFailure() << id << " is safe";
return IsInValidState(extension);
}
// Returns whether |extension| is strictly blacklisted: in ExtensionService's
// blacklist, and not in any of its other extension sets.
testing::AssertionResult IsBlacklisted(const Extension* extension) {
std::string id = extension->id();
if (!extension_service()->blacklisted_extensions()->Contains(id))
return testing::AssertionFailure() << id << " is not blacklisted";
return IsInValidState(extension);
}
std::set<std::string> GetTestExtensionIDs() {
std::set<std::string> extension_ids;
extension_ids.insert(info_a_.id());
extension_ids.insert(info_b_.id());
extension_ids.insert(info_c_.id());
return extension_ids;
}
Blacklist* blacklist() {
return ExtensionSystem::Get(profile())->blacklist();
}
CrxInfo info_a_;
CrxInfo info_b_;
CrxInfo info_c_;
private:
// Returns whether |extension| is either installed or blacklisted, but
// neither both nor neither.
testing::AssertionResult IsInValidState(const Extension* extension) {
std::string id = extension->id();
bool is_blacklisted =
extension_service()->blacklisted_extensions()->Contains(id);
int safe_mask = ExtensionService::INCLUDE_EVERYTHING &
~ExtensionService::INCLUDE_BLACKLISTED;
bool is_safe = extension_service()->GetExtensionById(id, safe_mask) != NULL;
if (is_blacklisted && is_safe) {
return testing::AssertionFailure() <<
id << " is both safe and in blacklisted_extensions";
}
if (!is_blacklisted && !is_safe) {
return testing::AssertionFailure() <<
id << " is neither safe nor in blacklisted_extensions";
}
return testing::AssertionSuccess();
}
Blacklist::ScopedDatabaseManagerForTest scoped_blacklist_database_manager_;
};
// Stage 1: blacklisting when there weren't any extensions installed when the
// browser started.
IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) {
ExtensionNotificationObserver notifications(
content::NotificationService::AllSources(), GetTestExtensionIDs());
scoped_refptr<const Extension> extension_a =
InstallExtension(test_data_dir_.AppendASCII(info_a_.path()), 1);
scoped_refptr<const Extension> extension_b =
InstallExtension(test_data_dir_.AppendASCII(info_b_.path()), 1);
scoped_refptr<const Extension> extension_c =
InstallExtension(test_data_dir_.AppendASCII(info_c_.path()), 1);
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_INSTALLED,
chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_INSTALLED,
chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_INSTALLED,
chrome::NOTIFICATION_EXTENSION_LOADED));
ASSERT_TRUE(extension_a.get());
ASSERT_TRUE(extension_b.get());
ASSERT_EQ(info_a_.id(), extension_a->id());
ASSERT_EQ(info_b_.id(), extension_b->id());
ASSERT_EQ(info_c_.id(), extension_c->id());
std::vector<std::string> empty_vector;
std::vector<std::string> vector_a(1, info_a_.id());
std::vector<std::string> vector_b(1, info_b_.id());
std::vector<std::string> vector_c(1, info_c_.id());
std::vector<std::string> vector_ab(1, info_a_.id());
vector_ab.push_back(info_b_.id());
std::vector<std::string> vector_bc(1, info_b_.id());
vector_bc.push_back(info_c_.id());
std::vector<std::string> vector_abc(1, info_a_.id());
vector_abc.push_back(info_b_.id());
vector_abc.push_back(info_c_.id());
EXPECT_TRUE(IsSafe(extension_a.get()));
EXPECT_TRUE(IsSafe(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
// Blacklist a and b.
blacklist()->SetFromUpdater(vector_ab, "1");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_UNLOADED,
chrome::NOTIFICATION_EXTENSION_UNLOADED));
// Un-blacklist a.
blacklist()->SetFromUpdater(vector_b, "2");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsSafe(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
EXPECT_TRUE(
notifications.CheckNotifications(chrome::NOTIFICATION_EXTENSION_LOADED));
// Blacklist a then switch with c.
blacklist()->SetFromUpdater(vector_ab, "3");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_UNLOADED));
blacklist()->SetFromUpdater(vector_bc, "4");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsSafe(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsBlacklisted(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_UNLOADED));
// Add a to blacklist.
blacklist()->SetFromUpdater(vector_abc, "5");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsBlacklisted(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_UNLOADED));
// Clear blacklist.
blacklist()->SetFromUpdater(empty_vector, "6");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsSafe(extension_a.get()));
EXPECT_TRUE(IsSafe(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
EXPECT_TRUE(
notifications.CheckNotifications(chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_LOADED));
// Add a and b back again for the next test.
blacklist()->SetFromUpdater(vector_ab, "7");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_UNLOADED,
chrome::NOTIFICATION_EXTENSION_UNLOADED));
}
// Stage 2: blacklisting with extensions A and B having been installed,
// with A actually in the blacklist.
IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) {
ExtensionNotificationObserver notifications(
content::Source<Profile>(profile()), GetTestExtensionIDs());
scoped_refptr<const Extension> extension_a =
extension_service()->blacklisted_extensions()->GetByID(info_a_.id());
ASSERT_TRUE(extension_a.get());
scoped_refptr<const Extension> extension_b =
extension_service()->blacklisted_extensions()->GetByID(info_b_.id());
ASSERT_TRUE(extension_b.get());
scoped_refptr<const Extension> extension_c =
extension_service()->extensions()->GetByID(info_c_.id());
ASSERT_TRUE(extension_c.get());
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsBlacklisted(extension_b.get()));
EXPECT_TRUE(IsSafe(extension_c.get()));
// Make sure that we can still blacklist c and unblacklist b.
std::vector<std::string> vector_ac(1, extension_a->id());
vector_ac.push_back(extension_c->id());
blacklist()->SetFromUpdater(vector_ac, "8");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBlacklisted(extension_a.get()));
EXPECT_TRUE(IsSafe(extension_b.get()));
EXPECT_TRUE(IsBlacklisted(extension_c.get()));
EXPECT_TRUE(notifications.CheckNotifications(
chrome::NOTIFICATION_EXTENSION_LOADED,
chrome::NOTIFICATION_EXTENSION_UNLOADED));
}
} // namespace extensions