Make ungranted extension permissions not be an error, but show a warning
in the extension developer mode.
For example, the following permissions wouldn't be granted:
- foobar
It's not a real permission.
- http://google.com:80
It's a malformed URL pattern.
- storage
(If manifest_version == 1) because manifest_version must be >= 2.
- storage
(If on stable/beta channel) because it's only supported on dev channel.
BUG=121826
TEST=unit_tests --gtest_fitler='*ExtensionManifestTest*'
Fake beta channel and try installing stylizr
Review URL: http://codereview.chromium.org/10067028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133144 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 7f30fea..8dab806 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -4,8 +4,6 @@
#include "chrome/common/extensions/extension.h"
-#include <algorithm>
-
#include "base/base64.h"
#include "base/basictypes.h"
#include "base/command_line.h"
@@ -20,6 +18,7 @@
#include "base/string_piece.h"
#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
@@ -3321,14 +3320,11 @@
extensions::Feature::ConvertLocation(location()),
manifest_version());
if (availability != extensions::Feature::IS_AVAILABLE) {
- // We special case hosted apps because some old versions of Chrome did
- // not return errors here and we ended up with extensions in the store
- // containing bad data: crbug.com/101993.
- if (availability != extensions::Feature::INVALID_TYPE ||
- !is_hosted_app()) {
- *error = ASCIIToUTF16(feature->GetErrorMessage(availability));
- return false;
- }
+ // Don't fail, but warn the developer that the manifest contains
+ // unrecognized permissions. This may happen legitimately if the
+ // extensions requests platform- or channel-specific permissions.
+ install_warnings_.push_back(feature->GetErrorMessage(availability));
+ continue;
}
if (permission->id() == ExtensionAPIPermission::kExperimental) {
@@ -3339,6 +3335,7 @@
}
api_permissions->insert(permission->id());
+ continue;
}
// Check if it's a host pattern permission.
@@ -3367,17 +3364,14 @@
}
host_permissions->AddPattern(pattern);
+ continue;
}
- // If it's not a host permission, then it's probably an unknown API
- // permission. Do not throw an error so extensions can retain
- // backwards compatability (http://crbug.com/42742).
- // TODO(jstritar): We can improve error messages by adding better
- // validation of API permissions here.
- // TODO(skerner): Consider showing the reason |permission_str| is not
- // a valid URL pattern if it is almost valid. For example, if it has
- // a valid scheme, and failed to parse because it has a port, show an
- // error.
+ // It's probably an unknown API permission. Do not throw an error so
+ // extensions can retain backwards compatability (http://crbug.com/42742).
+ install_warnings_.push_back(base::StringPrintf(
+ "Permission '%s' is unknown or URL pattern is malformed.",
+ permission_str.c_str()));
}
}
return true;
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 23c02931..29ddca6d 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -6,12 +6,12 @@
#define CHROME_COMMON_EXTENSIONS_EXTENSION_H_
#pragma once
+#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
-#include <algorithm>
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
@@ -615,6 +615,9 @@
const ExtensionPermissionSet* required_permission_set() const {
return required_permission_set_.get();
}
+ const std::vector<std::string>& install_warnings() const {
+ return install_warnings_;
+ }
const GURL& update_url() const { return update_url_; }
const ExtensionIconSet& icons() const { return icons_; }
const extensions::Manifest* manifest() const {
@@ -908,6 +911,9 @@
// The extension's required / default set of permissions.
scoped_refptr<const ExtensionPermissionSet> required_permission_set_;
+ // Any warnings that occurred when trying to create/parse the extension.
+ std::vector<std::string> install_warnings_;
+
// The icons for the extension.
ExtensionIconSet icons_;
diff --git a/chrome/common/extensions/feature.cc b/chrome/common/extensions/feature.cc
index e2fd613..9f683d7 100644
--- a/chrome/common/extensions/feature.cc
+++ b/chrome/common/extensions/feature.cc
@@ -215,27 +215,44 @@
case IS_AVAILABLE:
return "";
case NOT_FOUND_IN_WHITELIST:
- return "Not allowed for specified extension ID.";
+ return base::StringPrintf(
+ "'%s' is not allowed for specified extension ID.",
+ name().c_str());
case INVALID_TYPE:
- return "Not allowed for specified package type (theme, app, etc.).";
+ return base::StringPrintf(
+ "'%s' is not allowed for specified package type (theme, app, etc.).",
+ name().c_str());
case INVALID_CONTEXT:
- return "Not allowed for specified context type content script, extension "
- "page, web page, etc.).";
+ return base::StringPrintf(
+ "'%s' is not allowed for specified context type content script, "
+ " extension page, web page, etc.).",
+ name().c_str());
case INVALID_LOCATION:
- return "Not allowed for specified install location.";
+ return base::StringPrintf(
+ "'%s' is not allowed for specified install location.",
+ name().c_str());
case INVALID_PLATFORM:
- return "Not allowed for specified platform.";
+ return base::StringPrintf(
+ "'%s' is not allowed for specified platform.",
+ name().c_str());
case INVALID_MIN_MANIFEST_VERSION:
- return base::StringPrintf("Requires manifest version of at least %d.",
- min_manifest_version_);
+ return base::StringPrintf(
+ "'%s' requires manifest version of at least %d.",
+ name().c_str(),
+ min_manifest_version_);
case INVALID_MAX_MANIFEST_VERSION:
- return base::StringPrintf("Requires manifest version of %d or lower.",
- max_manifest_version_);
+ return base::StringPrintf(
+ "'%s' requires manifest version of %d or lower.",
+ name().c_str(),
+ max_manifest_version_);
case NOT_PRESENT:
- return "Requires a different Feature that is not present.";
+ return base::StringPrintf(
+ "'%s' requires a different Feature that is not present.",
+ name().c_str());
case UNSUPPORTED_CHANNEL:
return base::StringPrintf(
- "Google Chrome %s channel or newer is required, but current is %s.",
+ "'%s' requires Google Chrome %s channel or newer but current is %s.",
+ name().c_str(),
GetChannelName(channel_).c_str(),
GetChannelName(g_channel.Get().channel).c_str());
}
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
index dc8567b..dc994dc 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -25,7 +25,7 @@
LoadAndExpectError(
"init_invalid_platform_app_3.json",
"Feature 'platform_app' is not accessible. "
- "Requires manifest version of at least 2.");
+ "'platform_app' requires manifest version of at least 2.");
}
TEST_F(ExtensionManifestTest, CertainApisRequirePlatformApps) {
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
index 9900b472..8acb36c6 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
@@ -19,12 +19,18 @@
base_manifest.Set(keys::kPermissions, permissions);
}
- std::string kManifestVersionError("Requires manifest version of at least 2.");
+ std::string kManifestVersionError =
+ "'storage' requires manifest version of at least 2.";
// Extension with no manifest version cannot use storage API.
{
Manifest manifest(&base_manifest, "test");
- LoadAndExpectError(manifest, kManifestVersionError);
+ scoped_refptr<Extension> extension = LoadAndExpectSuccess(manifest);
+ if (extension.get()) {
+ std::vector<std::string> warnings;
+ warnings.push_back(kManifestVersionError);
+ EXPECT_EQ(warnings, extension->install_warnings());
+ }
}
// Extension with manifest version 1 cannot use storage API.
@@ -34,7 +40,12 @@
manifest_with_version.MergeDictionary(&base_manifest);
Manifest manifest(&manifest_with_version, "test");
- LoadAndExpectError(manifest, kManifestVersionError);
+ scoped_refptr<Extension> extension = LoadAndExpectSuccess(manifest);
+ if (extension.get()) {
+ std::vector<std::string> warnings;
+ warnings.push_back(kManifestVersionError);
+ EXPECT_EQ(warnings, extension->install_warnings());
+ }
}
// Extension with manifest version 2 *can* use storage API.
@@ -44,6 +55,10 @@
manifest_with_version.MergeDictionary(&base_manifest);
Manifest manifest(&manifest_with_version, "test");
- LoadAndExpectSuccess(manifest);
+ scoped_refptr<Extension> extension = LoadAndExpectSuccess(manifest);
+ if (extension.get()) {
+ std::vector<std::string> empty;
+ EXPECT_EQ(empty, extension->install_warnings());
+ }
}
}
diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc
index f7842052..5cabe03e 100644
--- a/chrome/common/extensions/manifest_unittest.cc
+++ b/chrome/common/extensions/manifest_unittest.cc
@@ -74,6 +74,7 @@
EXPECT_FALSE(manifest->ValidateManifest(&error));
{
Feature feature;
+ feature.set_name("background_page");
feature.set_max_manifest_version(1);
EXPECT_EQ(ExtensionErrorUtils::FormatErrorMessageUTF16(
errors::kFeatureNotAllowed,