Commit f42d0946 authored by Owen Min's avatar Owen Min Committed by Commit Bot

Add a util function to get CWS extension install status

The util function returns the extension status based on if it's installed,
disabled, terminated, blocked by policy and request status. This function
will be used by CWS extension detail page.

Bug: 1006899
Change-Id: I365caad7d99bb693aa664846f3d3a64ce424526d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1894100Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Commit-Queue: Owen Min <zmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712755}
parent e56fb409
...@@ -410,6 +410,8 @@ jumbo_static_library("extensions") { ...@@ -410,6 +410,8 @@ jumbo_static_library("extensions") {
"api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.h", "api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.h",
"api/webrtc_logging_private/webrtc_logging_private_api.cc", "api/webrtc_logging_private/webrtc_logging_private_api.cc",
"api/webrtc_logging_private/webrtc_logging_private_api.h", "api/webrtc_logging_private/webrtc_logging_private_api.h",
"api/webstore_private/extension_install_status.cc",
"api/webstore_private/extension_install_status.h",
"api/webstore_private/webstore_private_api.cc", "api/webstore_private/webstore_private_api.cc",
"api/webstore_private/webstore_private_api.h", "api/webstore_private/webstore_private_api.h",
"app_data_migrator.cc", "app_data_migrator.cc",
......
// Copyright 2019 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 "chrome/browser/extensions/api/webstore_private/extension_install_status.h"
#include "base/memory/scoped_refptr.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "components/crx_file/id_util.h"
#include "components/prefs/pref_service.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile) {
DCHECK(crx_file::id_util::IdIsValid(extension_id));
ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
if (registry->enabled_extensions().Contains(extension_id))
return kEnabled;
if (registry->terminated_extensions().Contains(extension_id))
return kTerminated;
if (registry->blacklisted_extensions().Contains(extension_id))
return kBlacklisted;
ExtensionManagement* extension_management =
ExtensionManagementFactory::GetForBrowserContext(profile);
ExtensionManagement::InstallationMode mode =
extension_management->GetInstallationMode(
extension_id, extension_urls::GetDefaultWebstoreUpdateUrl().spec());
// If an installed extension is disabled due to policy, returns
// kBlockedByPolicy, kCanRequest or kRequestPending instead of kDisabled.
// By doing so, user can still request an installed and policy blocked
// extension.
if (mode == ExtensionManagement::INSTALLATION_FORCED ||
mode == ExtensionManagement::INSTALLATION_RECOMMENDED ||
mode == ExtensionManagement::INSTALLATION_ALLOWED) {
if (registry->disabled_extensions().Contains(extension_id))
return kDisabled;
return kInstallable;
}
// The ability to request extension installs is not available if the extension
// request policy is disabled
if (!profile->GetPrefs()->GetBoolean(prefs::kCloudExtensionRequestEnabled))
return kBlockedByPolicy;
if (extension_management->IsInstallationExplicitlyBlocked(extension_id))
return kBlockedByPolicy;
const auto pending_list =
profile->GetPrefs()->GetList(prefs::kCloudExtensionRequestIds)->GetList();
if (std::any_of(pending_list.begin(), pending_list.end(),
[&extension_id](const base::Value& pending_id) {
return pending_id.GetString() == extension_id;
})) {
return kRequestPending;
}
return kCanRequest;
}
} // namespace extensions
// Copyright 2019 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_EXTENSION_INSTALL_STATUS_H_
#define CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_EXTENSION_INSTALL_STATUS_H_
#include "extensions/common/extension_id.h"
class Profile;
namespace extensions {
enum ExtensionInstallStatus {
// Extension is blocked by policy but can be requested.
kCanRequest,
// Extension install request has been sent and is waiting to be reviewed.
kRequestPending,
// Extension is blocked by policy and can not be requested.
kBlockedByPolicy,
// Extension is not installed and has not not been blocked by policy.
kInstallable,
// Extension has been installed and it's enabled.
kEnabled,
// Extension has been installed but it's disabled and not blocked by policy.
kDisabled,
// Extension has been installed but it's terminated.
kTerminated,
// Extension is blacklisted.
kBlacklisted
};
// Returns the Extension install status for an Chrome web store extension with
// |extension_id| in |profile|.
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile);
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_EXTENSION_INSTALL_STATUS_H_
// Copyright 2019 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 "chrome/browser/extensions/api/webstore_private/extension_install_status.h"
#include <vector>
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/extension_builder.h"
namespace extensions {
namespace {
constexpr char kExtensionId[] = "abcdefghijklmnopabcdefghijklmnop";
constexpr char kExtensionSettingsWithUpdateUrlBlocking[] = R"({
"update_url:https://clients2.google.com/service/update2/crx": {
"installation_mode": "blocked"
}
})";
constexpr char kExtensionSettingsWithWildcardBlocking[] = R"({
"*": {
"installation_mode": "blocked"
}
})";
constexpr char kExtensionSettingsWithIdBlocked[] = R"({
"abcdefghijklmnopabcdefghijklmnop": {
"installation_mode": "blocked"
}
})";
constexpr char kExtensionSettingsWithIdAllowed[] = R"({
"abcdefghijklmnopabcdefghijklmnop": {
"installation_mode": "allowed"
}
})";
} // namespace
class ExtensionInstallStatusTest : public BrowserWithTestWindowTest {
public:
ExtensionInstallStatusTest() = default;
std::string GenerateArgs(const char* id) {
return base::StringPrintf(R"(["%s"])", id);
}
scoped_refptr<const Extension> CreateExtension(const ExtensionId& id) {
return ExtensionBuilder("extension").SetID(id).Build();
}
void SetExtensionSettings(const std::string& settings_string) {
base::Optional<base::Value> settings =
base::JSONReader::Read(settings_string);
ASSERT_TRUE(settings);
SetPolicy(pref_names::kExtensionManagement,
base::Value::ToUniquePtrValue(std::move(*settings)));
}
void SetPolicy(const std::string& pref_name,
std::unique_ptr<base::Value> value) {
profile()->GetTestingPrefService()->SetManagedPref(pref_name,
std::move(value));
}
void AddExtensionsToPendingList(const std::vector<ExtensionId>& ids) {
base::Value::ListStorage id_values;
for (const auto& id : ids)
id_values.push_back(base::Value(id));
profile()->GetTestingPrefService()->SetUserPref(
prefs::kCloudExtensionRequestIds,
std::make_unique<base::Value>(std::move(id_values)));
}
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallStatusTest);
};
TEST_F(ExtensionInstallStatusTest, ExtensionEnabled) {
ExtensionRegistry::Get(profile())->AddEnabled(CreateExtension(kExtensionId));
EXPECT_EQ(ExtensionInstallStatus::kEnabled,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionDisabled) {
ExtensionRegistry::Get(profile())->AddDisabled(CreateExtension(kExtensionId));
EXPECT_EQ(ExtensionInstallStatus::kDisabled,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionInstalledButDisabledByPolicy) {
ExtensionRegistry::Get(profile())->AddDisabled(CreateExtension(kExtensionId));
SetExtensionSettings(kExtensionSettingsWithIdBlocked);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionTerminated) {
ExtensionRegistry::Get(profile())->AddTerminated(
CreateExtension(kExtensionId));
EXPECT_EQ(ExtensionInstallStatus::kTerminated,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlacklisted) {
ExtensionRegistry::Get(profile())->AddBlacklisted(
CreateExtension(kExtensionId));
EXPECT_EQ(ExtensionInstallStatus::kBlacklisted,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionAllowed) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlockedByUpdateUrl) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetExtensionSettings(kExtensionSettingsWithUpdateUrlBlocking);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlockedByWildcard) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetExtensionSettings(kExtensionSettingsWithWildcardBlocking);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlockedById) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetExtensionSettings(kExtensionSettingsWithIdBlocked);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest,
ExtensionBlockByUpdateUrlWithRequestEnabled) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
SetExtensionSettings(kExtensionSettingsWithUpdateUrlBlocking);
EXPECT_EQ(ExtensionInstallStatus::kCanRequest,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlockByWildcardWithRequestEnabled) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
SetExtensionSettings(kExtensionSettingsWithWildcardBlocking);
EXPECT_EQ(ExtensionInstallStatus::kCanRequest,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, ExtensionBlockByIdWithRequestEnabled) {
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
// An extension that is blocked by its ID can't be requested anymore.
SetExtensionSettings(kExtensionSettingsWithIdBlocked);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, PendingExtenisonIsWaitingToBeReviewed) {
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
std::vector<ExtensionId> ids = {kExtensionId};
AddExtensionsToPendingList(ids);
// The extension is blocked by wildcard and pending approval.
SetExtensionSettings(kExtensionSettingsWithWildcardBlocking);
EXPECT_EQ(ExtensionInstallStatus::kRequestPending,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, PendingExtenisonIsApproved) {
// Extension is approved but not installed, returns as INSTALLABLE.
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
std::vector<ExtensionId> ids = {kExtensionId};
SetExtensionSettings(kExtensionSettingsWithIdAllowed);
EXPECT_EQ(ExtensionInstallStatus::kInstallable,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
TEST_F(ExtensionInstallStatusTest, PendingExtenisonIsRejected) {
// Extension is rejected, it should be moved from the pending list soon.
SetPolicy(prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
std::vector<ExtensionId> ids = {kExtensionId};
SetExtensionSettings(kExtensionSettingsWithIdBlocked);
EXPECT_EQ(ExtensionInstallStatus::kBlockedByPolicy,
GetWebstoreExtensionInstallStatus(kExtensionId, profile()));
}
} // namespace extensions
...@@ -116,14 +116,21 @@ bool ExtensionManagement::BlacklistedByDefault() const { ...@@ -116,14 +116,21 @@ bool ExtensionManagement::BlacklistedByDefault() const {
ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode( ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
const Extension* extension) const { const Extension* extension) const {
std::string update_url;
if (extension->manifest()->GetString(manifest_keys::kUpdateURL, &update_url))
return GetInstallationMode(extension->id(), update_url);
return GetInstallationMode(extension->id(), std::string());
}
ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
const ExtensionId& extension_id,
const std::string& update_url) const {
// Check per-extension installation mode setting first. // Check per-extension installation mode setting first.
auto iter_id = settings_by_id_.find(extension->id()); auto iter_id = settings_by_id_.find(extension_id);
if (iter_id != settings_by_id_.end()) if (iter_id != settings_by_id_.end())
return iter_id->second->installation_mode; return iter_id->second->installation_mode;
std::string update_url;
// Check per-update-url installation mode setting. // Check per-update-url installation mode setting.
if (extension->manifest()->GetString(manifest_keys::kUpdateURL, if (!update_url.empty()) {
&update_url)) {
auto iter_update_url = settings_by_update_url_.find(update_url); auto iter_update_url = settings_by_update_url_.find(update_url);
if (iter_update_url != settings_by_update_url_.end()) if (iter_update_url != settings_by_update_url_.end())
return iter_update_url->second->installation_mode; return iter_update_url->second->installation_mode;
......
...@@ -96,6 +96,11 @@ class ExtensionManagement : public KeyedService { ...@@ -96,6 +96,11 @@ class ExtensionManagement : public KeyedService {
// Returns installation mode for an extension. // Returns installation mode for an extension.
InstallationMode GetInstallationMode(const Extension* extension) const; InstallationMode GetInstallationMode(const Extension* extension) const;
// Returns installation mode for an extension with id |id| and updated with
// |update_url|.
InstallationMode GetInstallationMode(const ExtensionId& extension_id,
const std::string& update_url) const;
// Returns the force install list, in format specified by // Returns the force install list, in format specified by
// ExternalPolicyLoader::AddExtension(). // ExternalPolicyLoader::AddExtension().
std::unique_ptr<base::DictionaryValue> GetForceInstallList() const; std::unique_ptr<base::DictionaryValue> GetForceInstallList() const;
......
...@@ -4269,6 +4269,7 @@ test("unit_tests") { ...@@ -4269,6 +4269,7 @@ test("unit_tests") {
"../browser/extensions/api/web_request/web_request_api_unittest.cc", "../browser/extensions/api/web_request/web_request_api_unittest.cc",
"../browser/extensions/api/web_request/web_request_event_details_unittest.cc", "../browser/extensions/api/web_request/web_request_event_details_unittest.cc",
"../browser/extensions/api/web_request/web_request_permissions_unittest.cc", "../browser/extensions/api/web_request/web_request_permissions_unittest.cc",
"../browser/extensions/api/webstore_private/extension_install_status_unittest.cc",
"../browser/extensions/app_data_migrator_unittest.cc", "../browser/extensions/app_data_migrator_unittest.cc",
"../browser/extensions/blacklist_check_unittest.cc", "../browser/extensions/blacklist_check_unittest.cc",
"../browser/extensions/blacklist_state_fetcher_unittest.cc", "../browser/extensions/blacklist_state_fetcher_unittest.cc",
......
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