diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-02 22:46:47 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-02 22:46:47 +0000 |
commit | 6d1c43b3e0324f6e870d9fc642f6135d990aee26 (patch) | |
tree | f263ef45ec4cff6e6e88ae39d64459b26360f6e7 /chrome/common | |
parent | 73dca1b6e24c63f52cc2aaf44afdfb7c21df93a1 (diff) | |
download | chromium_src-6d1c43b3e0324f6e870d9fc642f6135d990aee26.zip chromium_src-6d1c43b3e0324f6e870d9fc642f6135d990aee26.tar.gz chromium_src-6d1c43b3e0324f6e870d9fc642f6135d990aee26.tar.bz2 |
Revert "Restrict extension features based on the extension type."
This breaks some ChromeOS tests. Among the log output:
"Feature 'chrome_url_overrides' is not allowed in this type of manifest."
Original review: http://codereview.chromium.org/8654001
BUG=101992, 104103, chromium-os:23709
TEST=no
Review URL: http://codereview.chromium.org/8786004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112808 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/extensions/extension.cc | 269 | ||||
-rw-r--r-- | chrome/common/extensions/extension.h | 52 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.cc | 6 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.h | 3 | ||||
-rw-r--r-- | chrome/common/extensions/extension_manifests_unittest.cc | 12 | ||||
-rw-r--r-- | chrome/common/extensions/extension_messages.cc | 6 | ||||
-rw-r--r-- | chrome/common/extensions/manifest.cc | 229 | ||||
-rw-r--r-- | chrome/common/extensions/manifest.h | 112 | ||||
-rw-r--r-- | chrome/common/extensions/manifest_unittest.cc | 392 |
9 files changed, 228 insertions, 853 deletions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 1e84be7..c68280f 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -34,7 +34,6 @@ #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" @@ -86,6 +85,29 @@ 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: @@ -231,8 +253,7 @@ scoped_refptr<Extension> Extension::Create(const FilePath& path, DCHECK(error); scoped_refptr<Extension> extension = new Extension(path, location); - if (!extension->InitFromValue(new extensions::Manifest(value.DeepCopy()), - flags, error)) + if (!extension->InitFromValue(value, flags, error)) return NULL; return extension; } @@ -879,7 +900,31 @@ ExtensionSidebarDefaults* Extension::LoadExtensionSidebarDefaults( return result.release(); } -bool Extension::LoadExtent(const extensions::Manifest* manifest, +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, const char* key, URLPatternSet* extent, const char* list_error, @@ -956,7 +1001,7 @@ bool Extension::LoadExtent(const extensions::Manifest* manifest, return true; } -bool Extension::LoadLaunchURL(const extensions::Manifest* manifest, +bool Extension::LoadLaunchURL(const DictionaryValue* manifest, std::string* error) { Value* temp = NULL; @@ -1054,7 +1099,7 @@ bool Extension::LoadLaunchURL(const extensions::Manifest* manifest, return true; } -bool Extension::LoadLaunchContainer(const extensions::Manifest* manifest, +bool Extension::LoadLaunchContainer(const DictionaryValue* manifest, std::string* error) { Value* temp = NULL; if (!manifest->Get(keys::kLaunchContainer, &temp)) @@ -1109,7 +1154,7 @@ bool Extension::LoadLaunchContainer(const extensions::Manifest* manifest, return true; } -bool Extension::LoadAppIsolation(const extensions::Manifest* manifest, +bool Extension::LoadAppIsolation(const DictionaryValue* manifest, std::string* error) { Value* temp = NULL; if (!manifest->Get(keys::kIsolation, &temp)) @@ -1141,18 +1186,18 @@ bool Extension::LoadAppIsolation(const extensions::Manifest* manifest, return true; } -bool Extension::LoadWebIntentServices(const extensions::Manifest* manifest, +bool Extension::LoadWebIntentServices(const base::DictionaryValue& 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; } @@ -1211,6 +1256,32 @@ bool Extension::LoadWebIntentServices(const extensions::Manifest* 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. @@ -1223,6 +1294,9 @@ 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), @@ -1381,14 +1455,10 @@ GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { chrome::kStandardSchemeSeparator + extension_id + "/"); } -bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, +bool Extension::InitFromValue(const DictionaryValue& source, 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 @@ -1399,9 +1469,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, optional_permission_set_ = new ExtensionPermissionSet(); required_permission_set_ = new ExtensionPermissionSet(); - if (manifest->HasKey(keys::kManifestVersion)) { + if (source.HasKey(keys::kManifestVersion)) { int manifest_version = 0; - if (!manifest->GetInteger(keys::kManifestVersion, &manifest_version) || + if (!source.GetInteger(keys::kManifestVersion, &manifest_version) || manifest_version < 1) { *error = errors::kInvalidManifestVersion; return false; @@ -1420,10 +1490,10 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, return false; } - if (manifest->HasKey(keys::kPublicKey)) { + if (source.HasKey(keys::kPublicKey)) { std::string public_key_bytes; - if (!manifest->GetString(keys::kPublicKey, - &public_key_) || + if (!source.GetString(keys::kPublicKey, + &public_key_) || !ParsePEMKeyBytes(public_key_, &public_key_bytes) || !GenerateId(public_key_bytes, &id_)) { @@ -1446,14 +1516,15 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, creation_flags_ = flags; - manifest_.reset(manifest); + // Make a copy of the manifest so we can store it in prefs. + manifest_value_.reset(source.DeepCopy()); // Initialize the URL. extension_url_ = Extension::GetBaseURLFromExtensionId(id()); // Initialize version. std::string version_str; - if (!manifest->GetString(keys::kVersion, &version_str)) { + if (!source.GetString(keys::kVersion, &version_str)) { *error = errors::kInvalidVersion; return false; } @@ -1466,7 +1537,7 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // Initialize name. string16 localized_name; - if (!manifest->GetString(keys::kName, &localized_name)) { + if (!source.GetString(keys::kName, &localized_name)) { *error = errors::kInvalidName; return false; } @@ -1476,17 +1547,18 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, 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 (is_app() && - (!LoadExtent(manifest_.get(), keys::kWebURLs, - &extent_, - errors::kInvalidWebURLs, errors::kInvalidWebURL, - parse_strictness, error) || - !LoadLaunchURL(manifest_.get(), error) || - !LoadLaunchContainer(manifest_.get(), error))) { + 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)) { return false; } - if (is_platform_app()) { + if (is_platform_app_) { if (launch_container() != extension_misc::LAUNCH_SHELL) { *error = errors::kInvalidLaunchContainerForPlatform; return false; @@ -1499,7 +1571,7 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // Initialize the permissions (optional). ExtensionAPIPermissionSet api_permissions; URLPatternSet host_permissions; - if (!ParsePermissions(manifest_.get(), + if (!ParsePermissions(&source, keys::kPermissions, flags, error, @@ -1511,7 +1583,7 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // Initialize the optional permissions (optional). ExtensionAPIPermissionSet optional_api_permissions; URLPatternSet optional_host_permissions; - if (!ParsePermissions(manifest_.get(), + if (!ParsePermissions(&source, keys::kOptionalPermissions, flags, error, @@ -1521,8 +1593,8 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize description (if present). - if (manifest->HasKey(keys::kDescription)) { - if (!manifest->GetString(keys::kDescription, + if (source.HasKey(keys::kDescription)) { + if (!source.GetString(keys::kDescription, &description_)) { *error = errors::kInvalidDescription; return false; @@ -1530,9 +1602,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize homepage url (if present). - if (manifest->HasKey(keys::kHomepageURL)) { + if (source.HasKey(keys::kHomepageURL)) { std::string tmp; - if (!manifest->GetString(keys::kHomepageURL, &tmp)) { + if (!source.GetString(keys::kHomepageURL, &tmp)) { *error = ExtensionErrorUtils::FormatErrorMessage( errors::kInvalidHomepageURL, ""); return false; @@ -1548,9 +1620,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize update url (if present). - if (manifest->HasKey(keys::kUpdateURL)) { + if (source.HasKey(keys::kUpdateURL)) { std::string tmp; - if (!manifest->GetString(keys::kUpdateURL, &tmp)) { + if (!source.GetString(keys::kUpdateURL, &tmp)) { *error = ExtensionErrorUtils::FormatErrorMessage( errors::kInvalidUpdateURL, ""); return false; @@ -1566,9 +1638,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, 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 (manifest->HasKey(keys::kMinimumChromeVersion)) { + if (source.HasKey(keys::kMinimumChromeVersion)) { std::string minimum_version_string; - if (!manifest->GetString(keys::kMinimumChromeVersion, + if (!source.GetString(keys::kMinimumChromeVersion, &minimum_version_string)) { *error = errors::kInvalidMinimumChromeVersion; return false; @@ -1604,14 +1676,13 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize converted_from_user_script (if present) - if (manifest->HasKey(keys::kConvertedFromUserScript)) - manifest->GetBoolean(keys::kConvertedFromUserScript, - &converted_from_user_script_); + source.GetBoolean(keys::kConvertedFromUserScript, + &converted_from_user_script_); // Initialize icons (if present). - if (manifest->HasKey(keys::kIcons)) { + if (source.HasKey(keys::kIcons)) { DictionaryValue* icons_value = NULL; - if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { + if (!source.GetDictionary(keys::kIcons, &icons_value)) { *error = errors::kInvalidIcons; return false; } @@ -1641,12 +1712,20 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize themes (if present). - if (manifest->HasKey(keys::kTheme)) { + is_theme_ = false; + if (source.HasKey(keys::kTheme)) { + // Themes cannot contain extension keys. + if (ContainsNonThemeKeys(source)) { + *error = errors::kThemesCannotContainExtensions; + return false; + } + DictionaryValue* theme_value = NULL; - if (!manifest->GetDictionary(keys::kTheme, &theme_value)) { + if (!source.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)) { @@ -1719,9 +1798,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize plugins (optional). - if (manifest->HasKey(keys::kPlugins)) { + if (source.HasKey(keys::kPlugins)) { ListValue* list_value = NULL; - if (!manifest->GetList(keys::kPlugins, &list_value)) { + if (!source.GetList(keys::kPlugins, &list_value)) { *error = errors::kInvalidPlugins; return false; } @@ -1763,9 +1842,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } } - if (manifest->HasKey(keys::kNaClModules)) { + if (source.HasKey(keys::kNaClModules)) { ListValue* list_value = NULL; - if (!manifest->GetList(keys::kNaClModules, &list_value)) { + if (!source.GetList(keys::kNaClModules, &list_value)) { *error = errors::kInvalidNaClModules; return false; } @@ -1801,9 +1880,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize content scripts (optional). - if (manifest->HasKey(keys::kContentScripts)) { + if (source.HasKey(keys::kContentScripts)) { ListValue* list_value; - if (!manifest->GetList(keys::kContentScripts, &list_value)) { + if (!source.GetList(keys::kContentScripts, &list_value)) { *error = errors::kInvalidContentScriptsList; return false; } @@ -1831,9 +1910,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // Initialize page action (optional). DictionaryValue* page_action_value = NULL; - if (manifest->HasKey(keys::kPageActions)) { + if (source.HasKey(keys::kPageActions)) { ListValue* list_value = NULL; - if (!manifest->GetList(keys::kPageActions, &list_value)) { + if (!source.GetList(keys::kPageActions, &list_value)) { *error = errors::kInvalidPageActionsList; return false; } @@ -1852,8 +1931,8 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, *error = errors::kInvalidPageActionsListSize; return false; } - } else if (manifest->HasKey(keys::kPageAction)) { - if (!manifest->GetDictionary(keys::kPageAction, &page_action_value)) { + } else if (source.HasKey(keys::kPageAction)) { + if (!source.GetDictionary(keys::kPageAction, &page_action_value)) { *error = errors::kInvalidPageAction; return false; } @@ -1868,9 +1947,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize browser action (optional). - if (manifest->HasKey(keys::kBrowserAction)) { + if (source.HasKey(keys::kBrowserAction)) { DictionaryValue* browser_action_value = NULL; - if (!manifest->GetDictionary(keys::kBrowserAction, &browser_action_value)) { + if (!source.GetDictionary(keys::kBrowserAction, &browser_action_value)) { *error = errors::kInvalidBrowserAction; return false; } @@ -1882,9 +1961,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize file browser actions (optional). - if (manifest->HasKey(keys::kFileBrowserHandlers)) { + if (source.HasKey(keys::kFileBrowserHandlers)) { ListValue* file_browser_handlers_value = NULL; - if (!manifest->GetList(keys::kFileBrowserHandlers, + if (!source.GetList(keys::kFileBrowserHandlers, &file_browser_handlers_value)) { *error = errors::kInvalidFileBrowserHandler; return false; @@ -1898,14 +1977,15 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // App isolation. if (api_permissions.count(ExtensionAPIPermission::kExperimental)) { - if (is_app() && !LoadAppIsolation(manifest_.get(), error)) + if (!LoadAppIsolation(manifest_value_.get(), error)) return false; } // Initialize options page url (optional). - if (manifest->HasKey(keys::kOptionsPage)) { + // Function LoadIsApp() set is_app_ above. + if (source.HasKey(keys::kOptionsPage)) { std::string options_str; - if (!manifest->GetString(keys::kOptionsPage, &options_str)) { + if (!source.GetString(keys::kOptionsPage, &options_str)) { *error = errors::kInvalidOptionsPage; return false; } @@ -1934,9 +2014,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize background url (optional). - if (manifest->HasKey(keys::kBackground)) { + if (source.HasKey(keys::kBackground)) { std::string background_str; - if (!manifest->GetString(keys::kBackground, &background_str)) { + if (!source.GetString(keys::kBackground, &background_str)) { *error = errors::kInvalidBackground; return false; } @@ -1967,8 +2047,8 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } } - if (manifest->HasKey(keys::kDefaultLocale)) { - if (!manifest->GetString(keys::kDefaultLocale, &default_locale_) || + if (source.HasKey(keys::kDefaultLocale)) { + if (!source.GetString(keys::kDefaultLocale, &default_locale_) || !l10n_util::IsValidLocaleSyntax(default_locale_)) { *error = errors::kInvalidDefaultLocale; return false; @@ -1976,9 +2056,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Chrome URL overrides (optional) - if (manifest->HasKey(keys::kChromeURLOverrides)) { + if (source.HasKey(keys::kChromeURLOverrides)) { DictionaryValue* overrides = NULL; - if (!manifest->GetDictionary(keys::kChromeURLOverrides, &overrides)) { + if (!source.GetDictionary(keys::kChromeURLOverrides, &overrides)) { *error = errors::kInvalidChromeURLOverrides; return false; } @@ -2020,9 +2100,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } if (api_permissions.count(ExtensionAPIPermission::kExperimental) && - manifest->HasKey(keys::kInputComponents)) { + source.HasKey(keys::kInputComponents)) { ListValue* list_value = NULL; - if (!manifest->GetList(keys::kInputComponents, &list_value)) { + if (!source.GetList(keys::kInputComponents, &list_value)) { *error = errors::kInvalidInputComponents; return false; } @@ -2151,17 +2231,17 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } } - if (manifest->HasKey(keys::kOmnibox)) { - if (!manifest->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || + if (source.HasKey(keys::kOmnibox)) { + if (!source.GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || omnibox_keyword_.empty()) { *error = errors::kInvalidOmniboxKeyword; return false; } } - if (manifest->HasKey(keys::kContentSecurityPolicy)) { + if (source.HasKey(keys::kContentSecurityPolicy)) { std::string content_security_policy; - if (!manifest->GetString(keys::kContentSecurityPolicy, + if (!source.GetString(keys::kContentSecurityPolicy, &content_security_policy)) { *error = errors::kInvalidContentSecurityPolicy; return false; @@ -2186,9 +2266,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize devtools page url (optional). - if (manifest->HasKey(keys::kDevToolsPage)) { + if (source.HasKey(keys::kDevToolsPage)) { std::string devtools_str; - if (!manifest->GetString(keys::kDevToolsPage, &devtools_str)) { + if (!source.GetString(keys::kDevToolsPage, &devtools_str)) { *error = errors::kInvalidDevToolsPage; return false; } @@ -2200,9 +2280,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize sidebar action (optional). - if (manifest->HasKey(keys::kSidebar)) { + if (source.HasKey(keys::kSidebar)) { DictionaryValue* sidebar_value = NULL; - if (!manifest->GetDictionary(keys::kSidebar, &sidebar_value)) { + if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) { *error = errors::kInvalidSidebar; return false; } @@ -2216,9 +2296,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize text-to-speech voices (optional). - if (manifest->HasKey(keys::kTtsEngine)) { + if (source.HasKey(keys::kTtsEngine)) { DictionaryValue* tts_dict = NULL; - if (!manifest->GetDictionary(keys::kTtsEngine, &tts_dict)) { + if (!source.GetDictionary(keys::kTtsEngine, &tts_dict)) { *error = errors::kInvalidTts; return false; } @@ -2299,15 +2379,15 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize web intents (optional). - if (!LoadWebIntentServices(manifest, error)) + if (!LoadWebIntentServices(source, error)) return false; // Initialize incognito behavior. Apps default to split mode, extensions // default to spanning. incognito_split_mode_ = is_app(); - if (manifest->HasKey(keys::kIncognito)) { + if (source.HasKey(keys::kIncognito)) { std::string value; - if (!manifest->GetString(keys::kIncognito, &value)) { + if (!source.GetString(keys::kIncognito, &value)) { *error = errors::kInvalidIncognitoBehavior; return false; } @@ -2322,8 +2402,8 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, } // Initialize offline-enabled status. Defaults to false. - if (manifest->HasKey(keys::kOfflineEnabled)) { - if (!manifest->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { + if (source.HasKey(keys::kOfflineEnabled)) { + if (!source.GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { *error = errors::kInvalidOfflineEnabled; return false; } @@ -2331,9 +2411,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags, // Initialize requirements (optional). Not actually persisted (they're only // used by the store), but still validated. - if (manifest->HasKey(keys::kRequirements)) { + if (source.HasKey(keys::kRequirements)) { DictionaryValue* requirements_value = NULL; - if (!manifest->GetDictionary(keys::kRequirements, &requirements_value)) { + if (!source.GetDictionary(keys::kRequirements, &requirements_value)) { *error = errors::kInvalidRequirements; return false; } @@ -2362,6 +2442,13 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, 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; } @@ -2517,7 +2604,7 @@ GURL Extension::GetIconURL(int size, return GetResourceURL(path); } -bool Extension::ParsePermissions(const extensions::Manifest* source, +bool Extension::ParsePermissions(const DictionaryValue* source, const char* key, int flags, std::string* error, diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index 54bff60..a0ec6d8 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -20,7 +20,6 @@ #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" @@ -375,7 +374,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 extensions::Manifest* source, + bool ParsePermissions(const base::DictionaryValue* source, const char* key, int flags, std::string* error, @@ -532,8 +531,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> { } const GURL& update_url() const { return update_url_; } const ExtensionIconSet& icons() const { return icons_; } - const extensions::Manifest* manifest() const { - return manifest_.get(); + const base::DictionaryValue* manifest_value() const { + return manifest_value_.get(); } const std::string default_locale() const { return default_locale_; } const URLOverrideMap& GetChromeURLOverrides() const { @@ -558,12 +557,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> { } // App-related. - bool is_app() const { - return is_packaged_app() || is_hosted_app() || is_platform_app(); + 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_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_; } @@ -575,7 +574,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> { int launch_height() const { return launch_height_; } // Theme-related. - bool is_theme() const { return manifest()->IsTheme(); } + bool is_theme() const { return is_theme_; } base::DictionaryValue* GetThemeImages() const { return theme_images_.get(); } base::DictionaryValue* GetThemeColors() const {return theme_colors_.get(); } base::DictionaryValue* GetThemeTints() const { return theme_tints_.get(); } @@ -617,8 +616,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> { ~Extension(); // Initialize the extension from a parsed manifest. - // Takes ownership of the manifest |value|. - bool InitFromValue(extensions::Manifest* value, int flags, + bool InitFromValue(const base::DictionaryValue& value, int flags, std::string* error); // Helper function for implementing HasCachedImage/GetCachedImage. A return @@ -645,21 +643,24 @@ class Extension : public base::RefCountedThreadSafe<Extension> { UserScript *instance); // Helpers to load various chunks of the manifest. - bool LoadExtent(const extensions::Manifest* manifest, + bool LoadIsApp(const base::DictionaryValue* manifest, std::string* error); + bool LoadExtent(const base::DictionaryValue* manifest, const char* key, URLPatternSet* extent, const char* list_error, const char* value_error, URLPattern::ParseOption parse_strictness, std::string* error); - bool LoadLaunchContainer(const extensions::Manifest* manifest, + bool LoadLaunchContainer(const base::DictionaryValue* manifest, std::string* error); - bool LoadLaunchURL(const extensions::Manifest* manifest, + bool LoadLaunchURL(const base::DictionaryValue* manifest, std::string* error); - bool LoadAppIsolation(const extensions::Manifest* manifest, + bool LoadAppIsolation(const base::DictionaryValue* manifest, std::string* error); - bool LoadWebIntentServices(const extensions::Manifest* manifest, + bool LoadWebIntentServices(const base::DictionaryValue& 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. @@ -682,6 +683,10 @@ 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); @@ -815,6 +820,9 @@ 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_; @@ -822,13 +830,19 @@ class Extension : public base::RefCountedThreadSafe<Extension> { // URL for fetching an update manifest GURL update_url_; - // The manifest that this extension was created from. - scoped_ptr<extensions::Manifest> manifest_; + // A copy of the manifest that this extension was created from. + scoped_ptr<base::DictionaryValue> manifest_value_; // 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 f818e62..2d0e730 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 kFeatureNotAllowed[] = - "Feature '*' is not allowed in this type of manifest."; +const char kHostedAppsCannotIncludeExtensionFeatures[] = + "Hosted apps cannot use the extension feature '*'."; const char kInvalidAllFrames[] = "Invalid value for 'content_scripts[*].all_frames'."; const char kInvalidBackground[] = @@ -429,6 +429,8 @@ 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 abb77f0..8c988f3 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 kFeatureNotAllowed[]; + extern const char kHostedAppsCannotIncludeExtensionFeatures[]; extern const char kInvalidAllFrames[]; extern const char kInvalidBackground[]; extern const char kInvalidBackgroundInHostedApp[]; @@ -280,6 +280,7 @@ 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 8136dea..adc6969 100644 --- a/chrome/common/extensions/extension_manifests_unittest.cc +++ b/chrome/common/extensions/extension_manifests_unittest.cc @@ -588,8 +588,12 @@ TEST_F(ExtensionManifestTest, Sidebar) { extension->sidebar_defaults()->default_page().spec()); } -TEST_F(ExtensionManifestTest, BackgroundPermission) { - LoadAndExpectError("background_permission.json", +TEST_F(ExtensionManifestTest, DisallowHybridApps) { + LoadAndExpectError("disallow_hybrid_1.json", + ExtensionErrorUtils::FormatErrorMessage( + errors::kHostedAppsCannotIncludeExtensionFeatures, + keys::kBrowserAction)); + LoadAndExpectError("disallow_hybrid_2.json", errors::kBackgroundPermissionNeeded); } @@ -738,7 +742,9 @@ TEST_F(ExtensionManifestTest, NormalizeIconPaths) { } TEST_F(ExtensionManifestTest, DisallowMultipleUISurfaces) { - LoadAndExpectError("multiple_ui_surfaces.json", errors::kOneUISurfaceOnly); + LoadAndExpectError("multiple_ui_surfaces_1.json", errors::kOneUISurfaceOnly); + LoadAndExpectError("multiple_ui_surfaces_2.json", errors::kOneUISurfaceOnly); + LoadAndExpectError("multiple_ui_surfaces_3.json", errors::kOneUISurfaceOnly); } TEST_F(ExtensionManifestTest, ParseHomepageURLs) { diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc index 3adee27..a326289 100644 --- a/chrome/common/extensions/extension_messages.cc +++ b/chrome/common/extensions/extension_messages.cc @@ -5,7 +5,6 @@ #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() @@ -50,11 +49,10 @@ ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params( extension_manifest_keys::kVersion, }; - // Copy only the data we need and bypass the manifest type checks. - DictionaryValue* source = extension->manifest()->value(); + // Copy only the data we need. for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRendererExtensionKeys); ++i) { Value* temp = NULL; - if (source->Get(kRendererExtensionKeys[i], &temp)) + if (extension->manifest_value()->Get(kRendererExtensionKeys[i], &temp)) manifest->Set(kRendererExtensionKeys[i], temp->DeepCopy()); } } diff --git a/chrome/common/extensions/manifest.cc b/chrome/common/extensions/manifest.cc deleted file mode 100644 index 7f05bb6..0000000 --- a/chrome/common/extensions/manifest.cc +++ /dev/null @@ -1,229 +0,0 @@ -// 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; - map[keys::kChromeURLOverrides] = 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; - - // 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 deleted file mode 100644 index fb372708..0000000 --- a/chrome/common/extensions/manifest.h +++ /dev/null @@ -1,112 +0,0 @@ -// 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 deleted file mode 100644 index 61282fa..0000000 --- a/chrome/common/extensions/manifest_unittest.cc +++ /dev/null @@ -1,392 +0,0 @@ -// 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::kChromeURLOverrides, -}; - -// 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 |