summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-04 00:55:32 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-04 00:55:32 +0000
commit953620b6b138131552b29163a6a3fa4b3593f083 (patch)
tree6837b6816b4401a665266a96786180c9a038e8a8
parent107248107d7b38e9614e99972b3a99385005956e (diff)
downloadchromium_src-953620b6b138131552b29163a6a3fa4b3593f083.zip
chromium_src-953620b6b138131552b29163a6a3fa4b3593f083.tar.gz
chromium_src-953620b6b138131552b29163a6a3fa4b3593f083.tar.bz2
Reland restrict extension features based on the extension type.
The "chrome_url_overrides" manifest key is now accessible by packaged apps. BUG=101992, 104103 TEST=existing, ManifestTest Review URL: http://codereview.chromium.org/8654001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112914 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/chrome_app_api_browsertest.cc9
-rw-r--r--chrome/browser/extensions/extension_prefs.cc7
-rw-r--r--chrome/browser/extensions/installed_loader.cc3
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/extension.cc269
-rw-r--r--chrome/common/extensions/extension.h52
-rw-r--r--chrome/common/extensions/extension_constants.cc6
-rw-r--r--chrome/common/extensions/extension_constants.h3
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc12
-rw-r--r--chrome/common/extensions/extension_messages.cc6
-rw-r--r--chrome/common/extensions/manifest.cc229
-rw-r--r--chrome/common/extensions/manifest.h112
-rw-r--r--chrome/common/extensions/manifest_unittest.cc391
-rw-r--r--chrome/renderer/extensions/app_bindings.cc3
-rw-r--r--chrome/test/data/extensions/manifest_tests/background_permission.json (renamed from chrome/test/data/extensions/manifest_tests/disallow_hybrid_2.json)0
-rw-r--r--chrome/test/data/extensions/manifest_tests/disallow_hybrid_1.json17
-rw-r--r--chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces.json (renamed from chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_1.json)0
-rw-r--r--chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_2.json10
-rw-r--r--chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_3.json11
20 files changed, 868 insertions, 275 deletions
diff --git a/chrome/browser/extensions/chrome_app_api_browsertest.cc b/chrome/browser/extensions/chrome_app_api_browsertest.cc
index 0f5219e..738afe1 100644
--- a/chrome/browser/extensions/chrome_app_api_browsertest.cc
+++ b/chrome/browser/extensions/chrome_app_api_browsertest.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
@@ -98,10 +99,10 @@ IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
scoped_ptr<DictionaryValue> app_details(
static_cast<DictionaryValue*>(
base::JSONReader::Read(result, false /* allow trailing comma */)));
- // extension->manifest_value() does not contain the id.
+ // extension->manifest() does not contain the id.
app_details->Remove("id", NULL);
EXPECT_TRUE(app_details.get());
- EXPECT_TRUE(app_details->Equals(extension->manifest_value()));
+ EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
// Try to change app.isInstalled. Should silently fail, so
// that isInstalled should have the initial value.
@@ -177,8 +178,8 @@ IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, GetDetailsForFrame) {
scoped_ptr<DictionaryValue> app_details(
static_cast<DictionaryValue*>(
base::JSONReader::Read(json, false /* allow trailing comma */)));
- // extension->manifest_value() does not contain the id.
+ // extension->manifest() does not contain the id.
app_details->Remove("id", NULL);
EXPECT_TRUE(app_details.get());
- EXPECT_TRUE(app_details->Equals(extension->manifest_value()));
+ EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
}
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 6e7a907..875b842 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -1106,7 +1107,7 @@ void ExtensionPrefs::OnExtensionInstalled(
// since it may change on disk.
if (extension->location() != Extension::LOAD) {
extension_dict->Set(kPrefManifest,
- extension->manifest_value()->DeepCopy());
+ extension->manifest()->value()->DeepCopy());
}
if (extension->is_app()) {
@@ -1196,10 +1197,10 @@ void ExtensionPrefs::UpdateManifest(const Extension* extension) {
DictionaryValue* old_manifest = NULL;
bool update_required =
!extension_dict->GetDictionary(kPrefManifest, &old_manifest) ||
- !extension->manifest_value()->Equals(old_manifest);
+ !extension->manifest()->value()->Equals(old_manifest);
if (update_required) {
UpdateExtensionPref(extension->id(), kPrefManifest,
- extension->manifest_value()->DeepCopy());
+ extension->manifest()->value()->DeepCopy());
}
}
}
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index 43a1304..2fb5e2d 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -15,6 +15,7 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/browser/user_metrics.h"
@@ -141,7 +142,7 @@ void InstalledLoader::LoadAllExtensions() {
if (extension.get()) {
extensions_info->at(i)->extension_manifest.reset(
static_cast<DictionaryValue*>(
- extension->manifest_value()->DeepCopy()));
+ extension->manifest()->value()->DeepCopy()));
should_write_prefs = true;
}
}
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 4ab037f..d29f9db 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -138,6 +138,8 @@
'common/extensions/extension_unpacker.h',
'common/extensions/file_browser_handler.cc',
'common/extensions/file_browser_handler.h',
+ 'common/extensions/manifest.cc',
+ 'common/extensions/manifest.h',
'common/extensions/update_manifest.cc',
'common/extensions/update_manifest.h',
'common/extensions/url_pattern.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 89b904d..f543d377 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1959,6 +1959,7 @@
'common/extensions/extension_test_util.cc',
'common/extensions/extension_unittest.cc',
'common/extensions/extension_unpacker_unittest.cc',
+ 'common/extensions/manifest_unittest.cc',
'common/extensions/update_manifest_unittest.cc',
'common/extensions/url_pattern_set_unittest.cc',
'common/extensions/url_pattern_unittest.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index c68280f..1e84be7 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -34,6 +34,7 @@
#include "chrome/common/extensions/extension_sidebar_defaults.h"
#include "chrome/common/extensions/extension_sidebar_utils.h"
#include "chrome/common/extensions/file_browser_handler.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
@@ -85,29 +86,6 @@ static void ConvertHexadecimalToIDAlphabet(std::string* id) {
}
}
-// These keys are allowed by all crx files (apps, extensions, themes, etc).
-static const char* kBaseCrxKeys[] = {
- keys::kCurrentLocale,
- keys::kDefaultLocale,
- keys::kDescription,
- keys::kIcons,
- keys::kManifestVersion,
- keys::kName,
- keys::kPublicKey,
- keys::kSignature,
- keys::kUpdateURL,
- keys::kVersion,
-};
-
-bool IsBaseCrxKey(const std::string& key) {
- for (size_t i = 0; i < arraysize(kBaseCrxKeys); ++i) {
- if (key == kBaseCrxKeys[i])
- return true;
- }
-
- return false;
-}
-
// A singleton object containing global data needed by the extension objects.
class ExtensionConfig {
public:
@@ -253,7 +231,8 @@ scoped_refptr<Extension> Extension::Create(const FilePath& path,
DCHECK(error);
scoped_refptr<Extension> extension = new Extension(path, location);
- if (!extension->InitFromValue(value, flags, error))
+ if (!extension->InitFromValue(new extensions::Manifest(value.DeepCopy()),
+ flags, error))
return NULL;
return extension;
}
@@ -900,31 +879,7 @@ ExtensionSidebarDefaults* Extension::LoadExtensionSidebarDefaults(
return result.release();
}
-bool Extension::ContainsNonThemeKeys(const DictionaryValue& source) const {
- for (DictionaryValue::key_iterator key = source.begin_keys();
- key != source.end_keys(); ++key) {
- if (!IsBaseCrxKey(*key) && *key != keys::kTheme)
- return true;
- }
- return false;
-}
-
-bool Extension::LoadIsApp(const DictionaryValue* manifest,
- std::string* error) {
- if (manifest->HasKey(keys::kApp))
- is_app_ = true;
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnablePlatformApps)) {
- if (manifest->HasKey(keys::kPlatformApp)) {
- manifest->GetBoolean(keys::kPlatformApp, &is_platform_app_);
- }
- }
-
- return true;
-}
-
-bool Extension::LoadExtent(const DictionaryValue* manifest,
+bool Extension::LoadExtent(const extensions::Manifest* manifest,
const char* key,
URLPatternSet* extent,
const char* list_error,
@@ -1001,7 +956,7 @@ bool Extension::LoadExtent(const DictionaryValue* manifest,
return true;
}
-bool Extension::LoadLaunchURL(const DictionaryValue* manifest,
+bool Extension::LoadLaunchURL(const extensions::Manifest* manifest,
std::string* error) {
Value* temp = NULL;
@@ -1099,7 +1054,7 @@ bool Extension::LoadLaunchURL(const DictionaryValue* manifest,
return true;
}
-bool Extension::LoadLaunchContainer(const DictionaryValue* manifest,
+bool Extension::LoadLaunchContainer(const extensions::Manifest* manifest,
std::string* error) {
Value* temp = NULL;
if (!manifest->Get(keys::kLaunchContainer, &temp))
@@ -1154,7 +1109,7 @@ bool Extension::LoadLaunchContainer(const DictionaryValue* manifest,
return true;
}
-bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
+bool Extension::LoadAppIsolation(const extensions::Manifest* manifest,
std::string* error) {
Value* temp = NULL;
if (!manifest->Get(keys::kIsolation, &temp))
@@ -1186,18 +1141,18 @@ bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
return true;
}
-bool Extension::LoadWebIntentServices(const base::DictionaryValue& manifest,
+bool Extension::LoadWebIntentServices(const extensions::Manifest* manifest,
std::string* error) {
DCHECK(error);
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebIntents))
return true;
- if (!manifest.HasKey(keys::kIntents))
+ if (!manifest->HasKey(keys::kIntents))
return true;
DictionaryValue* all_services = NULL;
- if (!manifest.GetDictionary(keys::kIntents, &all_services)) {
+ if (!manifest->GetDictionary(keys::kIntents, &all_services)) {
*error = errors::kInvalidIntents;
return false;
}
@@ -1256,32 +1211,6 @@ bool Extension::LoadWebIntentServices(const base::DictionaryValue& manifest,
return true;
}
-
-bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
- std::string* error) {
- if (web_extent().is_empty())
- return true;
-
- for (DictionaryValue::key_iterator key = manifest->begin_keys();
- key != manifest->end_keys(); ++key) {
- if (!IsBaseCrxKey(*key) &&
- *key != keys::kApp &&
- *key != keys::kPermissions &&
- *key != keys::kOptionalPermissions &&
- *key != keys::kOptionsPage &&
- *key != keys::kBackground &&
- *key != keys::kOfflineEnabled &&
- *key != keys::kMinimumChromeVersion &&
- *key != keys::kRequirements) {
- *error = ExtensionErrorUtils::FormatErrorMessage(
- errors::kHostedAppsCannotIncludeExtensionFeatures, *key);
- return false;
- }
- }
-
- return true;
-}
-
// static
bool Extension::IsTrustedId(const std::string& id) {
// See http://b/4946060 for more details.
@@ -1294,9 +1223,6 @@ Extension::Extension(const FilePath& path, Location location)
offline_enabled_(false),
location_(location),
converted_from_user_script_(false),
- is_theme_(false),
- is_app_(false),
- is_platform_app_(false),
is_storage_isolated_(false),
launch_container_(extension_misc::LAUNCH_TAB),
launch_width_(0),
@@ -1455,10 +1381,14 @@ GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
chrome::kStandardSchemeSeparator + extension_id + "/");
}
-bool Extension::InitFromValue(const DictionaryValue& source, int flags,
+bool Extension::InitFromValue(extensions::Manifest* manifest, int flags,
std::string* error) {
DCHECK(error);
base::AutoLock auto_lock(runtime_data_lock_);
+
+ if (!manifest->ValidateManifest(error))
+ return false;
+
// When strict error checks are enabled, make URL pattern parsing strict.
URLPattern::ParseOption parse_strictness =
(flags & STRICT_ERROR_CHECKS ? URLPattern::ERROR_ON_PORTS
@@ -1469,9 +1399,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
optional_permission_set_ = new ExtensionPermissionSet();
required_permission_set_ = new ExtensionPermissionSet();
- if (source.HasKey(keys::kManifestVersion)) {
+ if (manifest->HasKey(keys::kManifestVersion)) {
int manifest_version = 0;
- if (!source.GetInteger(keys::kManifestVersion, &manifest_version) ||
+ if (!manifest->GetInteger(keys::kManifestVersion, &manifest_version) ||
manifest_version < 1) {
*error = errors::kInvalidManifestVersion;
return false;
@@ -1490,10 +1420,10 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
return false;
}
- if (source.HasKey(keys::kPublicKey)) {
+ if (manifest->HasKey(keys::kPublicKey)) {
std::string public_key_bytes;
- if (!source.GetString(keys::kPublicKey,
- &public_key_) ||
+ if (!manifest->GetString(keys::kPublicKey,
+ &public_key_) ||
!ParsePEMKeyBytes(public_key_,
&public_key_bytes) ||
!GenerateId(public_key_bytes, &id_)) {
@@ -1516,15 +1446,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
creation_flags_ = flags;
- // Make a copy of the manifest so we can store it in prefs.
- manifest_value_.reset(source.DeepCopy());
+ manifest_.reset(manifest);
// Initialize the URL.
extension_url_ = Extension::GetBaseURLFromExtensionId(id());
// Initialize version.
std::string version_str;
- if (!source.GetString(keys::kVersion, &version_str)) {
+ if (!manifest->GetString(keys::kVersion, &version_str)) {
*error = errors::kInvalidVersion;
return false;
}
@@ -1537,7 +1466,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Initialize name.
string16 localized_name;
- if (!source.GetString(keys::kName, &localized_name)) {
+ if (!manifest->GetString(keys::kName, &localized_name)) {
*error = errors::kInvalidName;
return false;
}
@@ -1547,18 +1476,17 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Load App settings. LoadExtent at least has to be done before
// ParsePermissions(), because the valid permissions depend on what type of
// package this is.
- if (!LoadIsApp(manifest_value_.get(), error) ||
- !LoadExtent(manifest_value_.get(), keys::kWebURLs,
- &extent_,
- errors::kInvalidWebURLs, errors::kInvalidWebURL,
- parse_strictness, error) ||
- !EnsureNotHybridApp(manifest_value_.get(), error) ||
- !LoadLaunchURL(manifest_value_.get(), error) ||
- !LoadLaunchContainer(manifest_value_.get(), error)) {
+ if (is_app() &&
+ (!LoadExtent(manifest_.get(), keys::kWebURLs,
+ &extent_,
+ errors::kInvalidWebURLs, errors::kInvalidWebURL,
+ parse_strictness, error) ||
+ !LoadLaunchURL(manifest_.get(), error) ||
+ !LoadLaunchContainer(manifest_.get(), error))) {
return false;
}
- if (is_platform_app_) {
+ if (is_platform_app()) {
if (launch_container() != extension_misc::LAUNCH_SHELL) {
*error = errors::kInvalidLaunchContainerForPlatform;
return false;
@@ -1571,7 +1499,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Initialize the permissions (optional).
ExtensionAPIPermissionSet api_permissions;
URLPatternSet host_permissions;
- if (!ParsePermissions(&source,
+ if (!ParsePermissions(manifest_.get(),
keys::kPermissions,
flags,
error,
@@ -1583,7 +1511,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Initialize the optional permissions (optional).
ExtensionAPIPermissionSet optional_api_permissions;
URLPatternSet optional_host_permissions;
- if (!ParsePermissions(&source,
+ if (!ParsePermissions(manifest_.get(),
keys::kOptionalPermissions,
flags,
error,
@@ -1593,8 +1521,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize description (if present).
- if (source.HasKey(keys::kDescription)) {
- if (!source.GetString(keys::kDescription,
+ if (manifest->HasKey(keys::kDescription)) {
+ if (!manifest->GetString(keys::kDescription,
&description_)) {
*error = errors::kInvalidDescription;
return false;
@@ -1602,9 +1530,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize homepage url (if present).
- if (source.HasKey(keys::kHomepageURL)) {
+ if (manifest->HasKey(keys::kHomepageURL)) {
std::string tmp;
- if (!source.GetString(keys::kHomepageURL, &tmp)) {
+ if (!manifest->GetString(keys::kHomepageURL, &tmp)) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidHomepageURL, "");
return false;
@@ -1620,9 +1548,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize update url (if present).
- if (source.HasKey(keys::kUpdateURL)) {
+ if (manifest->HasKey(keys::kUpdateURL)) {
std::string tmp;
- if (!source.GetString(keys::kUpdateURL, &tmp)) {
+ if (!manifest->GetString(keys::kUpdateURL, &tmp)) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidUpdateURL, "");
return false;
@@ -1638,9 +1566,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Validate minimum Chrome version (if present). We don't need to store this,
// since the extension is not valid if it is incorrect.
- if (source.HasKey(keys::kMinimumChromeVersion)) {
+ if (manifest->HasKey(keys::kMinimumChromeVersion)) {
std::string minimum_version_string;
- if (!source.GetString(keys::kMinimumChromeVersion,
+ if (!manifest->GetString(keys::kMinimumChromeVersion,
&minimum_version_string)) {
*error = errors::kInvalidMinimumChromeVersion;
return false;
@@ -1676,13 +1604,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize converted_from_user_script (if present)
- source.GetBoolean(keys::kConvertedFromUserScript,
- &converted_from_user_script_);
+ if (manifest->HasKey(keys::kConvertedFromUserScript))
+ manifest->GetBoolean(keys::kConvertedFromUserScript,
+ &converted_from_user_script_);
// Initialize icons (if present).
- if (source.HasKey(keys::kIcons)) {
+ if (manifest->HasKey(keys::kIcons)) {
DictionaryValue* icons_value = NULL;
- if (!source.GetDictionary(keys::kIcons, &icons_value)) {
+ if (!manifest->GetDictionary(keys::kIcons, &icons_value)) {
*error = errors::kInvalidIcons;
return false;
}
@@ -1712,20 +1641,12 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize themes (if present).
- is_theme_ = false;
- if (source.HasKey(keys::kTheme)) {
- // Themes cannot contain extension keys.
- if (ContainsNonThemeKeys(source)) {
- *error = errors::kThemesCannotContainExtensions;
- return false;
- }
-
+ if (manifest->HasKey(keys::kTheme)) {
DictionaryValue* theme_value = NULL;
- if (!source.GetDictionary(keys::kTheme, &theme_value)) {
+ if (!manifest->GetDictionary(keys::kTheme, &theme_value)) {
*error = errors::kInvalidTheme;
return false;
}
- is_theme_ = true;
DictionaryValue* images_value = NULL;
if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
@@ -1798,9 +1719,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize plugins (optional).
- if (source.HasKey(keys::kPlugins)) {
+ if (manifest->HasKey(keys::kPlugins)) {
ListValue* list_value = NULL;
- if (!source.GetList(keys::kPlugins, &list_value)) {
+ if (!manifest->GetList(keys::kPlugins, &list_value)) {
*error = errors::kInvalidPlugins;
return false;
}
@@ -1842,9 +1763,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
}
- if (source.HasKey(keys::kNaClModules)) {
+ if (manifest->HasKey(keys::kNaClModules)) {
ListValue* list_value = NULL;
- if (!source.GetList(keys::kNaClModules, &list_value)) {
+ if (!manifest->GetList(keys::kNaClModules, &list_value)) {
*error = errors::kInvalidNaClModules;
return false;
}
@@ -1880,9 +1801,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize content scripts (optional).
- if (source.HasKey(keys::kContentScripts)) {
+ if (manifest->HasKey(keys::kContentScripts)) {
ListValue* list_value;
- if (!source.GetList(keys::kContentScripts, &list_value)) {
+ if (!manifest->GetList(keys::kContentScripts, &list_value)) {
*error = errors::kInvalidContentScriptsList;
return false;
}
@@ -1910,9 +1831,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Initialize page action (optional).
DictionaryValue* page_action_value = NULL;
- if (source.HasKey(keys::kPageActions)) {
+ if (manifest->HasKey(keys::kPageActions)) {
ListValue* list_value = NULL;
- if (!source.GetList(keys::kPageActions, &list_value)) {
+ if (!manifest->GetList(keys::kPageActions, &list_value)) {
*error = errors::kInvalidPageActionsList;
return false;
}
@@ -1931,8 +1852,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
*error = errors::kInvalidPageActionsListSize;
return false;
}
- } else if (source.HasKey(keys::kPageAction)) {
- if (!source.GetDictionary(keys::kPageAction, &page_action_value)) {
+ } else if (manifest->HasKey(keys::kPageAction)) {
+ if (!manifest->GetDictionary(keys::kPageAction, &page_action_value)) {
*error = errors::kInvalidPageAction;
return false;
}
@@ -1947,9 +1868,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize browser action (optional).
- if (source.HasKey(keys::kBrowserAction)) {
+ if (manifest->HasKey(keys::kBrowserAction)) {
DictionaryValue* browser_action_value = NULL;
- if (!source.GetDictionary(keys::kBrowserAction, &browser_action_value)) {
+ if (!manifest->GetDictionary(keys::kBrowserAction, &browser_action_value)) {
*error = errors::kInvalidBrowserAction;
return false;
}
@@ -1961,9 +1882,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize file browser actions (optional).
- if (source.HasKey(keys::kFileBrowserHandlers)) {
+ if (manifest->HasKey(keys::kFileBrowserHandlers)) {
ListValue* file_browser_handlers_value = NULL;
- if (!source.GetList(keys::kFileBrowserHandlers,
+ if (!manifest->GetList(keys::kFileBrowserHandlers,
&file_browser_handlers_value)) {
*error = errors::kInvalidFileBrowserHandler;
return false;
@@ -1977,15 +1898,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// App isolation.
if (api_permissions.count(ExtensionAPIPermission::kExperimental)) {
- if (!LoadAppIsolation(manifest_value_.get(), error))
+ if (is_app() && !LoadAppIsolation(manifest_.get(), error))
return false;
}
// Initialize options page url (optional).
- // Function LoadIsApp() set is_app_ above.
- if (source.HasKey(keys::kOptionsPage)) {
+ if (manifest->HasKey(keys::kOptionsPage)) {
std::string options_str;
- if (!source.GetString(keys::kOptionsPage, &options_str)) {
+ if (!manifest->GetString(keys::kOptionsPage, &options_str)) {
*error = errors::kInvalidOptionsPage;
return false;
}
@@ -2014,9 +1934,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize background url (optional).
- if (source.HasKey(keys::kBackground)) {
+ if (manifest->HasKey(keys::kBackground)) {
std::string background_str;
- if (!source.GetString(keys::kBackground, &background_str)) {
+ if (!manifest->GetString(keys::kBackground, &background_str)) {
*error = errors::kInvalidBackground;
return false;
}
@@ -2047,8 +1967,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
}
- if (source.HasKey(keys::kDefaultLocale)) {
- if (!source.GetString(keys::kDefaultLocale, &default_locale_) ||
+ if (manifest->HasKey(keys::kDefaultLocale)) {
+ if (!manifest->GetString(keys::kDefaultLocale, &default_locale_) ||
!l10n_util::IsValidLocaleSyntax(default_locale_)) {
*error = errors::kInvalidDefaultLocale;
return false;
@@ -2056,9 +1976,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Chrome URL overrides (optional)
- if (source.HasKey(keys::kChromeURLOverrides)) {
+ if (manifest->HasKey(keys::kChromeURLOverrides)) {
DictionaryValue* overrides = NULL;
- if (!source.GetDictionary(keys::kChromeURLOverrides, &overrides)) {
+ if (!manifest->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
*error = errors::kInvalidChromeURLOverrides;
return false;
}
@@ -2100,9 +2020,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
if (api_permissions.count(ExtensionAPIPermission::kExperimental) &&
- source.HasKey(keys::kInputComponents)) {
+ manifest->HasKey(keys::kInputComponents)) {
ListValue* list_value = NULL;
- if (!source.GetList(keys::kInputComponents, &list_value)) {
+ if (!manifest->GetList(keys::kInputComponents, &list_value)) {
*error = errors::kInvalidInputComponents;
return false;
}
@@ -2231,17 +2151,17 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
}
- if (source.HasKey(keys::kOmnibox)) {
- if (!source.GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
+ if (manifest->HasKey(keys::kOmnibox)) {
+ if (!manifest->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
omnibox_keyword_.empty()) {
*error = errors::kInvalidOmniboxKeyword;
return false;
}
}
- if (source.HasKey(keys::kContentSecurityPolicy)) {
+ if (manifest->HasKey(keys::kContentSecurityPolicy)) {
std::string content_security_policy;
- if (!source.GetString(keys::kContentSecurityPolicy,
+ if (!manifest->GetString(keys::kContentSecurityPolicy,
&content_security_policy)) {
*error = errors::kInvalidContentSecurityPolicy;
return false;
@@ -2266,9 +2186,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize devtools page url (optional).
- if (source.HasKey(keys::kDevToolsPage)) {
+ if (manifest->HasKey(keys::kDevToolsPage)) {
std::string devtools_str;
- if (!source.GetString(keys::kDevToolsPage, &devtools_str)) {
+ if (!manifest->GetString(keys::kDevToolsPage, &devtools_str)) {
*error = errors::kInvalidDevToolsPage;
return false;
}
@@ -2280,9 +2200,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize sidebar action (optional).
- if (source.HasKey(keys::kSidebar)) {
+ if (manifest->HasKey(keys::kSidebar)) {
DictionaryValue* sidebar_value = NULL;
- if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) {
+ if (!manifest->GetDictionary(keys::kSidebar, &sidebar_value)) {
*error = errors::kInvalidSidebar;
return false;
}
@@ -2296,9 +2216,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize text-to-speech voices (optional).
- if (source.HasKey(keys::kTtsEngine)) {
+ if (manifest->HasKey(keys::kTtsEngine)) {
DictionaryValue* tts_dict = NULL;
- if (!source.GetDictionary(keys::kTtsEngine, &tts_dict)) {
+ if (!manifest->GetDictionary(keys::kTtsEngine, &tts_dict)) {
*error = errors::kInvalidTts;
return false;
}
@@ -2379,15 +2299,15 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize web intents (optional).
- if (!LoadWebIntentServices(source, error))
+ if (!LoadWebIntentServices(manifest, error))
return false;
// Initialize incognito behavior. Apps default to split mode, extensions
// default to spanning.
incognito_split_mode_ = is_app();
- if (source.HasKey(keys::kIncognito)) {
+ if (manifest->HasKey(keys::kIncognito)) {
std::string value;
- if (!source.GetString(keys::kIncognito, &value)) {
+ if (!manifest->GetString(keys::kIncognito, &value)) {
*error = errors::kInvalidIncognitoBehavior;
return false;
}
@@ -2402,8 +2322,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
// Initialize offline-enabled status. Defaults to false.
- if (source.HasKey(keys::kOfflineEnabled)) {
- if (!source.GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
+ if (manifest->HasKey(keys::kOfflineEnabled)) {
+ if (!manifest->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
*error = errors::kInvalidOfflineEnabled;
return false;
}
@@ -2411,9 +2331,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
// Initialize requirements (optional). Not actually persisted (they're only
// used by the store), but still validated.
- if (source.HasKey(keys::kRequirements)) {
+ if (manifest->HasKey(keys::kRequirements)) {
DictionaryValue* requirements_value = NULL;
- if (!source.GetDictionary(keys::kRequirements, &requirements_value)) {
+ if (!manifest->GetDictionary(keys::kRequirements, &requirements_value)) {
*error = errors::kInvalidRequirements;
return false;
}
@@ -2442,13 +2362,6 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
optional_permission_set_ = new ExtensionPermissionSet(
optional_api_permissions, optional_host_permissions, URLPatternSet());
- // Although |source| is passed in as a const, it's still possible to modify
- // it. This is dangerous since the utility process re-uses |source| after
- // it calls InitFromValue, passing it up to the browser process which calls
- // InitFromValue again. As a result, we need to make sure that nobody
- // accidentally modifies it.
- DCHECK(source.Equals(manifest_value_.get()));
-
return true;
}
@@ -2604,7 +2517,7 @@ GURL Extension::GetIconURL(int size,
return GetResourceURL(path);
}
-bool Extension::ParsePermissions(const DictionaryValue* source,
+bool Extension::ParsePermissions(const extensions::Manifest* source,
const char* key,
int flags,
std::string* error,
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index a0ec6d8..54bff60 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -20,6 +20,7 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_permission_set.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/extensions/url_pattern_set.h"
@@ -374,7 +375,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Parses the host and api permissions from the specified permission |key|
// in the manifest |source|.
- bool ParsePermissions(const base::DictionaryValue* source,
+ bool ParsePermissions(const extensions::Manifest* source,
const char* key,
int flags,
std::string* error,
@@ -531,8 +532,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
}
const GURL& update_url() const { return update_url_; }
const ExtensionIconSet& icons() const { return icons_; }
- const base::DictionaryValue* manifest_value() const {
- return manifest_value_.get();
+ const extensions::Manifest* manifest() const {
+ return manifest_.get();
}
const std::string default_locale() const { return default_locale_; }
const URLOverrideMap& GetChromeURLOverrides() const {
@@ -557,12 +558,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
}
// App-related.
- bool is_app() const { return is_app_; }
- bool is_platform_app() const { return is_platform_app_; }
- bool is_hosted_app() const { return is_app() && !web_extent().is_empty(); }
- bool is_packaged_app() const {
- return !is_platform_app() && is_app() && web_extent().is_empty();
+ bool is_app() const {
+ return is_packaged_app() || is_hosted_app() || is_platform_app();
}
+ bool is_platform_app() const { return manifest()->IsPlatformApp(); }
+ bool is_hosted_app() const { return manifest()->IsHostedApp(); }
+ bool is_packaged_app() const { return manifest()->IsPackagedApp(); }
bool is_storage_isolated() const { return is_app() && is_storage_isolated_; }
const URLPatternSet& web_extent() const { return extent_; }
const std::string& launch_local_path() const { return launch_local_path_; }
@@ -574,7 +575,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
int launch_height() const { return launch_height_; }
// Theme-related.
- bool is_theme() const { return is_theme_; }
+ bool is_theme() const { return manifest()->IsTheme(); }
base::DictionaryValue* GetThemeImages() const { return theme_images_.get(); }
base::DictionaryValue* GetThemeColors() const {return theme_colors_.get(); }
base::DictionaryValue* GetThemeTints() const { return theme_tints_.get(); }
@@ -616,7 +617,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
~Extension();
// Initialize the extension from a parsed manifest.
- bool InitFromValue(const base::DictionaryValue& value, int flags,
+ // Takes ownership of the manifest |value|.
+ bool InitFromValue(extensions::Manifest* value, int flags,
std::string* error);
// Helper function for implementing HasCachedImage/GetCachedImage. A return
@@ -643,24 +645,21 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
UserScript *instance);
// Helpers to load various chunks of the manifest.
- bool LoadIsApp(const base::DictionaryValue* manifest, std::string* error);
- bool LoadExtent(const base::DictionaryValue* manifest,
+ bool LoadExtent(const extensions::Manifest* manifest,
const char* key,
URLPatternSet* extent,
const char* list_error,
const char* value_error,
URLPattern::ParseOption parse_strictness,
std::string* error);
- bool LoadLaunchContainer(const base::DictionaryValue* manifest,
+ bool LoadLaunchContainer(const extensions::Manifest* manifest,
std::string* error);
- bool LoadLaunchURL(const base::DictionaryValue* manifest,
+ bool LoadLaunchURL(const extensions::Manifest* manifest,
std::string* error);
- bool LoadAppIsolation(const base::DictionaryValue* manifest,
+ bool LoadAppIsolation(const extensions::Manifest* manifest,
std::string* error);
- bool LoadWebIntentServices(const base::DictionaryValue& manifest,
+ bool LoadWebIntentServices(const extensions::Manifest* manifest,
std::string* error);
- bool EnsureNotHybridApp(const base::DictionaryValue* manifest,
- std::string* error);
// Helper method to load an ExtensionAction from the page_action or
// browser_action entries in the manifest.
@@ -683,10 +682,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// an extension that has a browser action and a page action.
bool HasMultipleUISurfaces() const;
- // Figures out if a source contains keys not associated with themes - we
- // don't want to allow scripts and such to be bundled with themes.
- bool ContainsNonThemeKeys(const base::DictionaryValue& source) const;
-
// Updates the launch URL and extents for the extension using the given
// |override_url|.
void OverrideLaunchUrl(const GURL& override_url);
@@ -820,9 +815,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// A map of display properties.
scoped_ptr<base::DictionaryValue> theme_display_properties_;
- // Whether the extension is a theme.
- bool is_theme_;
-
// The homepage for this extension. Useful if it is not hosted by Google and
// therefore does not have a Gallery URL.
GURL homepage_url_;
@@ -830,19 +822,13 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// URL for fetching an update manifest
GURL update_url_;
- // A copy of the manifest that this extension was created from.
- scoped_ptr<base::DictionaryValue> manifest_value_;
+ // The manifest that this extension was created from.
+ scoped_ptr<extensions::Manifest> manifest_;
// A map of chrome:// hostnames (newtab, downloads, etc.) to Extension URLs
// which override the handling of those URLs. (see ExtensionOverrideUI).
URLOverrideMap chrome_url_overrides_;
- // Whether this extension uses app features.
- bool is_app_;
-
- // Whether this app uses platform features.
- bool is_platform_app_;
-
// Whether this extension requests isolated storage.
bool is_storage_isolated_;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 2d0e730..f818e62 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -166,8 +166,8 @@ const char kExpectString[] = "Expect string value.";
const char kExperimentalFlagRequired[] =
"Loading extensions with 'experimental' permission requires"
" --enable-experimental-extension-apis command line flag.";
-const char kHostedAppsCannotIncludeExtensionFeatures[] =
- "Hosted apps cannot use the extension feature '*'.";
+const char kFeatureNotAllowed[] =
+ "Feature '*' is not allowed in this type of manifest.";
const char kInvalidAllFrames[] =
"Invalid value for 'content_scripts[*].all_frames'.";
const char kInvalidBackground[] =
@@ -429,8 +429,6 @@ const char kReservedMessageFound[] =
const char kSidebarExperimental[] =
"You must request the 'experimental' permission in order to use the"
" Sidebar API.";
-const char kThemesCannotContainExtensions[] =
- "A theme cannot contain extensions code.";
#if defined(OS_CHROMEOS)
const char kIllegalPlugins[] =
"Extensions cannot install plugins on Chrome OS";
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 8c988f3..abb77f0 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -150,7 +150,7 @@ namespace extension_manifest_errors {
extern const char kDisabledByPolicy[];
extern const char kExperimentalFlagRequired[];
extern const char kExpectString[];
- extern const char kHostedAppsCannotIncludeExtensionFeatures[];
+ extern const char kFeatureNotAllowed[];
extern const char kInvalidAllFrames[];
extern const char kInvalidBackground[];
extern const char kInvalidBackgroundInHostedApp[];
@@ -280,7 +280,6 @@ namespace extension_manifest_errors {
extern const char kOneUISurfaceOnly[];
extern const char kReservedMessageFound[];
extern const char kSidebarExperimental[];
- extern const char kThemesCannotContainExtensions[];
extern const char kWebContentMustBeEnabled[];
#if defined(OS_CHROMEOS)
extern const char kIllegalPlugins[];
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index adc6969..8136dea 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -588,12 +588,8 @@ TEST_F(ExtensionManifestTest, Sidebar) {
extension->sidebar_defaults()->default_page().spec());
}
-TEST_F(ExtensionManifestTest, DisallowHybridApps) {
- LoadAndExpectError("disallow_hybrid_1.json",
- ExtensionErrorUtils::FormatErrorMessage(
- errors::kHostedAppsCannotIncludeExtensionFeatures,
- keys::kBrowserAction));
- LoadAndExpectError("disallow_hybrid_2.json",
+TEST_F(ExtensionManifestTest, BackgroundPermission) {
+ LoadAndExpectError("background_permission.json",
errors::kBackgroundPermissionNeeded);
}
@@ -742,9 +738,7 @@ TEST_F(ExtensionManifestTest, NormalizeIconPaths) {
}
TEST_F(ExtensionManifestTest, DisallowMultipleUISurfaces) {
- LoadAndExpectError("multiple_ui_surfaces_1.json", errors::kOneUISurfaceOnly);
- LoadAndExpectError("multiple_ui_surfaces_2.json", errors::kOneUISurfaceOnly);
- LoadAndExpectError("multiple_ui_surfaces_3.json", errors::kOneUISurfaceOnly);
+ LoadAndExpectError("multiple_ui_surfaces.json", errors::kOneUISurfaceOnly);
}
TEST_F(ExtensionManifestTest, ParseHomepageURLs) {
diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc
index a326289..3adee27 100644
--- a/chrome/common/extensions/extension_messages.cc
+++ b/chrome/common/extensions/extension_messages.cc
@@ -5,6 +5,7 @@
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/manifest.h"
#include "content/public/common/common_param_traits.h"
ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params()
@@ -49,10 +50,11 @@ ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
extension_manifest_keys::kVersion,
};
- // Copy only the data we need.
+ // Copy only the data we need and bypass the manifest type checks.
+ DictionaryValue* source = extension->manifest()->value();
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRendererExtensionKeys); ++i) {
Value* temp = NULL;
- if (extension->manifest_value()->Get(kRendererExtensionKeys[i], &temp))
+ if (source->Get(kRendererExtensionKeys[i], &temp))
manifest->Set(kRendererExtensionKeys[i], temp->DeepCopy());
}
}
diff --git a/chrome/common/extensions/manifest.cc b/chrome/common/extensions/manifest.cc
new file mode 100644
index 0000000..ecd5dfb
--- /dev/null
+++ b/chrome/common/extensions/manifest.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2011 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/common/extensions/manifest.h"
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/string_split.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_error_utils.h"
+
+namespace errors = extension_manifest_errors;
+namespace keys = extension_manifest_keys;
+
+namespace extensions {
+
+namespace {
+
+typedef std::map<std::string, int> RestrictionMap;
+
+struct Restrictions {
+ Restrictions() {
+ // Base keys that all manifests can specify.
+ map[keys::kName] = Manifest::kTypeAll;
+ map[keys::kVersion] = Manifest::kTypeAll;
+ map[keys::kManifestVersion] = Manifest::kTypeAll;
+ map[keys::kDescription] = Manifest::kTypeAll;
+ map[keys::kIcons] = Manifest::kTypeAll;
+ map[keys::kCurrentLocale] = Manifest::kTypeAll;
+ map[keys::kDefaultLocale] = Manifest::kTypeAll;
+ map[keys::kSignature] = Manifest::kTypeAll;
+ map[keys::kUpdateURL] = Manifest::kTypeAll;
+ map[keys::kPublicKey] = Manifest::kTypeAll;
+
+ // Type specific.
+ map[keys::kApp] = Manifest::kTypeHostedApp | Manifest::kTypePackagedApp |
+ Manifest::kTypePlatformApp;
+ map[keys::kTheme] = Manifest::kTypeTheme;
+
+ // keys::kPlatformApp holds a boolean, so all types can define it.
+ map[keys::kPlatformApp] = Manifest::kTypeAll;
+
+ // Extensions only.
+ map[keys::kBrowserAction] = Manifest::kTypeExtension;
+ map[keys::kPageAction] = Manifest::kTypeExtension;
+ map[keys::kPageActions] = Manifest::kTypeExtension;
+
+ // Everything except themes.
+ int all_but_themes = Manifest::kTypeAll - Manifest::kTypeTheme;
+ map[keys::kPermissions] = all_but_themes;
+ map[keys::kOptionalPermissions] = all_but_themes;
+ map[keys::kOptionsPage] = all_but_themes;
+ map[keys::kBackground] = all_but_themes;
+ map[keys::kOfflineEnabled] = all_but_themes;
+ map[keys::kMinimumChromeVersion] = all_but_themes;
+ map[keys::kRequirements] = all_but_themes;
+ map[keys::kConvertedFromUserScript] = all_but_themes;
+ map[keys::kNaClModules] = all_but_themes;
+ map[keys::kPlugins] = all_but_themes;
+
+ // Extensions and packaged apps.
+ int ext_and_packaged =
+ Manifest::kTypeExtension | Manifest::kTypePackagedApp;
+ map[keys::kContentScripts] = ext_and_packaged;
+ map[keys::kOmnibox] = ext_and_packaged;
+ map[keys::kDevToolsPage] = ext_and_packaged;
+ map[keys::kSidebar] = ext_and_packaged;
+ map[keys::kHomepageURL] = ext_and_packaged;
+ map[keys::kChromeURLOverrides] = ext_and_packaged;
+
+ // Extensions, packaged apps and platform apps.
+ int local_apps_and_ext = ext_and_packaged | Manifest::kTypePlatformApp;
+ map[keys::kContentSecurityPolicy] = local_apps_and_ext;
+ map[keys::kFileBrowserHandlers] = local_apps_and_ext;
+ map[keys::kIncognito] = local_apps_and_ext;
+ map[keys::kInputComponents] = local_apps_and_ext;
+ map[keys::kTtsEngine] = local_apps_and_ext;
+ map[keys::kIntents] = local_apps_and_ext;
+ }
+
+ // Returns true if the |key| is recognized.
+ bool IsKnownKey(const std::string& key) const {
+ RestrictionMap::const_iterator i = map.find(key);
+ return i != map.end();
+ }
+
+ // Returns true if the given |key| can be specified by the manifest |type|.
+ bool CanAccessKey(const std::string& key, Manifest::Type type) const {
+ RestrictionMap::const_iterator i = map.find(key);
+ return (i != map.end() && (type & i->second) != 0);
+ }
+
+ RestrictionMap map;
+};
+
+base::LazyInstance<Restrictions> g_restrictions;
+
+} // namespace
+
+// static
+std::set<std::string> Manifest::GetAllKnownKeys() {
+ std::set<std::string> keys;
+ const RestrictionMap& map = g_restrictions.Get().map;
+ for (RestrictionMap::const_iterator i = map.begin(); i != map.end(); i++)
+ keys.insert(i->first);
+ return keys;
+}
+
+Manifest::Manifest(DictionaryValue* value) : value_(value) {}
+Manifest::~Manifest() {}
+
+bool Manifest::ValidateManifest(std::string* error) const {
+ Restrictions restrictions = g_restrictions.Get();
+ Type type = GetType();
+
+ for (DictionaryValue::key_iterator key = value_->begin_keys();
+ key != value_->end_keys(); ++key) {
+ // When validating the extension manifests, we ignore keys that are not
+ // recognized for forward compatibility.
+ if (!restrictions.IsKnownKey(*key)) {
+ // TODO(aa): Consider having an error here in the case of strict error
+ // checking to let developers know when they screw up.
+ continue;
+ }
+
+ if (!restrictions.CanAccessKey(*key, type)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kFeatureNotAllowed, *key);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Manifest::HasKey(const std::string& key) const {
+ Restrictions restrictions = g_restrictions.Get();
+ return restrictions.CanAccessKey(key, GetType()) && value_->HasKey(key);
+}
+
+bool Manifest::Get(
+ const std::string& path, Value** out_value) const {
+ return CanAccessPath(path) && value_->Get(path, out_value);
+}
+
+bool Manifest::GetBoolean(
+ const std::string& path, bool* out_value) const {
+ return CanAccessPath(path) && value_->GetBoolean(path, out_value);
+}
+
+bool Manifest::GetInteger(
+ const std::string& path, int* out_value) const {
+ return CanAccessPath(path) && value_->GetInteger(path, out_value);
+}
+
+bool Manifest::GetString(
+ const std::string& path, std::string* out_value) const {
+ return CanAccessPath(path) && value_->GetString(path, out_value);
+}
+
+bool Manifest::GetString(
+ const std::string& path, string16* out_value) const {
+ return CanAccessPath(path) && value_->GetString(path, out_value);
+}
+
+bool Manifest::GetDictionary(
+ const std::string& path, DictionaryValue** out_value) const {
+ return CanAccessPath(path) && value_->GetDictionary(path, out_value);
+}
+
+bool Manifest::GetList(
+ const std::string& path, ListValue** out_value) const {
+ return CanAccessPath(path) && value_->GetList(path, out_value);
+}
+
+Manifest* Manifest::DeepCopy() const {
+ return new Manifest(value_->DeepCopy());
+}
+
+bool Manifest::Equals(const Manifest* other) const {
+ return other && value_->Equals(other->value());
+}
+
+Manifest::Type Manifest::GetType() const {
+ if (value_->HasKey(keys::kTheme))
+ return kTypeTheme;
+ bool is_platform_app = false;
+ if (value_->GetBoolean(keys::kPlatformApp, &is_platform_app) &&
+ is_platform_app)
+ return kTypePlatformApp;
+ if (value_->HasKey(keys::kApp)) {
+ if (value_->Get(keys::kWebURLs, NULL) ||
+ value_->Get(keys::kLaunchWebURL, NULL))
+ return kTypeHostedApp;
+ else
+ return kTypePackagedApp;
+ } else {
+ return kTypeExtension;
+ }
+}
+
+bool Manifest::IsTheme() const {
+ return GetType() == kTypeTheme;
+}
+
+bool Manifest::IsPlatformApp() const {
+ return GetType() == kTypePlatformApp;
+}
+
+bool Manifest::IsPackagedApp() const {
+ return GetType() == kTypePackagedApp;
+}
+
+bool Manifest::IsHostedApp() const {
+ return GetType() == kTypeHostedApp;
+}
+
+bool Manifest::CanAccessPath(const std::string& path) const {
+ std::vector<std::string> components;
+ base::SplitString(path, '.', &components);
+
+ Restrictions restrictions = g_restrictions.Get();
+ return restrictions.CanAccessKey(components[0], GetType());
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/manifest.h b/chrome/common/extensions/manifest.h
new file mode 100644
index 0000000..fb372708
--- /dev/null
+++ b/chrome/common/extensions/manifest.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 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_COMMON_EXTENSIONS_MANIFEST_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <set>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Value;
+}
+
+namespace extensions {
+
+// Lightweight wrapper around a DictionaryValue representing an extension's
+// manifest. Currently enforces access to properties of the manifest based
+// on manifest type.
+//
+// TODO(aa): Move more smarts about mmanifest into this class over time.
+class Manifest {
+ public:
+ // Flags for matching types of extension manifests.
+ enum Type {
+ kTypeNone = 0,
+
+ // Extension::TYPE_EXTENSION and Extension::TYPE_USER_SCRIPT
+ kTypeExtension = 1 << 0,
+
+ // Extension::TYPE_THEME
+ kTypeTheme = 1 << 1,
+
+ // Extension::TYPE_HOSTED_APP
+ kTypeHostedApp = 1 << 2,
+
+ // Extension::TYPE_PACKAGED_APP
+ kTypePackagedApp = 1 << 3,
+
+ // Extension::TYPE_PLATFORM_APP
+ kTypePlatformApp = 1 << 4,
+
+ // All types
+ kTypeAll = (1 << 5) - 1,
+ };
+
+ // Returns all known keys (this is used for testing).
+ static std::set<std::string> GetAllKnownKeys();
+
+ // Takes over ownership of |value|.
+ explicit Manifest(base::DictionaryValue* value);
+ virtual ~Manifest();
+
+ // Returns true if all keys in the manifest can be specified by
+ // the extension type.
+ bool ValidateManifest(std::string* error) const;
+
+ // Returns the manifest type.
+ Type GetType() const;
+
+ // Returns true if the manifest represents an Extension::TYPE_THEME.
+ bool IsTheme() const;
+
+ // Returns true for Extension::TYPE_PLATFORM_APP
+ bool IsPlatformApp() const;
+
+ // Returns true for Extension::TYPE_PACKAGED_APP.
+ bool IsPackagedApp() const;
+
+ // Returns true for Extension::TYPE_HOSTED_APP.
+ bool IsHostedApp() const;
+
+ // These access the wrapped manifest value, returning false when the property
+ // does not exist or if the manifest type can't access it.
+ bool HasKey(const std::string& key) const;
+ bool Get(const std::string& path, base::Value** out_value) const;
+ bool GetBoolean(const std::string& path, bool* out_value) const;
+ bool GetInteger(const std::string& path, int* out_value) const;
+ bool GetString(const std::string& path, std::string* out_value) const;
+ bool GetString(const std::string& path, string16* out_value) const;
+ bool GetDictionary(const std::string& path,
+ base::DictionaryValue** out_value) const;
+ bool GetList(const std::string& path, base::ListValue** out_value) const;
+
+ // Returns a new Manifest equal to this one, passing ownership to
+ // the caller.
+ Manifest* DeepCopy() const;
+
+ // Returns true if this equals the |other| manifest.
+ bool Equals(const Manifest* other) const;
+
+ // Gets the underlying DictionaryValue representing the manifest.
+ // Note: only know this when you KNOW you don't need the validation.
+ base::DictionaryValue* value() const { return value_.get(); }
+
+ private:
+ // Returns true if the extension can specify the given |path|.
+ bool CanAccessPath(const std::string& path) const;
+
+ scoped_ptr<base::DictionaryValue> value_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_H_
diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc
new file mode 100644
index 0000000..66d4a6d
--- /dev/null
+++ b/chrome/common/extensions/manifest_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright (c) 2011 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/common/extensions/manifest.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_error_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace keys = extension_manifest_keys;
+namespace errors = extension_manifest_errors;
+
+namespace extensions {
+
+namespace {
+
+// Keys that define types.
+const char* kTypeKeys[] = {
+ keys::kApp,
+ keys::kTheme,
+ keys::kPlatformApp
+};
+
+// Keys that are not accesible by themes.
+const char* kNotThemeKeys[] = {
+ keys::kBrowserAction,
+ keys::kPageAction,
+ keys::kPageActions,
+ keys::kChromeURLOverrides,
+ keys::kPermissions,
+ keys::kOptionalPermissions,
+ keys::kOptionsPage,
+ keys::kBackground,
+ keys::kOfflineEnabled,
+ keys::kMinimumChromeVersion,
+ keys::kRequirements,
+ keys::kConvertedFromUserScript,
+ keys::kNaClModules,
+ keys::kPlugins,
+ keys::kContentScripts,
+ keys::kOmnibox,
+ keys::kDevToolsPage,
+ keys::kSidebar,
+ keys::kHomepageURL,
+ keys::kContentSecurityPolicy,
+ keys::kFileBrowserHandlers,
+ keys::kIncognito,
+ keys::kInputComponents,
+ keys::kTtsEngine,
+ keys::kIntents
+};
+
+// Keys that are not accessible by hosted apps.
+const char* kNotHostedAppKeys[] = {
+ keys::kBrowserAction,
+ keys::kPageAction,
+ keys::kPageActions,
+ keys::kChromeURLOverrides,
+ keys::kContentScripts,
+ keys::kOmnibox,
+ keys::kDevToolsPage,
+ keys::kSidebar,
+ keys::kHomepageURL,
+ keys::kContentSecurityPolicy,
+ keys::kFileBrowserHandlers,
+ keys::kIncognito,
+ keys::kInputComponents,
+ keys::kTtsEngine,
+ keys::kIntents
+};
+
+// Keys not accessible by packaged aps.
+const char* kNotPackagedAppKeys[] = {
+ keys::kBrowserAction,
+ keys::kPageAction,
+ keys::kPageActions
+};
+
+// Keys not accessible by platform apps.
+const char* kNotPlatformAppKeys[] = {
+ keys::kBrowserAction,
+ keys::kPageAction,
+ keys::kPageActions,
+ keys::kChromeURLOverrides,
+ keys::kContentScripts,
+ keys::kOmnibox,
+ keys::kDevToolsPage,
+ keys::kSidebar,
+ keys::kHomepageURL,
+};
+
+// Returns all the manifest keys not including those in |filtered| or kTypeKeys.
+std::set<std::string> GetAccessibleKeys(const char* filtered[], size_t length) {
+ std::set<std::string> all_keys = Manifest::GetAllKnownKeys();
+ std::set<std::string> filtered_keys(filtered, filtered + length);
+
+ // Starting with all possible manfiest keys, remove the keys that aren't
+ // accessible for the given type.
+ std::set<std::string> intermediate;
+ std::set_difference(all_keys.begin(), all_keys.end(),
+ filtered_keys.begin(), filtered_keys.end(),
+ std::insert_iterator<std::set<std::string> >(
+ intermediate, intermediate.begin()));
+
+ // Then remove the keys that specify types (app, platform_app, etc.).
+ std::set<std::string> result;
+ std::set<std::string> type_keys(
+ kTypeKeys, kTypeKeys + ARRAYSIZE_UNSAFE(kTypeKeys));
+ std::set_difference(intermediate.begin(), intermediate.end(),
+ type_keys.begin(), type_keys.end(),
+ std::insert_iterator<std::set<std::string> >(
+ result, result.begin()));
+
+ return result;
+}
+
+} // namespace
+
+class ManifestTest : public testing::Test {
+ public:
+ ManifestTest() : default_value_("test") {}
+
+ protected:
+ void AssertType(Manifest* manifest, Manifest::Type type) {
+ EXPECT_EQ(type, manifest->GetType());
+ EXPECT_EQ(type == Manifest::kTypeTheme, manifest->IsTheme());
+ EXPECT_EQ(type == Manifest::kTypePlatformApp, manifest->IsPlatformApp());
+ EXPECT_EQ(type == Manifest::kTypePackagedApp, manifest->IsPackagedApp());
+ EXPECT_EQ(type == Manifest::kTypeHostedApp, manifest->IsHostedApp());
+ }
+
+ void TestRestrictedKeys(Manifest* manifest,
+ const char* restricted_keys[],
+ size_t restricted_keys_length) {
+ // Verify that the keys on the restricted key list for the given manifest
+ // fail validation and are filtered out.
+ DictionaryValue* value = manifest->value();
+ for (size_t i = 0; i < restricted_keys_length; ++i) {
+ std::string error, str;
+ value->Set(restricted_keys[i], Value::CreateStringValue(default_value_));
+ EXPECT_FALSE(manifest->ValidateManifest(&error));
+ EXPECT_EQ(error, ExtensionErrorUtils::FormatErrorMessage(
+ errors::kFeatureNotAllowed, restricted_keys[i]));
+ EXPECT_FALSE(manifest->GetString(restricted_keys[i], &str));
+ EXPECT_TRUE(value->Remove(restricted_keys[i], NULL));
+ }
+ }
+
+ std::string default_value_;
+};
+
+// Verifies that extensions can access the correct keys.
+TEST_F(ManifestTest, Extension) {
+ // Generate the list of keys accessible by extensions.
+ std::set<std::string> extension_keys = GetAccessibleKeys(NULL, 0u);
+
+ // Construct the underlying value using every single key other than those
+ // on the restricted list.. We can use the same value for every key because we
+ // validate only by checking the presence of the keys.
+ DictionaryValue* value = new DictionaryValue();
+ for (std::set<std::string>::iterator i = extension_keys.begin();
+ i != extension_keys.end(); ++i)
+ value->Set(*i, Value::CreateStringValue(default_value_));
+
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string error;
+ EXPECT_TRUE(manifest->ValidateManifest(&error));
+ EXPECT_EQ("", error);
+ AssertType(manifest.get(), Manifest::kTypeExtension);
+
+ // Verify that all the extension keys are accessible.
+ for (std::set<std::string>::iterator i = extension_keys.begin();
+ i != extension_keys.end(); ++i) {
+ std::string value;
+ manifest->GetString(*i, &value);
+ EXPECT_EQ(default_value_, value) << *i;
+ }
+
+ // Test DeepCopy and Equals.
+ scoped_ptr<Manifest> manifest2(manifest->DeepCopy());
+ EXPECT_TRUE(manifest->Equals(manifest2.get()));
+ EXPECT_TRUE(manifest2->Equals(manifest.get()));
+ value->Set("foo", Value::CreateStringValue("blah"));
+ EXPECT_FALSE(manifest->Equals(manifest2.get()));
+}
+
+// Verifies that themes can access the right keys.
+TEST_F(ManifestTest, Theme) {
+ std::set<std::string> theme_keys =
+ GetAccessibleKeys(kNotThemeKeys, ARRAYSIZE_UNSAFE(kNotThemeKeys));
+
+ DictionaryValue* value = new DictionaryValue();
+ for (std::set<std::string>::iterator i = theme_keys.begin();
+ i != theme_keys.end(); ++i)
+ value->Set(*i, Value::CreateStringValue(default_value_));
+
+ std::string theme_key = keys::kTheme + std::string(".test");
+ value->Set(theme_key, Value::CreateStringValue(default_value_));
+
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string error;
+ EXPECT_TRUE(manifest->ValidateManifest(&error));
+ EXPECT_EQ("", error);
+ AssertType(manifest.get(), Manifest::kTypeTheme);
+
+ // Verify that all the theme keys are accessible.
+ std::string str;
+ for (std::set<std::string>::iterator i = theme_keys.begin();
+ i != theme_keys.end(); ++i) {
+ EXPECT_TRUE(manifest->GetString(*i, &str));
+ EXPECT_EQ(default_value_, str) << *i;
+ }
+ EXPECT_TRUE(manifest->GetString(theme_key, &str));
+ EXPECT_EQ(default_value_, str) << theme_key;
+
+ // And that all the other keys fail validation and are filtered out
+ TestRestrictedKeys(manifest.get(), kNotThemeKeys,
+ ARRAYSIZE_UNSAFE(kNotThemeKeys));
+};
+
+// Verifies that platform apps can access the right keys.
+TEST_F(ManifestTest, PlatformApp) {
+ std::set<std::string> platform_keys = GetAccessibleKeys(
+ kNotPlatformAppKeys,
+ ARRAYSIZE_UNSAFE(kNotPlatformAppKeys));
+
+ DictionaryValue* value = new DictionaryValue();
+ for (std::set<std::string>::iterator i = platform_keys.begin();
+ i != platform_keys.end(); ++i)
+ value->Set(*i, Value::CreateStringValue(default_value_));
+
+ value->Set(keys::kPlatformApp, Value::CreateBooleanValue(true));
+
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string error;
+ EXPECT_TRUE(manifest->ValidateManifest(&error));
+ EXPECT_EQ("", error);
+ AssertType(manifest.get(), Manifest::kTypePlatformApp);
+
+ // Verify that all the platform app keys are accessible.
+ std::string str;
+ for (std::set<std::string>::iterator i = platform_keys.begin();
+ i != platform_keys.end(); ++i) {
+ EXPECT_TRUE(manifest->GetString(*i, &str));
+ EXPECT_EQ(default_value_, str) << *i;
+ }
+ bool is_platform_app = false;
+ EXPECT_TRUE(manifest->GetBoolean(keys::kPlatformApp, &is_platform_app));
+ EXPECT_TRUE(is_platform_app) << keys::kPlatformApp;
+
+ // And that all the other keys fail validation and are filtered out.
+ TestRestrictedKeys(manifest.get(), kNotPlatformAppKeys,
+ ARRAYSIZE_UNSAFE(kNotPlatformAppKeys));
+};
+
+// Verifies that hosted apps can access the right keys.
+TEST_F(ManifestTest, HostedApp) {
+ std::set<std::string> keys = GetAccessibleKeys(
+ kNotHostedAppKeys,
+ ARRAYSIZE_UNSAFE(kNotHostedAppKeys));
+
+ DictionaryValue* value = new DictionaryValue();
+ for (std::set<std::string>::iterator i = keys.begin();
+ i != keys.end(); ++i)
+ value->Set(*i, Value::CreateStringValue(default_value_));
+
+ value->Set(keys::kWebURLs, Value::CreateStringValue(default_value_));
+
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string error;
+ EXPECT_TRUE(manifest->ValidateManifest(&error));
+ EXPECT_EQ("", error);
+ AssertType(manifest.get(), Manifest::kTypeHostedApp);
+
+ // Verify that all the hosted app keys are accessible.
+ std::string str;
+ for (std::set<std::string>::iterator i = keys.begin();
+ i != keys.end(); ++i) {
+ EXPECT_TRUE(manifest->GetString(*i, &str));
+ EXPECT_EQ(default_value_, str) << *i;
+ }
+ EXPECT_TRUE(manifest->GetString(keys::kWebURLs, &str));
+ EXPECT_EQ(default_value_, str) << keys::kWebURLs;
+
+ // And that all the other keys fail validation and are filtered out.
+ TestRestrictedKeys(manifest.get(), kNotHostedAppKeys,
+ ARRAYSIZE_UNSAFE(kNotHostedAppKeys));
+};
+
+// Verifies that packaged apps can access the right keys.
+TEST_F(ManifestTest, PackagedApp) {
+ std::set<std::string> keys = GetAccessibleKeys(
+ kNotPackagedAppKeys,
+ ARRAYSIZE_UNSAFE(kNotPackagedAppKeys));
+
+ DictionaryValue* value = new DictionaryValue();
+ for (std::set<std::string>::iterator i = keys.begin();
+ i != keys.end(); ++i)
+ value->Set(*i, Value::CreateStringValue(default_value_));
+ value->Set(keys::kApp, Value::CreateStringValue(default_value_));
+
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string error;
+ EXPECT_TRUE(manifest->ValidateManifest(&error));
+ EXPECT_EQ("", error);
+ AssertType(manifest.get(), Manifest::kTypePackagedApp);
+
+ // Verify that all the packaged app keys are accessible.
+ std::string str;
+ for (std::set<std::string>::iterator i = keys.begin();
+ i != keys.end(); ++i) {
+ EXPECT_TRUE(manifest->GetString(*i, &str));
+ EXPECT_EQ(default_value_, str) << *i;
+ }
+ EXPECT_TRUE(manifest->GetString(keys::kApp, &str));
+ EXPECT_EQ(default_value_, str) << keys::kApp;
+
+ // And that all the other keys fail validation and are filtered out.
+ TestRestrictedKeys(manifest.get(), kNotPackagedAppKeys,
+ ARRAYSIZE_UNSAFE(kNotPackagedAppKeys));
+};
+
+// Verifies that the various getters filter unknown and restricted keys.
+TEST_F(ManifestTest, Getters) {
+ DictionaryValue* value = new DictionaryValue();
+ scoped_ptr<Manifest> manifest(new Manifest(value));
+ std::string unknown_key = "asdfaskldjf";
+
+ // Verify that the key filtering works for each of the getters.
+ // Get and GetBoolean
+ bool expected_bool = true, actual_bool = false;
+ value->Set(unknown_key, Value::CreateBooleanValue(expected_bool));
+ EXPECT_FALSE(manifest->HasKey(unknown_key));
+ EXPECT_FALSE(manifest->GetBoolean(unknown_key, &actual_bool));
+ EXPECT_FALSE(actual_bool);
+ Value* actual_value = NULL;
+ EXPECT_FALSE(manifest->Get(unknown_key, &actual_value));
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+
+ // GetInteger
+ int expected_int = 5, actual_int = 0;
+ value->Set(unknown_key, Value::CreateIntegerValue(expected_int));
+ EXPECT_FALSE(manifest->GetInteger(unknown_key, &actual_int));
+ EXPECT_NE(expected_int, actual_int);
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+
+ // GetString
+ std::string expected_str = "hello", actual_str;
+ value->Set(unknown_key, Value::CreateStringValue(expected_str));
+ EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str));
+ EXPECT_NE(expected_str, actual_str);
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+
+ // GetString (string16)
+ string16 expected_str16(UTF8ToUTF16("hello")), actual_str16;
+ value->Set(unknown_key, Value::CreateStringValue(expected_str16));
+ EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str16));
+ EXPECT_NE(expected_str16, actual_str16);
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+
+ // GetDictionary
+ DictionaryValue* expected_dict = new DictionaryValue();
+ DictionaryValue* actual_dict = NULL;
+ expected_dict->Set("foo", Value::CreateStringValue("bar"));
+ value->Set(unknown_key, expected_dict);
+ EXPECT_FALSE(manifest->GetDictionary(unknown_key, &actual_dict));
+ EXPECT_EQ(NULL, actual_dict);
+ std::string path = unknown_key + ".foo";
+ EXPECT_FALSE(manifest->GetString(path, &actual_str));
+ EXPECT_NE("bar", actual_str);
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+
+ // GetList
+ ListValue* expected_list = new ListValue();
+ ListValue* actual_list = NULL;
+ expected_list->Append(Value::CreateStringValue("blah"));
+ value->Set(unknown_key, expected_list);
+ EXPECT_FALSE(manifest->GetList(unknown_key, &actual_list));
+ EXPECT_EQ(NULL, actual_list);
+ EXPECT_TRUE(value->Remove(unknown_key, NULL));
+}
+
+} // namespace extensions
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index 48893eb..2b3faab 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -12,6 +12,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_helper.h"
@@ -194,7 +195,7 @@ v8::Handle<v8::Value> AppBindingsHandler::GetDetailsForFrameImpl(
return v8::Null();
scoped_ptr<DictionaryValue> manifest_copy(
- extension->manifest_value()->DeepCopy());
+ extension->manifest()->value()->DeepCopy());
manifest_copy->SetString("id", extension->id());
scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
return converter->ToV8Value(manifest_copy.get(),
diff --git a/chrome/test/data/extensions/manifest_tests/disallow_hybrid_2.json b/chrome/test/data/extensions/manifest_tests/background_permission.json
index 06be2c3..06be2c3 100644
--- a/chrome/test/data/extensions/manifest_tests/disallow_hybrid_2.json
+++ b/chrome/test/data/extensions/manifest_tests/background_permission.json
diff --git a/chrome/test/data/extensions/manifest_tests/disallow_hybrid_1.json b/chrome/test/data/extensions/manifest_tests/disallow_hybrid_1.json
deleted file mode 100644
index 3ec899f..0000000
--- a/chrome/test/data/extensions/manifest_tests/disallow_hybrid_1.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "test",
- "version": "1",
- "app": {
- "urls": [
- "http://www.google.com/mail/",
- "http://www.google.com/foobar/"
- ],
- "launch": {
- "web_url": "http://www.google.com/mail/"
- }
- },
- "permissions": [
- "notifications"
- ],
- "browser_action": {}
-}
diff --git a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_1.json b/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces.json
index ecc86eb..ecc86eb 100644
--- a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_1.json
+++ b/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces.json
diff --git a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_2.json b/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_2.json
deleted file mode 100644
index 13c798b..0000000
--- a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_2.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "foo",
- "version": "1",
- "browser_action": {},
- "app": {
- "launch": {
- "local_path": "foo.html"
- }
- }
-}
diff --git a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_3.json b/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_3.json
deleted file mode 100644
index 2317026..0000000
--- a/chrome/test/data/extensions/manifest_tests/multiple_ui_surfaces_3.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "foo",
- "version": "1",
- "browser_action": {},
- "page_action": {},
- "app": {
- "launch": {
- "local_path": "foo.html"
- }
- }
-}