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

Make extension install status also checks other policies.

Extension with blocked required permissions should be blocked.
Extension with manifest type that is not whitelisted should be
blocked.

These blockings have higher priority than installation mode.

The function will be used by webstore API.

Bug: 1083500
Change-Id: I477dbf7bf2084cfa93c432295f226fb2900ca179
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2204685
Commit-Queue: Owen Min <zmin@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774174}
parent 4bb85fae
......@@ -16,18 +16,76 @@
#include "extensions/common/extension.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/permission_set.h"
namespace extensions {
namespace {
// A helper function to determine if an extension from web store with given
// information should be blocked by enterprise policy. It checks extension's
// installation mode, permission and manifest type.
// Returns true if the extension |mode| is blocked, removed or allowed by
// wildcard/update_url but blocked by |manifest type| or |required permissions|.
bool IsExtensionInstallBlockedByPolicy(
ExtensionManagement* extension_management,
ExtensionManagement::InstallationMode mode,
const ExtensionId& extension_id,
const std::string& update_url,
Manifest::Type manifest_type,
const PermissionSet& required_permissions) {
switch (mode) {
case ExtensionManagement::INSTALLATION_BLOCKED:
case ExtensionManagement::INSTALLATION_REMOVED:
return true;
case ExtensionManagement::INSTALLATION_FORCED:
case ExtensionManagement::INSTALLATION_RECOMMENDED:
return false;
case ExtensionManagement::INSTALLATION_ALLOWED:
break;
}
if (extension_management->IsInstallationExplicitlyAllowed(extension_id))
return false;
// Extension is allowed by wildcard or update_url, checks required permissions
// and manifest type.
// TODO(crbug.com/1088021): Find out the right way to handle extension policy
// priority.
if (!extension_management->IsAllowedManifestType(manifest_type,
extension_id)) {
return true;
}
if (!extension_management->IsPermissionSetAllowed(extension_id, update_url,
required_permissions)) {
return true;
}
return false;
}
} // namespace
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile) {
return GetWebstoreExtensionInstallStatus(
extension_id, profile, Manifest::Type::TYPE_UNKNOWN, PermissionSet());
}
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile,
const Manifest::Type manifest_type,
const PermissionSet& required_permission_set) {
DCHECK(crx_file::id_util::IdIsValid(extension_id));
if (ExtensionPrefs::Get(profile)->HasDisableReason(
extension_id, disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED)) {
return kCustodianApprovalRequired;
}
const GURL update_url = extension_urls::GetWebstoreUpdateUrl();
ExtensionManagement* extension_management =
ExtensionManagementFactory::GetForBrowserContext(profile);
// Always use webstore update url to check the installation mode because this
......@@ -35,8 +93,8 @@ ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
// |Extension| instance. Note that we don't handle the case where an offstore
// extension with an identical ID is installed.
ExtensionManagement::InstallationMode mode =
extension_management->GetInstallationMode(
extension_id, extension_urls::GetWebstoreUpdateUrl().spec());
extension_management->GetInstallationMode(extension_id,
update_url.spec());
if (mode == ExtensionManagement::INSTALLATION_FORCED ||
mode == ExtensionManagement::INSTALLATION_RECOMMENDED)
......@@ -56,7 +114,9 @@ ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
// kBlockedByPolicy, kCanRequest or kRequestPending instead of kDisabled.
// By doing so, user can still request an installed and policy blocked
// extension.
if (mode == ExtensionManagement::INSTALLATION_ALLOWED) {
if (!IsExtensionInstallBlockedByPolicy(
extension_management, mode, extension_id, update_url.spec(),
manifest_type, required_permission_set)) {
if (registry->disabled_extensions().Contains(extension_id))
return kDisabled;
return kInstallable;
......@@ -67,6 +127,8 @@ ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
if (!profile->GetPrefs()->GetBoolean(prefs::kCloudExtensionRequestEnabled))
return kBlockedByPolicy;
// An extension which is explicitly blocked by enterprise policy can't be
// requested anymore.
if (extension_management->IsInstallationExplicitlyBlocked(extension_id))
return kBlockedByPolicy;
......
......@@ -6,11 +6,14 @@
#define CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_EXTENSION_INSTALL_STATUS_H_
#include "extensions/common/extension_id.h"
#include "extensions/common/manifest.h"
class Profile;
namespace extensions {
class PermissionSet;
enum ExtensionInstallStatus {
// Extension is blocked by policy but can be requested.
kCanRequest,
......@@ -34,12 +37,24 @@ enum ExtensionInstallStatus {
kForceInstalled
};
// Returns the Extension install status for an Chrome web store extension with
// |extension_id| in |profile|.
// Returns the Extension install status for a Chrome web store extension with
// |extension_id| in |profile|. Note that this function won't check whether the
// extension's manifest type or required permissions are blocked by enterprise
// policy. type blocking or permission blocking. Please use this function only
// if manifest file is not available.
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile);
// Returns the Extension install status for a Chrome web store extension with
// |extension_id| in |profile|. Also check if |manifest_type| or any permission
// in |required_permission_set| is blocked by enterprise policy.
ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
const ExtensionId& extension_id,
Profile* profile,
const Manifest::Type manifest_type,
const PermissionSet& required_permission_set);
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_EXTENSION_INSTALL_STATUS_H_
......@@ -217,16 +217,22 @@ bool ExtensionManagement::IsAllowedManifestType(
APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
const Extension* extension) const {
std::string update_url;
if (extension->manifest()->GetString(manifest_keys::kUpdateURL, &update_url))
return GetBlockedAPIPermissions(extension->id(), update_url);
return GetBlockedAPIPermissions(extension->id(), std::string());
}
APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
const ExtensionId& extension_id,
const std::string& update_url) const {
// Fetch per-extension blocked permissions setting.
auto iter_id = settings_by_id_.find(extension->id());
auto iter_id = settings_by_id_.find(extension_id);
// Fetch per-update-url blocked permissions setting.
std::string update_url;
auto iter_update_url = settings_by_update_url_.end();
if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
&update_url)) {
if (!update_url.empty())
iter_update_url = settings_by_update_url_.find(update_url);
}
if (iter_id != settings_by_id_.end() &&
iter_update_url != settings_by_update_url_.end()) {
......@@ -295,7 +301,18 @@ std::unique_ptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
bool ExtensionManagement::IsPermissionSetAllowed(
const Extension* extension,
const PermissionSet& perms) const {
for (auto* blocked_api : GetBlockedAPIPermissions(extension)) {
std::string update_url;
if (extension->manifest()->GetString(manifest_keys::kUpdateURL, &update_url))
return IsPermissionSetAllowed(extension->id(), update_url, perms);
return IsPermissionSetAllowed(extension->id(), std::string(), perms);
}
bool ExtensionManagement::IsPermissionSetAllowed(
const ExtensionId& extension_id,
const std::string& update_url,
const PermissionSet& perms) const {
for (const extensions::APIPermission* blocked_api :
GetBlockedAPIPermissions(extension_id, update_url)) {
if (perms.HasAPIPermission(blocked_api->id()))
return false;
}
......
......@@ -96,8 +96,8 @@ class ExtensionManagement : public KeyedService {
// Returns installation mode for an extension.
InstallationMode GetInstallationMode(const Extension* extension) const;
// Returns installation mode for an extension with id |id| and updated with
// |update_url|.
// Returns installation mode for an extension with id |extension_id| and
// updated with |update_url|.
InstallationMode GetInstallationMode(const ExtensionId& extension_id,
const std::string& update_url) const;
......@@ -133,6 +133,12 @@ class ExtensionManagement : public KeyedService {
// Returns the list of blocked API permissions for |extension|.
APIPermissionSet GetBlockedAPIPermissions(const Extension* extension) const;
// Returns the list of blocked API permissions for an extension with id
// |extension_id| and updated with |update_url|.
APIPermissionSet GetBlockedAPIPermissions(
const ExtensionId& extension_id,
const std::string& update_url) const;
// Returns the list of hosts blocked by policy for |extension|.
const URLPatternSet& GetPolicyBlockedHosts(const Extension* extension) const;
......@@ -174,6 +180,12 @@ class ExtensionManagement : public KeyedService {
bool IsPermissionSetAllowed(const Extension* extension,
const PermissionSet& perms) const;
// Returns true if every permission in |perms| is allowed for an extension
// with id |extension_id| and updated with |update_url|.
bool IsPermissionSetAllowed(const ExtensionId& extension_id,
const std::string& update_url,
const PermissionSet& perms) const;
// Returns true if |extension| meets the minimum required version set for it.
// If there is no such requirement set for it, returns true as well.
// If false is returned and |required_version| is not null, the minimum
......
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