Commit 800d47ea authored by Sebastien Lalancette's avatar Sebastien Lalancette Committed by Commit Bot

Added a feature flag for ChromePromptImpl::DisableExtensions

Details:
Flag name: kChromeCleanupExtensionsFeature
When ON, extensions are included when prompting the user for UwS cleanup.
When OFF, extensions are NOT included when prompting the user for UwS cleanup.

Bug: 904958
Change-Id: Ie483ddb64de11de015429557343f0ee5c4676ff5
Reviewed-on: https://chromium-review.googlesource.com/c/1337790
Commit-Queue: Sebastien Lalancette <seblalancette@chromium.org>
Reviewed-by: default avatarJoe Mason <joenotcharles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609859}
parent 7b5f9f9e
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
#include "components/crx_file/id_util.h" #include "components/crx_file/id_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "extensions/browser/uninstall_reason.h" #include "extensions/browser/uninstall_reason.h"
...@@ -53,35 +54,41 @@ void ChromePromptImpl::PromptUser( ...@@ -53,35 +54,41 @@ void ChromePromptImpl::PromptUser(
using ExtensionCollection = ChromeCleanerScannerResults::ExtensionCollection; using ExtensionCollection = ChromeCleanerScannerResults::ExtensionCollection;
if (on_prompt_user_) { if (on_prompt_user_) {
if (base::FeatureList::IsEnabled(kChromeCleanupExtensionsFeature) &&
extension_ids) {
extension_ids_ = extension_ids.value();
} else {
extension_ids_.clear();
}
ChromeCleanerScannerResults scanner_results( ChromeCleanerScannerResults scanner_results(
FileCollection(files_to_delete.begin(), files_to_delete.end()), FileCollection(files_to_delete.begin(), files_to_delete.end()),
registry_keys ? RegistryKeyCollection(registry_keys->begin(), registry_keys ? RegistryKeyCollection(registry_keys->begin(),
registry_keys->end()) registry_keys->end())
: RegistryKeyCollection(), : RegistryKeyCollection(),
extension_ids extension_ids_.empty() ? ExtensionCollection()
? ExtensionCollection(extension_ids->begin(), extension_ids->end()) : ExtensionCollection(extension_ids_.begin(),
: ExtensionCollection()); extension_ids_.end()));
if (extension_ids.has_value()) {
extension_ids_ = extension_ids;
}
std::move(on_prompt_user_) std::move(on_prompt_user_)
.Run(std::move(scanner_results), std::move(callback)); .Run(std::move(scanner_results), std::move(callback));
} }
} }
// The |extensions_ids| passed to this function are a subset of the
// |extension_ids| passed to PromptUser because the extensions are not all
// disabled at the same time.
void ChromePromptImpl::DisableExtensions( void ChromePromptImpl::DisableExtensions(
const std::vector<base::string16>& extension_ids, const std::vector<base::string16>& extension_ids,
ChromePrompt::DisableExtensionsCallback callback) { ChromePrompt::DisableExtensionsCallback callback) {
if (extension_service_ == nullptr || !extension_ids_.has_value()) { if (extension_service_ == nullptr || extension_ids_.empty()) {
std::move(callback).Run(false); std::move(callback).Run(false);
return; return;
} }
// Clear the stored extension_ids by moving it onto this stack frame, // Clear the stored extension_ids by moving it onto this stack frame,
// so subsequent calls will fail. // so subsequent calls will fail.
base::Optional<std::vector<base::string16>> optional_verified_extension_ids{}; std::vector<base::string16> verified_extension_ids{};
extension_ids_.swap(optional_verified_extension_ids); extension_ids_.swap(verified_extension_ids);
std::vector<base::string16> verified_extension_ids =
optional_verified_extension_ids.value();
bool ids_are_valid = std::all_of( bool ids_are_valid = std::all_of(
extension_ids.begin(), extension_ids.end(), extension_ids.begin(), extension_ids.end(),
[this, &verified_extension_ids](const base::string16& id) { [this, &verified_extension_ids](const base::string16& id) {
......
...@@ -50,7 +50,7 @@ class ChromePromptImpl : public chrome_cleaner::mojom::ChromePrompt { ...@@ -50,7 +50,7 @@ class ChromePromptImpl : public chrome_cleaner::mojom::ChromePrompt {
mojo::Binding<chrome_cleaner::mojom::ChromePrompt> binding_; mojo::Binding<chrome_cleaner::mojom::ChromePrompt> binding_;
extensions::ExtensionService* extension_service_; extensions::ExtensionService* extension_service_;
OnPromptUser on_prompt_user_; OnPromptUser on_prompt_user_;
base::Optional<std::vector<base::string16>> extension_ids_; std::vector<base::string16> extension_ids_;
DISALLOW_COPY_AND_ASSIGN(ChromePromptImpl); DISALLOW_COPY_AND_ASSIGN(ChromePromptImpl);
}; };
......
...@@ -4,13 +4,20 @@ ...@@ -4,13 +4,20 @@
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_chrome_prompt_impl.h" #include "chrome/browser/safe_browsing/chrome_cleaner/srt_chrome_prompt_impl.h"
#include <vector>
#include "base/feature_list.h"
#include "base/location.h" #include "base/location.h"
#include "base/macros.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/extension_service_test_base.h"
#include "chrome/browser/extensions/test_extension_service.h" #include "chrome/browser/extensions/test_extension_service.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/mock_extension_system.h" #include "extensions/browser/mock_extension_system.h"
...@@ -23,16 +30,34 @@ namespace safe_browsing { ...@@ -23,16 +30,34 @@ namespace safe_browsing {
class ExtensionDeletionTest : public extensions::ExtensionServiceTestBase { class ExtensionDeletionTest : public extensions::ExtensionServiceTestBase {
public: public:
ExtensionDeletionTest() { InitializeEmptyExtensionService(); }
~ExtensionDeletionTest() override = default; ~ExtensionDeletionTest() override = default;
void SetUp() override {} void SetUp() override {
const std::vector<base::Feature> enabled_features = GetEnabledFeatures();
const std::vector<base::Feature> disabled_features = GetDisabledFeatures();
private: scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
DISALLOW_COPY_AND_ASSIGN(ExtensionDeletionTest);
}; ExtensionServiceTestBase::SetUp();
}
TEST_F(ExtensionDeletionTest, DisableExtensionTest) { protected:
// Protected constructor to make this class abstract. Following
// implementations will be explicit about the feature flag state.
ExtensionDeletionTest() { InitializeEmptyExtensionService(); }
// Hooks to set up feature flags.
virtual const std::vector<base::Feature> GetEnabledFeatures() const {
return {};
}
virtual const std::vector<base::Feature> GetDisabledFeatures() const {
return {};
}
// Creates some extension IDs and registers them in the service.
std::vector<base::string16> PopulateExtensionIds(
bool installExtensions = true) {
std::vector<base::string16> extension_ids{}; std::vector<base::string16> extension_ids{};
extensions::ExtensionService* extension_service = this->service(); extensions::ExtensionService* extension_service = this->service();
for (int i = 40; i < 43; i++) { for (int i = 40; i < 43; i++) {
...@@ -42,12 +67,55 @@ TEST_F(ExtensionDeletionTest, DisableExtensionTest) { ...@@ -42,12 +67,55 @@ TEST_F(ExtensionDeletionTest, DisableExtensionTest) {
.Build(); .Build();
auto id = extension->id(); auto id = extension->id();
extension_ids.push_back(base::UTF8ToUTF16(id)); extension_ids.push_back(base::UTF8ToUTF16(id));
if (installExtensions) {
extension_service->AddExtension(extension.get()); extension_service->AddExtension(extension.get());
extension_service->EnableExtension(id); extension_service->EnableExtension(id);
} }
}
return extension_ids;
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(ExtensionDeletionTest);
};
class ExtensionDeletionEnabledTest : public ExtensionDeletionTest {
public:
ExtensionDeletionEnabledTest() = default;
~ExtensionDeletionEnabledTest() override = default;
protected:
const std::vector<base::Feature> GetEnabledFeatures() const override {
return {kChromeCleanupExtensionsFeature};
}
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionDeletionEnabledTest);
};
class ExtensionDeletionDisabledTest : public ExtensionDeletionTest {
public:
ExtensionDeletionDisabledTest() = default;
~ExtensionDeletionDisabledTest() override = default;
protected:
const std::vector<base::Feature> GetDisabledFeatures() const override {
return {kChromeCleanupExtensionsFeature};
}
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionDeletionDisabledTest);
};
TEST_F(ExtensionDeletionEnabledTest, DisableExtensionTest) {
std::vector<base::string16> extension_ids = PopulateExtensionIds();
extensions::ExtensionService* extension_service = this->service();
std::unique_ptr<ChromePromptImpl> chrome_prompt = std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr, std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing()); base::DoNothing(), base::DoNothing());
chrome_prompt->PromptUser({}, {}, extension_ids, base::DoNothing()); chrome_prompt->PromptUser({}, {}, extension_ids, base::DoNothing());
std::vector<base::string16> extensions_to_disable{extension_ids[0]}; std::vector<base::string16> extensions_to_disable{extension_ids[0]};
chrome_prompt->DisableExtensions( chrome_prompt->DisableExtensions(
...@@ -81,22 +149,13 @@ TEST_F(ExtensionDeletionTest, DisableExtensionTest) { ...@@ -81,22 +149,13 @@ TEST_F(ExtensionDeletionTest, DisableExtensionTest) {
nullptr); nullptr);
} }
TEST_F(ExtensionDeletionTest, CantDeleteNonPromptedExtensions) { TEST_F(ExtensionDeletionEnabledTest, CantDeleteNonPromptedExtensions) {
std::vector<base::string16> extension_ids{}; std::vector<base::string16> extension_ids = PopulateExtensionIds();
extensions::ExtensionService* extension_service = this->service(); extensions::ExtensionService* extension_service = this->service();
for (int i = 40; i < 43; i++) {
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder(base::NumberToString(i))
.SetManifestKey("version", "1")
.Build();
auto id = extension->id();
extension_ids.push_back(base::UTF8ToUTF16(id));
extension_service->AddExtension(extension.get());
extension_service->EnableExtension(id);
}
std::unique_ptr<ChromePromptImpl> chrome_prompt = std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr, std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing()); base::DoNothing(), base::DoNothing());
std::vector<base::string16> extensions_to_disable{extension_ids[0]}; std::vector<base::string16> extensions_to_disable{extension_ids[0]};
chrome_prompt->DisableExtensions( chrome_prompt->DisableExtensions(
extensions_to_disable, extensions_to_disable,
...@@ -140,23 +199,14 @@ TEST_F(ExtensionDeletionTest, CantDeleteNonPromptedExtensions) { ...@@ -140,23 +199,14 @@ TEST_F(ExtensionDeletionTest, CantDeleteNonPromptedExtensions) {
nullptr); nullptr);
} }
TEST_F(ExtensionDeletionTest, EmptyDeletionTest) { TEST_F(ExtensionDeletionEnabledTest, EmptyDeletionTest) {
std::vector<base::string16> extension_ids{}; std::vector<base::string16> extension_ids = PopulateExtensionIds();
extensions::ExtensionService* extension_service = this->service(); extensions::ExtensionService* extension_service = this->service();
std::unique_ptr<ChromePromptImpl> chrome_prompt = std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr, std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing()); base::DoNothing(), base::DoNothing());
chrome_prompt->PromptUser({}, {}, extension_ids, base::DoNothing()); chrome_prompt->PromptUser({}, {}, extension_ids, base::DoNothing());
for (int i = 40; i < 43; i++) {
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder(base::NumberToString(i))
.SetManifestKey("version", "1")
.Build();
auto id = extension->id();
extension_ids.push_back(base::UTF8ToUTF16(id));
extension_service->AddExtension(extension.get());
extension_service->EnableExtension(id);
}
chrome_prompt->DisableExtensions( chrome_prompt->DisableExtensions(
{}, base::BindOnce([](bool result) { EXPECT_TRUE(result); })); {}, base::BindOnce([](bool result) { EXPECT_TRUE(result); }));
EXPECT_TRUE(extension_service->IsExtensionEnabled( EXPECT_TRUE(extension_service->IsExtensionEnabled(
...@@ -167,22 +217,13 @@ TEST_F(ExtensionDeletionTest, EmptyDeletionTest) { ...@@ -167,22 +217,13 @@ TEST_F(ExtensionDeletionTest, EmptyDeletionTest) {
base::UTF16ToUTF8(extension_ids[2]))); base::UTF16ToUTF8(extension_ids[2])));
} }
TEST_F(ExtensionDeletionTest, BadlyFormattedDeletionTest) { TEST_F(ExtensionDeletionEnabledTest, BadlyFormattedDeletionTest) {
std::vector<base::string16> extension_ids{}; std::vector<base::string16> extension_ids = PopulateExtensionIds();
extensions::ExtensionService* extension_service = this->service(); extensions::ExtensionService* extension_service = this->service();
std::unique_ptr<ChromePromptImpl> chrome_prompt = std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr, std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing()); base::DoNothing(), base::DoNothing());
for (int i = 40; i < 43; i++) {
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder(base::NumberToString(i))
.SetManifestKey("version", "1")
.Build();
auto id = extension->id();
extension_ids.push_back(base::UTF8ToUTF16(id));
extension_service->AddExtension(extension.get());
extension_service->EnableExtension(id);
}
chrome_prompt->DisableExtensions( chrome_prompt->DisableExtensions(
{L"bad-extension-id"}, {L"bad-extension-id"},
base::BindOnce([](bool result) { EXPECT_FALSE(result); })); base::BindOnce([](bool result) { EXPECT_FALSE(result); }));
...@@ -193,23 +234,41 @@ TEST_F(ExtensionDeletionTest, BadlyFormattedDeletionTest) { ...@@ -193,23 +234,41 @@ TEST_F(ExtensionDeletionTest, BadlyFormattedDeletionTest) {
base::BindOnce([](bool result) { EXPECT_FALSE(result); })); base::BindOnce([](bool result) { EXPECT_FALSE(result); }));
} }
TEST_F(ExtensionDeletionTest, NotInstalledExtensionTest) { TEST_F(ExtensionDeletionEnabledTest, NotInstalledExtensionTest) {
std::vector<base::string16> extension_ids{}; // Don't actually install the extension
std::vector<base::string16> extension_ids = PopulateExtensionIds(false);
extensions::ExtensionService* extension_service = this->service(); extensions::ExtensionService* extension_service = this->service();
std::unique_ptr<ChromePromptImpl> chrome_prompt = std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr, std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing()); base::DoNothing(), base::DoNothing());
for (int i = 40; i < 43; i++) {
// Don't actually install the extension
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder(base::NumberToString(i))
.SetManifestKey("version", "1")
.Build();
auto id = extension->id();
extension_ids.push_back(base::UTF8ToUTF16(id));
}
chrome_prompt->DisableExtensions( chrome_prompt->DisableExtensions(
extension_ids, base::BindOnce([](bool result) { EXPECT_FALSE(result); })); extension_ids, base::BindOnce([](bool result) { EXPECT_FALSE(result); }));
} }
TEST_F(ExtensionDeletionDisabledTest, CannotDisableExtensionTest) {
std::vector<base::string16> extension_ids = PopulateExtensionIds();
extensions::ExtensionService* extension_service = this->service();
std::unique_ptr<ChromePromptImpl> chrome_prompt =
std::make_unique<ChromePromptImpl>(extension_service, nullptr,
base::DoNothing(), base::DoNothing());
chrome_prompt->PromptUser({}, {}, extension_ids, base::DoNothing());
std::vector<base::string16> extensions_to_disable{extension_ids[0]};
chrome_prompt->DisableExtensions(
extensions_to_disable,
base::BindOnce([](bool result) { EXPECT_FALSE(result); }));
// Even if we called disable, the extension doesn't get disabled.
EXPECT_NE(extension_service->GetInstalledExtension(
base::UTF16ToUTF8(extension_ids[0])),
nullptr);
EXPECT_NE(extension_service->GetInstalledExtension(
base::UTF16ToUTF8(extension_ids[1])),
nullptr);
EXPECT_NE(extension_service->GetInstalledExtension(
base::UTF16ToUTF8(extension_ids[2])),
nullptr);
}
} // namespace safe_browsing } // namespace safe_browsing
...@@ -47,6 +47,9 @@ const base::Feature kChromeCleanupDistributionFeature{ ...@@ -47,6 +47,9 @@ const base::Feature kChromeCleanupDistributionFeature{
const base::Feature kChromeCleanupQuarantineFeature{ const base::Feature kChromeCleanupQuarantineFeature{
"ChromeCleanupQuarantine", base::FEATURE_DISABLED_BY_DEFAULT}; "ChromeCleanupQuarantine", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kChromeCleanupExtensionsFeature{
"ChromeCleanupExtensions", base::FEATURE_DISABLED_BY_DEFAULT};
bool IsInSRTPromptFieldTrialGroups() { bool IsInSRTPromptFieldTrialGroups() {
return !base::StartsWith(base::FieldTrialList::FindFullName(kSRTPromptTrial), return !base::StartsWith(base::FieldTrialList::FindFullName(kSRTPromptTrial),
kSRTPromptOffGroup, base::CompareCase::SENSITIVE); kSRTPromptOffGroup, base::CompareCase::SENSITIVE);
......
...@@ -74,6 +74,10 @@ extern const base::Feature kChromeCleanupDistributionFeature; ...@@ -74,6 +74,10 @@ extern const base::Feature kChromeCleanupDistributionFeature;
// files. // files.
extern const base::Feature kChromeCleanupQuarantineFeature; extern const base::Feature kChromeCleanupQuarantineFeature;
// Extensions cleanup feature. When enabled, Chrome Cleaner will prompt users
// for, and cleanup, bad extensions.
extern const base::Feature kChromeCleanupExtensionsFeature;
extern const char kSRTPromptTrial[]; extern const char kSRTPromptTrial[];
// Returns true if this Chrome is in a field trial group which shows the SRT // Returns true if this Chrome is in a field trial group which shows the SRT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment