Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3716)

Unified Diff: chrome/common/extensions/extension.cc

Issue 9424009: Cleaning up Extension::InitFromValue() (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Final update with requested changes, latest versions of extension.* Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/common/extensions/extension.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/common/extensions/extension.cc
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 0e8530073461c0a1c11e5fa92a560fb36b2f0114..a14bf66dee60b5b9908539dcb0fc3fd673dd3591 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -172,6 +172,30 @@ int GetLocationRank(Extension::Location location) {
return rank;
}
+bool ReadLaunchDimension(const extensions::Manifest* manifest,
+ const char* key,
+ int* target,
+ bool is_valid_container,
+ string16* error) {
+ Value* temp = NULL;
+ if (manifest->Get(key, &temp)) {
+ if (!is_valid_container) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValueContainer,
+ key);
+ return false;
+ }
+ if (!temp->GetAsInteger(target) || *target < 0) {
+ *target = 0;
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ key);
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
const FilePath::CharType Extension::kManifestFilename[] =
@@ -333,7 +357,6 @@ scoped_refptr<Extension> Extension::Create(const FilePath& path,
const std::string& explicit_id,
std::string* utf8_error) {
DCHECK(utf8_error);
-
string16 error;
scoped_ptr<extensions::Manifest> manifest(
new extensions::Manifest(
@@ -480,11 +503,11 @@ bool Extension::is_platform_app() const {
}
bool Extension::is_hosted_app() const {
- return manifest()->IsHostedApp();
+ return manifest()->IsHostedApp();
}
bool Extension::is_packaged_app() const {
- return manifest()->IsPackagedApp();
+ return manifest()->IsPackagedApp();
}
bool Extension::is_theme() const {
@@ -535,7 +558,6 @@ bool Extension::GenerateId(const std::string& input, std::string* output) {
// content_script list of the manifest.
bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
int definition_index,
- int flags,
string16* error,
UserScript* result) {
// run_at
@@ -616,7 +638,7 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
if (pattern.MatchesScheme(chrome::kFileScheme) &&
!CanExecuteScriptEverywhere()) {
wants_file_access_ = true;
- if (!(flags & ALLOW_FILE_ACCESS))
+ if (!(creation_flags_ & ALLOW_FILE_ACCESS))
pattern.SetValidSchemes(
pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
}
@@ -892,98 +914,123 @@ ExtensionAction* Extension::LoadExtensionActionHelper(
return result.release();
}
-Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers(
- const ListValue* extension_actions, string16* error) {
- scoped_ptr<FileBrowserHandlerList> result(
- new FileBrowserHandlerList());
- for (ListValue::const_iterator iter = extension_actions->begin();
- iter != extension_actions->end();
- ++iter) {
- if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
- *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
- return NULL;
+// static
+bool Extension::InitExtensionID(extensions::Manifest* manifest,
+ const FilePath& path,
+ const std::string& explicit_id,
+ int creation_flags,
+ string16* error) {
+ if (!explicit_id.empty()) {
+ manifest->set_extension_id(explicit_id);
+ return true;
+ }
+
+ if (manifest->HasKey(keys::kPublicKey)) {
+ std::string public_key;
+ std::string public_key_bytes;
+ std::string extension_id;
+ if (!manifest->GetString(keys::kPublicKey, &public_key) ||
+ !ParsePEMKeyBytes(public_key, &public_key_bytes) ||
+ !GenerateId(public_key_bytes, &extension_id)) {
+ *error = ASCIIToUTF16(errors::kInvalidKey);
+ return false;
}
- scoped_ptr<FileBrowserHandler> action(
- LoadFileBrowserHandler(
- reinterpret_cast<DictionaryValue*>(*iter), error));
- if (!action.get())
- return NULL; // Failed to parse file browser action definition.
- result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
+ manifest->set_extension_id(extension_id);
+ return true;
+ }
+
+ if (creation_flags & REQUIRE_KEY) {
+ *error = ASCIIToUTF16(errors::kInvalidKey);
+ return false;
+ } else {
+ // If there is a path, we generate the ID from it. This is useful for
+ // development mode, because it keeps the ID stable across restarts and
+ // reloading the extension.
+ std::string extension_id = GenerateIdForPath(path);
+ if (extension_id.empty()) {
+ NOTREACHED() << "Could not create ID from path.";
+ return false;
+ }
+ manifest->set_extension_id(extension_id);
+ return true;
}
- return result.release();
}
-FileBrowserHandler* Extension::LoadFileBrowserHandler(
- const DictionaryValue* file_browser_handler, string16* error) {
- scoped_ptr<FileBrowserHandler> result(
- new FileBrowserHandler());
- result->set_extension_id(id());
+bool Extension::CheckMinimumChromeVersion(string16* error) {
+ if (!manifest_->HasKey(keys::kMinimumChromeVersion))
+ return true;
+ std::string minimum_version_string;
+ if (!manifest_->GetString(keys::kMinimumChromeVersion,
+ &minimum_version_string)) {
+ *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
+ return false;
+ }
- std::string id;
- // Read the file action |id| (mandatory).
- if (!file_browser_handler->HasKey(keys::kPageActionId) ||
- !file_browser_handler->GetString(keys::kPageActionId, &id)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionId);
- return NULL;
+ scoped_ptr<Version> minimum_version(
+ Version::GetVersionFromString(minimum_version_string));
+ if (!minimum_version.get()) {
+ *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
+ return false;
}
- result->set_id(id);
- // Read the page action title from |default_title| (mandatory).
- std::string title;
- if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
- !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
- return NULL;
+ chrome::VersionInfo current_version_info;
+ if (!current_version_info.is_valid()) {
+ NOTREACHED();
+ return false;
}
- result->set_title(title);
- // Initialize file filters (mandatory).
- ListValue* list_value = NULL;
- if (!file_browser_handler->HasKey(keys::kFileFilters) ||
- !file_browser_handler->GetList(keys::kFileFilters, &list_value) ||
- list_value->empty()) {
- *error = ASCIIToUTF16(errors::kInvalidFileFiltersList);
- return NULL;
+ scoped_ptr<Version> current_version(
+ Version::GetVersionFromString(current_version_info.Version()));
+ if (!current_version.get()) {
+ DCHECK(false);
+ return false;
}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- std::string filter;
- if (!list_value->GetString(i, &filter)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidFileFilterValue, base::IntToString(i));
- return NULL;
- }
- StringToLowerASCII(&filter);
- URLPattern pattern(URLPattern::SCHEME_FILESYSTEM);
- if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, filter);
- return NULL;
- }
- std::string path = pattern.path();
- bool allowed = path == "*" || path == "*.*" ||
- (path.compare(0, 2, "*.") == 0 &&
- path.find_first_of('*', 2) == std::string::npos);
- if (!allowed) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, filter);
- return NULL;
- }
- result->AddPattern(pattern);
+
+ if (current_version->CompareTo(*minimum_version) < 0) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kChromeVersionTooLow,
+ l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
+ minimum_version_string);
+ return false;
}
+ return true;
+}
- std::string default_icon;
- // Read the file browser action |default_icon| (optional).
- if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
- if (!file_browser_handler->GetString(
- keys::kPageActionDefaultIcon, &default_icon) ||
- default_icon.empty()) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
- return NULL;
- }
- result->set_icon_path(default_icon);
+bool Extension::LoadRequiredFeatures(string16* error) {
+ if (!LoadName(error) ||
+ !LoadVersion(error))
+ return false;
+ return true;
+}
+
+bool Extension::LoadName(string16* error) {
+ string16 localized_name;
+ if (!manifest_->GetString(keys::kName, &localized_name)) {
+ *error = ASCIIToUTF16(errors::kInvalidName);
+ return false;
+ }
+ base::i18n::AdjustStringForLocaleDirection(&localized_name);
+ name_ = UTF16ToUTF8(localized_name);
+ return true;
+}
+
+bool Extension::LoadDescription(string16* error) {
+ if (manifest_->HasKey(keys::kDescription) &&
+ !manifest_->GetString(keys::kDescription, &description_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDescription);
+ return false;
}
+ return true;
+}
- return result.release();
+bool Extension::LoadAppFeatures(string16* error) {
+ if (!LoadExtent(keys::kWebURLs, &extent_,
+ errors::kInvalidWebURLs, errors::kInvalidWebURL, error) ||
+ !LoadLaunchURL(error) ||
+ !LoadLaunchContainer(error))
+ return false;
+
+ return true;
}
bool Extension::LoadExtent(const char* key,
@@ -1164,30 +1211,7 @@ bool Extension::LoadLaunchURL(string16* error) {
OverrideLaunchUrl(cloud_print_enable_connector_url);
}
}
- return true;
-}
-bool ReadLaunchDimension(const extensions::Manifest* manifest,
- const char* key,
- int* target,
- bool is_valid_container,
- string16* error) {
- Value* temp = NULL;
- if (manifest->Get(key, &temp)) {
- if (!is_valid_container) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValueContainer,
- key);
- return false;
- }
- if (!temp->GetAsInteger(target) || *target < 0) {
- *target = 0;
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- key);
- return false;
- }
- }
return true;
}
@@ -1214,9 +1238,9 @@ bool Extension::LoadLaunchContainer(string16* error) {
}
bool can_specify_initial_size =
- launch_container() == extension_misc::LAUNCH_PANEL ||
- launch_container() == extension_misc::LAUNCH_WINDOW ||
- launch_container() == extension_misc::LAUNCH_SHELL;
+ launch_container_ == extension_misc::LAUNCH_PANEL ||
+ launch_container_ == extension_misc::LAUNCH_WINDOW ||
+ launch_container_ == extension_misc::LAUNCH_SHELL;
// Validate the container width if present.
if (!ReadLaunchDimension(manifest_,
@@ -1235,7 +1259,7 @@ bool Extension::LoadLaunchContainer(string16* error) {
return false;
bool can_specify_size_range =
- launch_container() == extension_misc::LAUNCH_SHELL;
+ launch_container_ == extension_misc::LAUNCH_SHELL;
// Validate min size if present.
if (!ReadLaunchDimension(manifest_,
@@ -1263,7 +1287,7 @@ bool Extension::LoadLaunchContainer(string16* error) {
error))
return false;
- if (launch_container() == extension_misc::LAUNCH_SHELL) {
+ if (launch_container_ == extension_misc::LAUNCH_SHELL) {
if (!manifest_->Get(keys::kLaunchWidth, &temp)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidLaunchValue,
@@ -1290,173 +1314,373 @@ bool Extension::LoadLaunchContainer(string16* error) {
}
}
+ if (is_platform_app()) {
+ if (launch_container_ != extension_misc::LAUNCH_SHELL) {
+ *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform);
+ return false;
+ }
+ } else if (launch_container_ == extension_misc::LAUNCH_SHELL) {
+ *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform);
+ return false;
+ }
+
return true;
}
-bool Extension::LoadAppIsolation(string16* error) {
- Value* temp = NULL;
- if (!manifest_->Get(keys::kIsolation, &temp))
- return true;
+bool Extension::LoadSharedFeatures(
+ const ExtensionAPIPermissionSet& api_permissions,
+ string16* error) {
+ if (!LoadDescription(error) ||
+ !LoadManifestVersion(error) ||
+ !LoadHomepageURL(error) ||
+ !LoadUpdateURL(error) ||
+ !LoadIcons(error) ||
+ !LoadCommands(error) ||
+ !LoadPlugins(error) ||
+ !LoadNaClModules(error) ||
+ !LoadWebAccessibleResources(error) ||
+ !CheckRequirements(error) ||
+ !LoadDefaultLocale(error) ||
+ !LoadOfflineEnabled(error) ||
+ !LoadOptionsPage(error) ||
+ // LoadBackgroundScripts() must be called before LoadBackgroundPage().
+ !LoadBackgroundScripts(error) ||
+ !LoadBackgroundPage(api_permissions, error) ||
+ !LoadBackgroundPersistent(api_permissions, error) ||
+ !LoadBackgroundAllowJSAccess(api_permissions, error) ||
+ !LoadWebIntentServices(error))
+ return false;
- if (temp->GetType() != Value::TYPE_LIST) {
- *error = ASCIIToUTF16(errors::kInvalidIsolation);
+ return true;
+}
+
+bool Extension::LoadVersion(string16* error) {
+ std::string version_str;
+ if (!manifest_->GetString(keys::kVersion, &version_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
+ return false;
+ }
+ version_.reset(Version::GetVersionFromString(version_str));
+ if (!version_.get() ||
+ version_->components().size() > 4) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
return false;
}
+ return true;
+}
- ListValue* isolation_list = static_cast<ListValue*>(temp);
- for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
- std::string isolation_string;
- if (!isolation_list->GetString(i, &isolation_string)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIsolationValue,
- base::UintToString(i));
+bool Extension::LoadManifestVersion(string16* error) {
+ // Get the original value out of the dictionary so that we can validate it
+ // more strictly.
+ if (manifest_->value()->HasKey(keys::kManifestVersion)) {
+ int manifest_version = 1;
+ if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
+ manifest_version < 1) {
+ *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
return false;
}
+ }
- // Check for isolated storage.
- if (isolation_string == values::kIsolatedStorage) {
- is_storage_isolated_ = true;
- } else {
- DLOG(WARNING) << "Did not recognize isolation type: "
- << isolation_string;
- }
+ manifest_version_ = manifest_->GetManifestVersion();
+ if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
+ manifest_version_ < kModernManifestVersion &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowLegacyExtensionManifests)) {
+ *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
+ return false;
}
+
return true;
}
-bool Extension::LoadWebIntentAction(const std::string& action_name,
- const DictionaryValue& intent_service,
- string16* error) {
- DCHECK(error);
- webkit_glue::WebIntentServiceData service;
- std::string value;
-
- service.action = UTF8ToUTF16(action_name);
+bool Extension::LoadHomepageURL(string16* error) {
+ if (!manifest_->HasKey(keys::kHomepageURL))
+ return true;
+ std::string tmp;
+ if (!manifest_->GetString(keys::kHomepageURL, &tmp)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidHomepageURL, "");
+ return false;
+ }
+ homepage_url_ = GURL(tmp);
+ if (!homepage_url_.is_valid() ||
+ (!homepage_url_.SchemeIs("http") &&
+ !homepage_url_.SchemeIs("https"))) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidHomepageURL, tmp);
+ return false;
+ }
+ return true;
+}
- ListValue* mime_types = NULL;
- if (!intent_service.HasKey(keys::kIntentType) ||
- !intent_service.GetList(keys::kIntentType, &mime_types) ||
- mime_types->GetSize() == 0) {
+bool Extension::LoadUpdateURL(string16* error) {
+ if (!manifest_->HasKey(keys::kUpdateURL))
+ return true;
+ std::string tmp;
+ if (!manifest_->GetString(keys::kUpdateURL, &tmp)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentType, action_name);
+ errors::kInvalidUpdateURL, "");
+ return false;
+ }
+ update_url_ = GURL(tmp);
+ if (!update_url_.is_valid() ||
+ update_url_.has_ref()) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidUpdateURL, tmp);
return false;
}
+ return true;
+}
- std::string href;
- if (intent_service.HasKey(keys::kIntentPath)) {
- if (!intent_service.GetString(keys::kIntentPath, &href)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentHref);
- return false;
- }
+bool Extension::LoadIcons(string16* error) {
+ if (!manifest_->HasKey(keys::kIcons))
+ return true;
+ DictionaryValue* icons_value = NULL;
+ if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidIcons);
+ return false;
}
- if (intent_service.HasKey(keys::kIntentHref)) {
- if (!href.empty()) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentHrefOldAndNewKey, action_name,
- keys::kIntentPath, keys::kIntentHref);
- return false;
+ for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) {
+ std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]);
+ if (icons_value->HasKey(key)) {
+ std::string icon_path;
+ if (!icons_value->GetString(key, &icon_path)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIconPath, key);
+ return false;
+ }
+
+ if (!icon_path.empty() && icon_path[0] == '/')
+ icon_path = icon_path.substr(1);
+
+ if (icon_path.empty()) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIconPath, key);
+ return false;
+ }
+ icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path);
}
- if (!intent_service.GetString(keys::kIntentHref, &href)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentHref);
+ }
+ return true;
+}
+
+bool Extension::LoadCommands(string16* error) {
+ if (manifest_->HasKey(keys::kCommands)) {
+ DictionaryValue* commands = NULL;
+ if (!manifest_->GetDictionary(keys::kCommands, &commands)) {
+ *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
return false;
}
- }
- if (!href.empty()) {
- GURL service_url(href);
- if (is_hosted_app()) {
- // Hosted apps require an absolute URL for intents.
- if (!service_url.is_valid() ||
- !(web_extent().MatchesURL(service_url))) {
+ int command_index = 0;
+ for (DictionaryValue::key_iterator iter = commands->begin_keys();
+ iter != commands->end_keys(); ++iter) {
+ ++command_index;
+
+ DictionaryValue* command = NULL;
+ if (!commands->GetDictionary(*iter, &command)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentPageInHostedApp, action_name);
+ errors::kInvalidKeyBindingDictionary,
+ base::IntToString(command_index));
return false;
}
- service.service_url = service_url;
- } else {
- // We do not allow absolute intent URLs in non-hosted apps.
- if (service_url.is_valid()) {
- *error =ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kCannotAccessPage, href);
+
+ ExtensionKeybinding binding;
+ if (!binding.Parse(command, *iter, command_index, error))
+ return false; // |error| already set.
+
+ commands_.push_back(binding);
+ }
+ }
+ return true;
+}
+
+bool Extension::LoadPlugins(string16* error) {
+ if (!manifest_->HasKey(keys::kPlugins))
+ return true;
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kPlugins, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPlugins);
+ return false;
+ }
+
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* plugin_value = NULL;
+ std::string path_str;
+ bool is_public = false;
+ if (!list_value->GetDictionary(i, &plugin_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPlugins);
+ return false;
+ }
+ // Get plugins[i].path.
+ if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPluginsPath, base::IntToString(i));
+ return false;
+ }
+
+ // Get plugins[i].content (optional).
+ if (plugin_value->HasKey(keys::kPluginsPublic)) {
+ if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPluginsPublic, base::IntToString(i));
return false;
}
- service.service_url = GetResourceURL(href);
}
+
+ // We don't allow extension plugins to run on Chrome OS. We still
+ // parse the manifest entry so that error messages are consistently
+ // displayed across platforms.
+#if !defined(OS_CHROMEOS)
+ plugins_.push_back(PluginInfo());
+ plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
+ plugins_.back().is_public = is_public;
+#endif
}
+ return true;
+}
- if (intent_service.HasKey(keys::kIntentTitle) &&
- !intent_service.GetString(keys::kIntentTitle, &service.title)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
+bool Extension::LoadNaClModules(string16* error) {
+ if (!manifest_->HasKey(keys::kNaClModules))
+ return true;
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kNaClModules, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidNaClModules);
return false;
}
- if (intent_service.HasKey(keys::kIntentDisposition)) {
- if (!intent_service.GetString(keys::kIntentDisposition, &value) ||
- (value != values::kIntentDispositionWindow &&
- value != values::kIntentDispositionInline)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentDisposition);
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* module_value = NULL;
+ std::string path_str;
+ std::string mime_type;
+
+ if (!list_value->GetDictionary(i, &module_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidNaClModules);
return false;
}
- if (value == values::kIntentDispositionInline) {
- service.disposition =
- webkit_glue::WebIntentServiceData::DISPOSITION_INLINE;
- } else {
- service.disposition =
- webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW;
+
+ // Get nacl_modules[i].path.
+ if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidNaClModulesPath, base::IntToString(i));
+ return false;
}
+
+ // Get nacl_modules[i].mime_type.
+ if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
+ return false;
+ }
+
+ nacl_modules_.push_back(NaClModuleInfo());
+ nacl_modules_.back().url = GetResourceURL(path_str);
+ nacl_modules_.back().mime_type = mime_type;
}
- for (size_t i = 0; i < mime_types->GetSize(); ++i) {
- if (!mime_types->GetString(i, &service.type)) {
+ return true;
+}
+
+bool Extension::LoadWebAccessibleResources(string16* error) {
+ if (!manifest_->HasKey(keys::kWebAccessibleResources))
+ return true;
+ ListValue* list_value;
+ if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList);
+ return false;
+ }
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ std::string relative_path;
+ if (!list_value->GetString(i, &relative_path)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentTypeElement, action_name,
- std::string(base::IntToString(i)));
+ errors::kInvalidWebAccessibleResource, base::IntToString(i));
return false;
}
- intents_services_.push_back(service);
+ if (relative_path[0] != '/')
+ relative_path = '/' + relative_path;
+ web_accessible_resources_.insert(relative_path);
}
+
return true;
}
-bool Extension::LoadWebIntentServices(string16* error) {
- DCHECK(error);
+// These are not actually persisted (they're only used by the store), but
+// still validated.
+bool Extension::CheckRequirements(string16* error) {
+ if (!manifest_->HasKey(keys::kRequirements))
+ return true;
+ DictionaryValue* requirements_value = NULL;
+ if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidRequirements);
+ return false;
+ }
- if (!manifest_->HasKey(keys::kIntents))
+ for (DictionaryValue::key_iterator it = requirements_value->begin_keys();
+ it != requirements_value->end_keys(); ++it) {
+ DictionaryValue* requirement_value;
+ if (!requirements_value->GetDictionaryWithoutPathExpansion(
+ *it, &requirement_value)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Extension::LoadDefaultLocale(string16* error) {
+ if (!manifest_->HasKey(keys::kDefaultLocale))
return true;
+ if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) ||
+ !l10n_util::IsValidLocaleSyntax(default_locale_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDefaultLocale);
+ return false;
+ }
+ return true;
+}
- DictionaryValue* all_services = NULL;
- if (!manifest_->GetDictionary(keys::kIntents, &all_services)) {
- *error = ASCIIToUTF16(errors::kInvalidIntents);
+bool Extension::LoadOfflineEnabled(string16* error) {
+ // Defaults to false.
+ if (manifest_->HasKey(keys::kOfflineEnabled) &&
+ !manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
+ *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
return false;
}
+ return true;
+}
- for (DictionaryValue::key_iterator iter(all_services->begin_keys());
- iter != all_services->end_keys(); ++iter) {
- // Any entry in the intents dictionary can either have a list of
- // dictionaries, or just a single dictionary attached to that. Try
- // lists first, fall back to single dictionary.
- ListValue* service_list = NULL;
- DictionaryValue* one_service = NULL;
- if (all_services->GetListWithoutPathExpansion(*iter, &service_list)) {
- for (size_t i = 0; i < service_list->GetSize(); ++i) {
- if (!service_list->GetDictionary(i, &one_service)) {
- *error = ASCIIToUTF16(errors::kInvalidIntent);
- return false;
- }
- if (!LoadWebIntentAction(*iter, *one_service, error))
- return false;
- }
- } else {
- if (!all_services->GetDictionaryWithoutPathExpansion(*iter,
- &one_service)) {
- *error = ASCIIToUTF16(errors::kInvalidIntent);
- return false;
- }
- if (!LoadWebIntentAction(*iter, *one_service, error))
- return false;
+bool Extension::LoadOptionsPage(string16* error) {
+ if (!manifest_->HasKey(keys::kOptionsPage))
+ return true;
+ std::string options_str;
+ if (!manifest_->GetString(keys::kOptionsPage, &options_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
+ return false;
+ }
+
+ if (is_hosted_app()) {
+ // hosted apps require an absolute URL.
+ GURL options_url(options_str);
+ if (!options_url.is_valid() ||
+ !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
+ return false;
+ }
+ options_url_ = options_url;
+ } else {
+ GURL absolute(options_str);
+ if (absolute.is_valid()) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
+ return false;
+ }
+ options_url_ = GetResourceURL(options_str);
+ if (!options_url_.is_valid()) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
+ return false;
}
}
+
return true;
}
@@ -1557,7 +1781,7 @@ bool Extension::LoadBackgroundPersistent(
return true;
}
-bool Extension::LoadBackgroundAllowJsAccess(
+bool Extension::LoadBackgroundAllowJSAccess(
const ExtensionAPIPermissionSet& api_permissions,
string16* error) {
Value* allow_js_access = NULL;
@@ -1578,1187 +1802,1100 @@ bool Extension::LoadBackgroundAllowJsAccess(
return true;
}
-// static
-bool Extension::IsTrustedId(const std::string& id) {
- // See http://b/4946060 for more details.
- return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
-}
-
-Extension::Extension(const FilePath& path,
- scoped_ptr<extensions::Manifest> manifest)
- : manifest_version_(0),
- incognito_split_mode_(false),
- offline_enabled_(false),
- converted_from_user_script_(false),
- background_page_persists_(true),
- allow_background_js_access_(true),
- manifest_(manifest.release()),
- is_storage_isolated_(false),
- launch_container_(extension_misc::LAUNCH_TAB),
- launch_width_(0),
- launch_height_(0),
- launch_min_width_(0),
- launch_min_height_(0),
- launch_max_width_(0),
- launch_max_height_(0),
- wants_file_access_(false),
- creation_flags_(0) {
- DCHECK(path.empty() || path.IsAbsolute());
- path_ = MaybeNormalizePath(path);
-}
+bool Extension::LoadWebIntentAction(const std::string& action_name,
+ const DictionaryValue& intent_service,
+ string16* error) {
+ DCHECK(error);
+ webkit_glue::WebIntentServiceData service;
+ std::string value;
-Extension::~Extension() {
- if (manifest_)
- delete manifest_;
-}
+ service.action = UTF8ToUTF16(action_name);
-ExtensionResource Extension::GetResource(
- const std::string& relative_path) const {
-#if defined(OS_POSIX)
- FilePath relative_file_path(relative_path);
-#elif defined(OS_WIN)
- FilePath relative_file_path(UTF8ToWide(relative_path));
-#endif
- return ExtensionResource(id(), path(), relative_file_path);
-}
-
-ExtensionResource Extension::GetResource(
- const FilePath& relative_file_path) const {
- return ExtensionResource(id(), path(), relative_file_path);
-}
-
-// TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
-// util class in base:
-// http://code.google.com/p/chromium/issues/detail?id=13572
-bool Extension::ParsePEMKeyBytes(const std::string& input,
- std::string* output) {
- DCHECK(output);
- if (!output)
- return false;
- if (input.length() == 0)
- return false;
-
- std::string working = input;
- if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
- working = CollapseWhitespaceASCII(working, true);
- size_t header_pos = working.find(kKeyInfoEndMarker,
- sizeof(kKeyBeginHeaderMarker) - 1);
- if (header_pos == std::string::npos)
- return false;
- size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
- size_t end_pos = working.rfind(kKeyBeginFooterMarker);
- if (end_pos == std::string::npos)
- return false;
- if (start_pos >= end_pos)
- return false;
-
- working = working.substr(start_pos, end_pos - start_pos);
- if (working.length() == 0)
- return false;
- }
-
- return base::Base64Decode(working, output);
-}
-
-bool Extension::ProducePEM(const std::string& input, std::string* output) {
- DCHECK(output);
- if (input.length() == 0)
- return false;
-
- return base::Base64Encode(input, output);
-}
-
-bool Extension::FormatPEMForFileOutput(const std::string& input,
- std::string* output,
- bool is_public) {
- DCHECK(output);
- if (input.length() == 0)
+ ListValue* mime_types = NULL;
+ if (!intent_service.HasKey(keys::kIntentType) ||
+ !intent_service.GetList(keys::kIntentType, &mime_types) ||
+ mime_types->GetSize() == 0) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentType, action_name);
return false;
- *output = "";
- output->append(kKeyBeginHeaderMarker);
- output->append(" ");
- output->append(is_public ? kPublic : kPrivate);
- output->append(" ");
- output->append(kKeyInfoEndMarker);
- output->append("\n");
- for (size_t i = 0; i < input.length(); ) {
- int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
- output->append(input.substr(i, slice));
- output->append("\n");
- i += slice;
- }
- output->append(kKeyBeginFooterMarker);
- output->append(" ");
- output->append(is_public ? kPublic : kPrivate);
- output->append(" ");
- output->append(kKeyInfoEndMarker);
- output->append("\n");
-
- return true;
-}
-
-// static
-void Extension::DecodeIcon(const Extension* extension,
- ExtensionIconSet::Icons preferred_icon_size,
- ExtensionIconSet::MatchType match_type,
- scoped_ptr<SkBitmap>* result) {
- std::string path = extension->icons().Get(preferred_icon_size, match_type);
- ExtensionIconSet::Icons size = extension->icons().GetIconSizeFromPath(path);
- ExtensionResource icon_resource = extension->GetResource(path);
- DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
-}
-
-// static
-void Extension::DecodeIcon(const Extension* extension,
- ExtensionIconSet::Icons icon_size,
- scoped_ptr<SkBitmap>* result) {
- DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
-}
-
-// static
-void Extension::DecodeIconFromPath(const FilePath& icon_path,
- ExtensionIconSet::Icons icon_size,
- scoped_ptr<SkBitmap>* result) {
- if (icon_path.empty())
- return;
-
- std::string file_contents;
- if (!file_util::ReadFileToString(icon_path, &file_contents)) {
- DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
- return;
- }
-
- // Decode the image using WebKit's image decoder.
- const unsigned char* data =
- reinterpret_cast<const unsigned char*>(file_contents.data());
- webkit_glue::ImageDecoder decoder;
- scoped_ptr<SkBitmap> decoded(new SkBitmap());
- *decoded = decoder.Decode(data, file_contents.length());
- if (decoded->empty()) {
- DLOG(ERROR) << "Could not decode icon file: "
- << icon_path.LossyDisplayName();
- return;
- }
-
- if (decoded->width() != icon_size || decoded->height() != icon_size) {
- DLOG(ERROR) << "Icon file has unexpected size: "
- << base::IntToString(decoded->width()) << "x"
- << base::IntToString(decoded->height());
- return;
}
- result->swap(decoded);
-}
-
-// static
-const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
- if (is_app) {
- return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_APP_DEFAULT_ICON);
- } else {
- return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_EXTENSION_DEFAULT_ICON);
+ std::string href;
+ if (intent_service.HasKey(keys::kIntentPath)) {
+ if (!intent_service.GetString(keys::kIntentPath, &href)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentHref);
+ return false;
+ }
}
-}
-
-GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
- return GURL(std::string(chrome::kExtensionScheme) +
- chrome::kStandardSchemeSeparator + extension_id + "/");
-}
-bool Extension::LoadManifestVersion(string16* error) {
- // Get the original value out of the dictionary so that we can validate it
- // more strictly.
- if (manifest_->value()->HasKey(keys::kManifestVersion)) {
- int manifest_version = 1;
- if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
- manifest_version < 1) {
- *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
+ if (intent_service.HasKey(keys::kIntentHref)) {
+ if (!href.empty()) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentHrefOldAndNewKey, action_name,
+ keys::kIntentPath, keys::kIntentHref);
+ return false;
+ }
+ if (!intent_service.GetString(keys::kIntentHref, &href)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentHref);
return false;
}
}
- manifest_version_ = manifest_->GetManifestVersion();
- if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
- manifest_version_ < kModernManifestVersion &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowLegacyExtensionManifests)) {
- *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
- return false;
+ if (!href.empty()) {
+ GURL service_url(href);
+ if (is_hosted_app()) {
+ // Hosted apps require an absolute URL for intents.
+ if (!service_url.is_valid() ||
+ !(web_extent().MatchesURL(service_url))) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentPageInHostedApp, action_name);
+ return false;
+ }
+ service.service_url = service_url;
+ } else {
+ // We do not allow absolute intent URLs in non-hosted apps.
+ if (service_url.is_valid()) {
+ *error =ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kCannotAccessPage, href);
+ return false;
+ }
+ service.service_url = GetResourceURL(href);
+ }
}
- return true;
-}
-
-// static
-bool Extension::InitExtensionID(extensions::Manifest* manifest,
- const FilePath& path,
- const std::string& explicit_id,
- int creation_flags,
- string16* error) {
- if (!explicit_id.empty()) {
- manifest->set_extension_id(explicit_id);
- return true;
+ if (intent_service.HasKey(keys::kIntentTitle) &&
+ !intent_service.GetString(keys::kIntentTitle, &service.title)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
+ return false;
}
- if (manifest->HasKey(keys::kPublicKey)) {
- std::string public_key;
- std::string public_key_bytes;
- std::string extension_id;
- if (!manifest->GetString(keys::kPublicKey, &public_key) ||
- !ParsePEMKeyBytes(public_key, &public_key_bytes) ||
- !GenerateId(public_key_bytes, &extension_id)) {
- *error = ASCIIToUTF16(errors::kInvalidKey);
+ if (intent_service.HasKey(keys::kIntentDisposition)) {
+ if (!intent_service.GetString(keys::kIntentDisposition, &value) ||
+ (value != values::kIntentDispositionWindow &&
+ value != values::kIntentDispositionInline)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentDisposition);
return false;
}
- manifest->set_extension_id(extension_id);
- return true;
+ if (value == values::kIntentDispositionInline) {
+ service.disposition =
+ webkit_glue::WebIntentServiceData::DISPOSITION_INLINE;
+ } else {
+ service.disposition =
+ webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW;
+ }
}
- if (creation_flags & REQUIRE_KEY) {
- *error = ASCIIToUTF16(errors::kInvalidKey);
- return false;
- } else {
- // If there is a path, we generate the ID from it. This is useful for
- // development mode, because it keeps the ID stable across restarts and
- // reloading the extension.
- std::string extension_id = GenerateIdForPath(path);
- if (extension_id.empty()) {
- NOTREACHED() << "Could not create ID from path.";
+ for (size_t i = 0; i < mime_types->GetSize(); ++i) {
+ if (!mime_types->GetString(i, &service.type)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentTypeElement, action_name,
+ std::string(base::IntToString(i)));
return false;
}
- manifest->set_extension_id(extension_id);
- return true;
+ intents_services_.push_back(service);
}
+ return true;
}
-bool Extension::InitFromValue(int flags, string16* error) {
+bool Extension::LoadWebIntentServices(string16* error) {
DCHECK(error);
- base::AutoLock auto_lock(runtime_data_lock_);
-
- // Initialize permissions with an empty, default permission set.
- runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
- optional_permission_set_ = new ExtensionPermissionSet();
- required_permission_set_ = new ExtensionPermissionSet();
-
- creation_flags_ = flags;
-
- if (!LoadManifestVersion(error))
- return false;
-
- // We don't ned to validate because InitExtensionID already did that.
- manifest_->GetString(keys::kPublicKey, &public_key_);
-
- // Initialize the URL.
- extension_url_ = Extension::GetBaseURLFromExtensionId(id());
+ if (!manifest_->HasKey(keys::kIntents))
+ return true;
- // Initialize version.
- std::string version_str;
- if (!manifest_->GetString(keys::kVersion, &version_str)) {
- *error = ASCIIToUTF16(errors::kInvalidVersion);
- return false;
- }
- version_.reset(Version::GetVersionFromString(version_str));
- if (!version_.get() ||
- version_->components().size() > 4) {
- *error = ASCIIToUTF16(errors::kInvalidVersion);
+ DictionaryValue* all_services = NULL;
+ if (!manifest_->GetDictionary(keys::kIntents, &all_services)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntents);
return false;
}
- // Initialize name.
- string16 localized_name;
- if (!manifest_->GetString(keys::kName, &localized_name)) {
- *error = ASCIIToUTF16(errors::kInvalidName);
- return false;
+ for (DictionaryValue::key_iterator iter(all_services->begin_keys());
+ iter != all_services->end_keys(); ++iter) {
+ // Any entry in the intents dictionary can either have a list of
+ // dictionaries, or just a single dictionary attached to that. Try
+ // lists first, fall back to single dictionary.
+ ListValue* service_list = NULL;
+ DictionaryValue* one_service = NULL;
+ if (all_services->GetListWithoutPathExpansion(*iter, &service_list)) {
+ for (size_t i = 0; i < service_list->GetSize(); ++i) {
+ if (!service_list->GetDictionary(i, &one_service)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntent);
+ return false;
+ }
+ if (!LoadWebIntentAction(*iter, *one_service, error))
+ return false;
+ }
+ } else {
+ if (!all_services->GetDictionaryWithoutPathExpansion(*iter,
+ &one_service)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntent);
+ return false;
+ }
+ if (!LoadWebIntentAction(*iter, *one_service, error))
+ return false;
+ }
}
- base::i18n::AdjustStringForLocaleDirection(&localized_name);
- name_ = UTF16ToUTF8(localized_name);
+ return true;
+}
+bool Extension::LoadExtensionFeatures(
+ const ExtensionAPIPermissionSet& api_permissions,
+ string16* error) {
+ if (manifest_->HasKey(keys::kConvertedFromUserScript))
+ manifest_->GetBoolean(keys::kConvertedFromUserScript,
+ &converted_from_user_script_);
- // 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(keys::kWebURLs, &extent_,errors::kInvalidWebURLs,
- errors::kInvalidWebURL, error) ||
- !LoadLaunchURL(error) ||
- !LoadLaunchContainer(error))) {
+ if (!LoadDevToolsPage(error) ||
+ !LoadInputComponents(api_permissions, error) ||
+ !LoadContentScripts(error) ||
+ !LoadPageAction(error) ||
+ !LoadBrowserAction(error) ||
+ !LoadFileBrowserHandlers(error) ||
+ !LoadChromeURLOverrides(error) ||
+ !LoadOmnibox(error) ||
+ !LoadTextToSpeechVoices(error) ||
+ !LoadIncognitoMode(error) ||
+ !LoadContentSecurityPolicy(error))
return false;
- }
- if (is_platform_app()) {
- if (launch_container() != extension_misc::LAUNCH_SHELL) {
- *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform);
- return false;
- }
- } else if (launch_container() == extension_misc::LAUNCH_SHELL) {
- *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform);
- return false;
- }
+ return true;
+}
- // Initialize the permissions (optional).
- ExtensionAPIPermissionSet api_permissions;
- URLPatternSet host_permissions;
- if (!ParsePermissions(keys::kPermissions,
- flags,
- error,
- &api_permissions,
- &host_permissions)) {
+bool Extension::LoadDevToolsPage(string16* error) {
+ if (!manifest_->HasKey(keys::kDevToolsPage))
+ return true;
+ std::string devtools_str;
+ if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
return false;
}
-
- // Initialize the optional permissions (optional).
- ExtensionAPIPermissionSet optional_api_permissions;
- URLPatternSet optional_host_permissions;
- if (!ParsePermissions(keys::kOptionalPermissions,
- flags,
- error,
- &optional_api_permissions,
- &optional_host_permissions)) {
+ devtools_url_ = GetResourceURL(devtools_str);
+ return true;
+}
+
+bool Extension::LoadInputComponents(
+ const ExtensionAPIPermissionSet& api_permissions,
+ string16* error) {
+ if (!manifest_->HasKey(keys::kInputComponents))
+ return true;
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kInputComponents, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidInputComponents);
return false;
}
- // Initialize description (if present).
- if (manifest_->HasKey(keys::kDescription)) {
- if (!manifest_->GetString(keys::kDescription, &description_)) {
- *error = ASCIIToUTF16(errors::kInvalidDescription);
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* module_value = NULL;
+ std::string name_str;
+ InputComponentType type;
+ std::string id_str;
+ std::string description_str;
+ std::string language_str;
+ std::set<std::string> layouts;
+ std::string shortcut_keycode_str;
+ bool shortcut_alt = false;
+ bool shortcut_ctrl = false;
+ bool shortcut_shift = false;
+
+ if (!list_value->GetDictionary(i, &module_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidInputComponents);
return false;
}
- }
- // Initialize homepage url (if present).
- if (manifest_->HasKey(keys::kHomepageURL)) {
- std::string tmp;
- if (!manifest_->GetString(keys::kHomepageURL, &tmp)) {
+ // Get input_components[i].name.
+ if (!module_value->GetString(keys::kName, &name_str)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidHomepageURL, "");
+ errors::kInvalidInputComponentName, base::IntToString(i));
return false;
}
- homepage_url_ = GURL(tmp);
- if (!homepage_url_.is_valid() ||
- (!homepage_url_.SchemeIs("http") &&
- !homepage_url_.SchemeIs("https"))) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidHomepageURL, tmp);
- return false;
- }
- }
- // Initialize update url (if present).
- if (manifest_->HasKey(keys::kUpdateURL)) {
- std::string tmp;
- if (!manifest_->GetString(keys::kUpdateURL, &tmp)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidUpdateURL, "");
- return false;
- }
- update_url_ = GURL(tmp);
- if (!update_url_.is_valid() ||
- update_url_.has_ref()) {
+ // Get input_components[i].type.
+ std::string type_str;
+ if (module_value->GetString(keys::kType, &type_str)) {
+ if (type_str == "ime") {
+ type = INPUT_COMPONENT_TYPE_IME;
+ } else if (type_str == "virtual_keyboard") {
+ if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
+ // Virtual Keyboards require the experimental flag.
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentType, base::IntToString(i));
+ return false;
+ }
+ type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD;
+ } else {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentType, base::IntToString(i));
+ return false;
+ }
+ } else {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidUpdateURL, tmp);
- return false;
- }
- }
-
- // 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)) {
- std::string minimum_version_string;
- if (!manifest_->GetString(keys::kMinimumChromeVersion,
- &minimum_version_string)) {
- *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
+ errors::kInvalidInputComponentType, base::IntToString(i));
return false;
}
- scoped_ptr<Version> minimum_version(
- Version::GetVersionFromString(minimum_version_string));
- if (!minimum_version.get()) {
- *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
- return false;
+ // Get input_components[i].id.
+ if (!module_value->GetString(keys::kId, &id_str)) {
+ id_str = "";
}
- chrome::VersionInfo current_version_info;
- if (!current_version_info.is_valid()) {
- NOTREACHED();
+ // Get input_components[i].description.
+ if (!module_value->GetString(keys::kDescription, &description_str)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentDescription, base::IntToString(i));
return false;
}
-
- scoped_ptr<Version> current_version(
- Version::GetVersionFromString(current_version_info.Version()));
- if (!current_version.get()) {
- DCHECK(false);
- return false;
+ // Get input_components[i].language.
+ if (!module_value->GetString(keys::kLanguage, &language_str)) {
+ language_str = "";
}
- if (current_version->CompareTo(*minimum_version) < 0) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kChromeVersionTooLow,
- l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
- minimum_version_string);
+ // Get input_components[i].layouts.
+ ListValue* layouts_value = NULL;
+ if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
return false;
}
- }
-
- // Initialize converted_from_user_script (if present)
- if (manifest_->HasKey(keys::kConvertedFromUserScript))
- manifest_->GetBoolean(keys::kConvertedFromUserScript,
- &converted_from_user_script_);
- // Initialize commands (if present).
- if (manifest_->HasKey(keys::kCommands)) {
- DictionaryValue* commands = NULL;
- if (!manifest_->GetDictionary(keys::kCommands, &commands)) {
- *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
- return false;
+ for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
+ std::string layout_name_str;
+ if (!layouts_value->GetString(j, &layout_name_str)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentLayoutName, base::IntToString(i),
+ base::IntToString(j));
+ return false;
+ }
+ layouts.insert(layout_name_str);
}
- int command_index = 0;
- for (DictionaryValue::key_iterator iter = commands->begin_keys();
- iter != commands->end_keys(); ++iter) {
- ++command_index;
+ if (module_value->HasKey(keys::kShortcutKey)) {
+ DictionaryValue* shortcut_value = NULL;
+ if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
+ return false;
+ }
- DictionaryValue* command = NULL;
- if (!commands->GetDictionary(*iter, &command)) {
+ // Get input_components[i].shortcut_keycode.
+ if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidKeyBindingDictionary,
- base::IntToString(command_index));
+ errors::kInvalidInputComponentShortcutKeycode,
+ base::IntToString(i));
return false;
}
- ExtensionKeybinding binding;
- if (!binding.Parse(command, *iter, command_index, error))
- return false; // |error| already set.
+ // Get input_components[i].shortcut_alt.
+ if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
+ shortcut_alt = false;
+ }
- commands_.push_back(binding);
- }
- }
+ // Get input_components[i].shortcut_ctrl.
+ if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
+ shortcut_ctrl = false;
+ }
- // Initialize icons (if present).
- if (manifest_->HasKey(keys::kIcons)) {
- DictionaryValue* icons_value = NULL;
- if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) {
- *error = ASCIIToUTF16(errors::kInvalidIcons);
- return false;
+ // Get input_components[i].shortcut_shift.
+ if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
+ shortcut_shift = false;
+ }
}
- for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) {
- std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]);
- if (icons_value->HasKey(key)) {
- std::string icon_path;
- if (!icons_value->GetString(key, &icon_path)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIconPath, key);
- return false;
- }
+ input_components_.push_back(InputComponentInfo());
+ input_components_.back().name = name_str;
+ input_components_.back().type = type;
+ input_components_.back().id = id_str;
+ input_components_.back().description = description_str;
+ input_components_.back().language = language_str;
+ input_components_.back().layouts.insert(layouts.begin(), layouts.end());
+ input_components_.back().shortcut_keycode = shortcut_keycode_str;
+ input_components_.back().shortcut_alt = shortcut_alt;
+ input_components_.back().shortcut_ctrl = shortcut_ctrl;
+ input_components_.back().shortcut_shift = shortcut_shift;
+ }
- if (!icon_path.empty() && icon_path[0] == '/')
- icon_path = icon_path.substr(1);
+ return true;
+}
- if (icon_path.empty()) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIconPath, key);
- return false;
- }
+bool Extension::LoadContentScripts(string16* error) {
+ if (!manifest_->HasKey(keys::kContentScripts))
+ return true;
+ ListValue* list_value;
+ if (!manifest_->GetList(keys::kContentScripts, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidContentScriptsList);
+ return false;
+ }
- icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path);
- }
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* content_script = NULL;
+ if (!list_value->GetDictionary(i, &content_script)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidContentScript, base::IntToString(i));
+ return false;
+ }
+
+ UserScript script;
+ if (!LoadUserScriptHelper(content_script, i, error, &script))
+ return false; // Failed to parse script context definition.
+ script.set_extension_id(id());
+ if (converted_from_user_script_) {
+ script.set_emulate_greasemonkey(true);
+ script.set_match_all_frames(true); // Greasemonkey matches all frames.
}
+ content_scripts_.push_back(script);
}
+ return true;
+}
+
+bool Extension::LoadPageAction(string16* error) {
+ DictionaryValue* page_action_value = NULL;
- // Initialize themes (if present).
- if (manifest_->HasKey(keys::kTheme)) {
- DictionaryValue* theme_value = NULL;
- if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
- *error = ASCIIToUTF16(errors::kInvalidTheme);
+ if (manifest_->HasKey(keys::kPageActions)) {
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kPageActions, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
return false;
}
- DictionaryValue* images_value = NULL;
- if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
- // Validate that the images are all strings
- for (DictionaryValue::key_iterator iter = images_value->begin_keys();
- iter != images_value->end_keys(); ++iter) {
- std::string val;
- if (!images_value->GetString(*iter, &val)) {
- *error = ASCIIToUTF16(errors::kInvalidThemeImages);
- return false;
- }
- }
- theme_images_.reset(images_value->DeepCopy());
- }
-
- DictionaryValue* colors_value = NULL;
- if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
- // Validate that the colors are RGB or RGBA lists
- for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
- iter != colors_value->end_keys(); ++iter) {
- ListValue* color_list = NULL;
- double alpha = 0.0;
- int color = 0;
- // The color must be a list
- if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
- // And either 3 items (RGB) or 4 (RGBA)
- ((color_list->GetSize() != 3) &&
- ((color_list->GetSize() != 4) ||
- // For RGBA, the fourth item must be a real or int alpha value.
- // Note that GetDouble() can get an integer value.
- !color_list->GetDouble(3, &alpha))) ||
- // For both RGB and RGBA, the first three items must be ints (R,G,B)
- !color_list->GetInteger(0, &color) ||
- !color_list->GetInteger(1, &color) ||
- !color_list->GetInteger(2, &color)) {
- *error = ASCIIToUTF16(errors::kInvalidThemeColors);
- return false;
- }
- }
- theme_colors_.reset(colors_value->DeepCopy());
- }
-
- DictionaryValue* tints_value = NULL;
- if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
- // Validate that the tints are all reals.
- for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
- iter != tints_value->end_keys(); ++iter) {
- ListValue* tint_list = NULL;
- double v = 0.0;
- if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
- tint_list->GetSize() != 3 ||
- !tint_list->GetDouble(0, &v) ||
- !tint_list->GetDouble(1, &v) ||
- !tint_list->GetDouble(2, &v)) {
- *error = ASCIIToUTF16(errors::kInvalidThemeTints);
- return false;
- }
+ size_t list_value_length = list_value->GetSize();
+
+ if (list_value_length == 0u) {
+ // A list with zero items is allowed, and is equivalent to not having
+ // a page_actions key in the manifest. Don't set |page_action_value|.
+ } else if (list_value_length == 1u) {
+ if (!list_value->GetDictionary(0, &page_action_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageAction);
+ return false;
}
- theme_tints_.reset(tints_value->DeepCopy());
+ } else { // list_value_length > 1u.
+ *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize);
+ return false;
}
-
- DictionaryValue* display_properties_value = NULL;
- if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
- &display_properties_value)) {
- theme_display_properties_.reset(
- display_properties_value->DeepCopy());
+ } else if (manifest_->HasKey(keys::kPageAction)) {
+ if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageAction);
+ return false;
}
+ }
+
+ // If page_action_value is not NULL, then there was a valid page action.
+ if (page_action_value) {
+ page_action_.reset(
+ LoadExtensionActionHelper(page_action_value, error));
+ if (!page_action_.get())
+ return false; // Failed to parse page action definition.
+ }
+
+ return true;
+}
+bool Extension::LoadBrowserAction(string16* error) {
+ if (!manifest_->HasKey(keys::kBrowserAction))
return true;
+ DictionaryValue* browser_action_value = NULL;
+ if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
+ return false;
}
- // Initialize plugins (optional).
- if (manifest_->HasKey(keys::kPlugins)) {
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kPlugins, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPlugins);
- return false;
+ browser_action_.reset(
+ LoadExtensionActionHelper(browser_action_value, error));
+ if (!browser_action_.get())
+ return false; // Failed to parse browser action definition.
+ return true;
+}
+
+bool Extension::LoadFileBrowserHandlers(string16* error) {
+ if (!manifest_->HasKey(keys::kFileBrowserHandlers))
+ return true;
+ ListValue* file_browser_handlers_value = NULL;
+ if (!manifest_->GetList(keys::kFileBrowserHandlers,
+ &file_browser_handlers_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
+ return false;
+ }
+ file_browser_handlers_.reset(
+ LoadFileBrowserHandlersHelper(file_browser_handlers_value, error));
+ if (!file_browser_handlers_.get())
+ return false; // Failed to parse file browser actions definition.
+ return true;
+}
+
+Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlersHelper(
+ const ListValue* extension_actions, string16* error) {
+ scoped_ptr<FileBrowserHandlerList> result(
+ new FileBrowserHandlerList());
+ for (ListValue::const_iterator iter = extension_actions->begin();
+ iter != extension_actions->end();
+ ++iter) {
+ if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
+ *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
+ return NULL;
}
+ scoped_ptr<FileBrowserHandler> action(
+ LoadFileBrowserHandler(
+ reinterpret_cast<DictionaryValue*>(*iter), error));
+ if (!action.get())
+ return NULL; // Failed to parse file browser action definition.
+ result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
+ }
+ return result.release();
+}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* plugin_value = NULL;
- std::string path_str;
- bool is_public = false;
+FileBrowserHandler* Extension::LoadFileBrowserHandler(
+ const DictionaryValue* file_browser_handler, string16* error) {
+ scoped_ptr<FileBrowserHandler> result(
+ new FileBrowserHandler());
+ result->set_extension_id(id());
- if (!list_value->GetDictionary(i, &plugin_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPlugins);
- return false;
- }
+ std::string id;
+ // Read the file action |id| (mandatory).
+ if (!file_browser_handler->HasKey(keys::kPageActionId) ||
+ !file_browser_handler->GetString(keys::kPageActionId, &id)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionId);
+ return NULL;
+ }
+ result->set_id(id);
- // Get plugins[i].path.
- if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPluginsPath, base::IntToString(i));
- return false;
- }
+ // Read the page action title from |default_title| (mandatory).
+ std::string title;
+ if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
+ !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
+ return NULL;
+ }
+ result->set_title(title);
- // Get plugins[i].content (optional).
- if (plugin_value->HasKey(keys::kPluginsPublic)) {
- if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPluginsPublic, base::IntToString(i));
- return false;
- }
- }
+ // Initialize file filters (mandatory).
+ ListValue* list_value = NULL;
+ if (!file_browser_handler->HasKey(keys::kFileFilters) ||
+ !file_browser_handler->GetList(keys::kFileFilters, &list_value) ||
+ list_value->empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidFileFiltersList);
+ return NULL;
+ }
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ std::string filter;
+ if (!list_value->GetString(i, &filter)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileFilterValue, base::IntToString(i));
+ return NULL;
+ }
+ StringToLowerASCII(&filter);
+ URLPattern pattern(URLPattern::SCHEME_FILESYSTEM);
+ if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ std::string path = pattern.path();
+ bool allowed = path == "*" || path == "*.*" ||
+ (path.compare(0, 2, "*.") == 0 &&
+ path.find_first_of('*', 2) == std::string::npos);
+ if (!allowed) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ result->AddPattern(pattern);
+ }
- // We don't allow extension plugins to run on Chrome OS. We still
- // parse the manifest entry so that error messages are consistently
- // displayed across platforms.
-#if !defined(OS_CHROMEOS)
- plugins_.push_back(PluginInfo());
- plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
- plugins_.back().is_public = is_public;
-#endif
+ std::string default_icon;
+ // Read the file browser action |default_icon| (optional).
+ if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
+ if (!file_browser_handler->GetString(
+ keys::kPageActionDefaultIcon, &default_icon) ||
+ default_icon.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
+ return NULL;
}
+ result->set_icon_path(default_icon);
}
- if (manifest_->HasKey(keys::kNaClModules)) {
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kNaClModules, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidNaClModules);
+ return result.release();
+}
+
+bool Extension::LoadChromeURLOverrides(string16* error) {
+ if (!manifest_->HasKey(keys::kChromeURLOverrides))
+ return true;
+ DictionaryValue* overrides = NULL;
+ if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
+ *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ return false;
+ }
+
+ // Validate that the overrides are all strings
+ for (DictionaryValue::key_iterator iter = overrides->begin_keys();
+ iter != overrides->end_keys(); ++iter) {
+ std::string page = *iter;
+ std::string val;
+ // Restrict override pages to a list of supported URLs.
+ if ((page != chrome::kChromeUINewTabHost &&
+#if defined(USE_VIRTUAL_KEYBOARD)
+ page != chrome::kChromeUIKeyboardHost &&
+#endif
+#if defined(OS_CHROMEOS)
+ page != chrome::kChromeUIActivationMessageHost &&
+#endif
+ page != chrome::kChromeUIBookmarksHost &&
+ page != chrome::kChromeUIHistoryHost
+#if defined(FILE_MANAGER_EXTENSION)
+ &&
+ !(location() == COMPONENT &&
+ page == chrome::kChromeUIFileManagerHost)
+#endif
+ ) ||
+ !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
+ *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
return false;
}
+ // Replace the entry with a fully qualified chrome-extension:// URL.
+ chrome_url_overrides_[page] = GetResourceURL(val);
+ }
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* module_value = NULL;
- std::string path_str;
- std::string mime_type;
-
- if (!list_value->GetDictionary(i, &module_value)) {
- *error = ASCIIToUTF16(errors::kInvalidNaClModules);
- return false;
- }
+ // An extension may override at most one page.
+ if (overrides->size() > 1) {
+ *error = ASCIIToUTF16(errors::kMultipleOverrides);
+ return false;
+ }
- // Get nacl_modules[i].path.
- if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidNaClModulesPath, base::IntToString(i));
- return false;
- }
+ return true;
+}
- // Get nacl_modules[i].mime_type.
- if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
- return false;
- }
+bool Extension::LoadOmnibox(string16* error) {
+ if (!manifest_->HasKey(keys::kOmnibox))
+ return true;
+ if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
+ omnibox_keyword_.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword);
+ return false;
+ }
+ return true;
+}
- nacl_modules_.push_back(NaClModuleInfo());
- nacl_modules_.back().url = GetResourceURL(path_str);
- nacl_modules_.back().mime_type = mime_type;
- }
+bool Extension::LoadTextToSpeechVoices(string16* error) {
+ if (!manifest_->HasKey(keys::kTtsEngine))
+ return true;
+ DictionaryValue* tts_dict = NULL;
+ if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) {
+ *error = ASCIIToUTF16(errors::kInvalidTts);
+ return false;
}
- // Initialize content scripts (optional).
- if (manifest_->HasKey(keys::kContentScripts)) {
- ListValue* list_value;
- if (!manifest_->GetList(keys::kContentScripts, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidContentScriptsList);
+ if (tts_dict->HasKey(keys::kTtsVoices)) {
+ ListValue* tts_voices = NULL;
+ if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
return false;
}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* content_script = NULL;
- if (!list_value->GetDictionary(i, &content_script)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidContentScript, base::IntToString(i));
+ for (size_t i = 0; i < tts_voices->GetSize(); i++) {
+ DictionaryValue* one_tts_voice = NULL;
+ if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
return false;
}
- UserScript script;
- if (!LoadUserScriptHelper(content_script, i, flags, error, &script))
- return false; // Failed to parse script context definition.
- script.set_extension_id(id());
- if (converted_from_user_script_) {
- script.set_emulate_greasemonkey(true);
- script.set_match_all_frames(true); // Greasemonkey matches all frames.
+ TtsVoice voice_data;
+ if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName);
+ return false;
+ }
}
- content_scripts_.push_back(script);
- }
- }
-
- // Initialize web accessible resources (optional).
- if (manifest_->HasKey(keys::kWebAccessibleResources)) {
- ListValue* list_value;
- if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList);
- return false;
- }
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- std::string relative_path;
- if (!list_value->GetString(i, &relative_path)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidWebAccessibleResource, base::IntToString(i));
- return false;
+ if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesLang, &voice_data.lang) ||
+ !l10n_util::IsValidLocaleSyntax(voice_data.lang)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang);
+ return false;
+ }
+ }
+ if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesGender, &voice_data.gender) ||
+ (voice_data.gender != keys::kTtsGenderMale &&
+ voice_data.gender != keys::kTtsGenderFemale)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender);
+ return false;
+ }
+ }
+ if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) {
+ ListValue* event_types_list;
+ if (!one_tts_voice->GetList(
+ keys::kTtsVoicesEventTypes, &event_types_list)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
+ return false;
+ }
+ for (size_t i = 0; i < event_types_list->GetSize(); i++) {
+ std::string event_type;
+ if (!event_types_list->GetString(i, &event_type)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
+ return false;
+ }
+ if (event_type != keys::kTtsVoicesEventTypeEnd &&
+ event_type != keys::kTtsVoicesEventTypeError &&
+ event_type != keys::kTtsVoicesEventTypeMarker &&
+ event_type != keys::kTtsVoicesEventTypeSentence &&
+ event_type != keys::kTtsVoicesEventTypeStart &&
+ event_type != keys::kTtsVoicesEventTypeWord) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
+ return false;
+ }
+ if (voice_data.event_types.find(event_type) !=
+ voice_data.event_types.end()) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
+ return false;
+ }
+ voice_data.event_types.insert(event_type);
+ }
}
- if (relative_path[0] != '/')
- relative_path = '/' + relative_path;
- web_accessible_resources_.insert(relative_path);
+
+ tts_voices_.push_back(voice_data);
}
}
+ return true;
+}
- // Initialize page action (optional).
- DictionaryValue* page_action_value = NULL;
+bool Extension::LoadIncognitoMode(string16* error) {
+ // Apps default to split mode, extensions default to spanning.
+ incognito_split_mode_ = is_app();
+ if (!manifest_->HasKey(keys::kIncognito))
+ return true;
+ std::string value;
+ if (!manifest_->GetString(keys::kIncognito, &value)) {
+ *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
+ return false;
+ }
+ if (value == values::kIncognitoSpanning) {
+ incognito_split_mode_ = false;
+ } else if (value == values::kIncognitoSplit) {
+ incognito_split_mode_ = true;
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
+ return false;
+ }
+ return true;
+}
- if (manifest_->HasKey(keys::kPageActions)) {
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kPageActions, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
+bool Extension::LoadContentSecurityPolicy(string16* error) {
+ if (manifest_->HasKey(keys::kContentSecurityPolicy)) {
+ std::string content_security_policy;
+ if (!manifest_->GetString(keys::kContentSecurityPolicy,
+ &content_security_policy)) {
+ *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
return false;
}
-
- size_t list_value_length = list_value->GetSize();
-
- if (list_value_length == 0u) {
- // A list with zero items is allowed, and is equivalent to not having
- // a page_actions key in the manifest. Don't set |page_action_value|.
- } else if (list_value_length == 1u) {
- if (!list_value->GetDictionary(0, &page_action_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPageAction);
- return false;
- }
- } else { // list_value_length > 1u.
- *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize);
+ if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
+ *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
return false;
}
- } else if (manifest_->HasKey(keys::kPageAction)) {
- if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPageAction);
+ if (manifest_version_ >= 2 &&
+ !ContentSecurityPolicyIsSecure(content_security_policy)) {
+ *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
return false;
}
- }
- // If page_action_value is not NULL, then there was a valid page action.
- if (page_action_value) {
- page_action_.reset(
- LoadExtensionActionHelper(page_action_value, error));
- if (!page_action_.get())
- return false; // Failed to parse page action definition.
+ content_security_policy_ = content_security_policy;
+ } else if (manifest_version_ >= 2) {
+ // Manifest version 2 introduced a default Content-Security-Policy.
+ // TODO(abarth): Should we continue to let extensions override the
+ // default Content-Security-Policy?
+ content_security_policy_ = kDefaultContentSecurityPolicy;
+ CHECK(ContentSecurityPolicyIsSecure(content_security_policy_));
}
+ return true;
+}
- // Initialize browser action (optional).
- if (manifest_->HasKey(keys::kBrowserAction)) {
- DictionaryValue* browser_action_value = NULL;
- if (!manifest_->GetDictionary(keys::kBrowserAction,
- &browser_action_value)) {
- *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
- return false;
- }
+bool Extension::LoadAppIsolation(string16* error) {
+ Value* temp = NULL;
+ if (!manifest_->Get(keys::kIsolation, &temp))
+ return true;
- browser_action_.reset(
- LoadExtensionActionHelper(browser_action_value, error));
- if (!browser_action_.get())
- return false; // Failed to parse browser action definition.
+ if (temp->GetType() != Value::TYPE_LIST) {
+ *error = ASCIIToUTF16(errors::kInvalidIsolation);
+ return false;
}
- // Initialize file browser actions (optional).
- if (manifest_->HasKey(keys::kFileBrowserHandlers)) {
- ListValue* file_browser_handlers_value = NULL;
- if (!manifest_->GetList(keys::kFileBrowserHandlers,
- &file_browser_handlers_value)) {
- *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
+ ListValue* isolation_list = static_cast<ListValue*>(temp);
+ for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
+ std::string isolation_string;
+ if (!isolation_list->GetString(i, &isolation_string)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIsolationValue,
+ base::UintToString(i));
return false;
}
- file_browser_handlers_.reset(
- LoadFileBrowserHandlers(file_browser_handlers_value, error));
- if (!file_browser_handlers_.get())
- return false; // Failed to parse file browser actions definition.
+ // Check for isolated storage.
+ if (isolation_string == values::kIsolatedStorage) {
+ is_storage_isolated_ = true;
+ } else {
+ DLOG(WARNING) << "Did not recognize isolation type: "
+ << isolation_string;
+ }
}
+ return true;
+}
- // App isolation.
- if (api_permissions.count(ExtensionAPIPermission::kExperimental)) {
- if (is_app() && !LoadAppIsolation(error))
- return false;
+bool Extension::LoadThemeFeatures(string16* error) {
+ if (!manifest_->HasKey(keys::kTheme))
+ return true;
+ DictionaryValue* theme_value = NULL;
+ if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidTheme);
+ return false;
}
+ if (!LoadThemeImages(theme_value, error))
+ return false;
+ if (!LoadThemeColors(theme_value, error))
+ return false;
+ if (!LoadThemeTints(theme_value, error))
+ return false;
+ if (!LoadThemeDisplayProperties(theme_value, error))
+ return false;
- // Initialize options page url (optional).
- if (manifest_->HasKey(keys::kOptionsPage)) {
- std::string options_str;
- if (!manifest_->GetString(keys::kOptionsPage, &options_str)) {
- *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
- return false;
- }
+ return true;
+}
- if (is_hosted_app()) {
- // hosted apps require an absolute URL.
- GURL options_url(options_str);
- if (!options_url.is_valid() ||
- !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
- *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
+bool Extension::LoadThemeImages(const DictionaryValue* theme_value,
+ string16* error) {
+ DictionaryValue* images_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
+ // Validate that the images are all strings
+ for (DictionaryValue::key_iterator iter = images_value->begin_keys();
+ iter != images_value->end_keys(); ++iter) {
+ std::string val;
+ if (!images_value->GetString(*iter, &val)) {
+ *error = ASCIIToUTF16(errors::kInvalidThemeImages);
return false;
}
- options_url_ = options_url;
- } else {
- GURL absolute(options_str);
- if (absolute.is_valid()) {
- *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
+ }
+ theme_images_.reset(images_value->DeepCopy());
+ }
+ return true;
+}
+
+bool Extension::LoadThemeColors(const DictionaryValue* theme_value,
+ string16* error) {
+ DictionaryValue* colors_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
+ // Validate that the colors are RGB or RGBA lists
+ for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
+ iter != colors_value->end_keys(); ++iter) {
+ ListValue* color_list = NULL;
+ double alpha = 0.0;
+ int color = 0;
+ // The color must be a list
+ if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
+ // And either 3 items (RGB) or 4 (RGBA)
+ ((color_list->GetSize() != 3) &&
+ ((color_list->GetSize() != 4) ||
+ // For RGBA, the fourth item must be a real or int alpha value.
+ // Note that GetDouble() can get an integer value.
+ !color_list->GetDouble(3, &alpha))) ||
+ // For both RGB and RGBA, the first three items must be ints (R,G,B)
+ !color_list->GetInteger(0, &color) ||
+ !color_list->GetInteger(1, &color) ||
+ !color_list->GetInteger(2, &color)) {
+ *error = ASCIIToUTF16(errors::kInvalidThemeColors);
return false;
}
- options_url_ = GetResourceURL(options_str);
- if (!options_url_.is_valid()) {
- *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
+ }
+ theme_colors_.reset(colors_value->DeepCopy());
+ }
+ return true;
+}
+
+bool Extension::LoadThemeTints(const DictionaryValue* theme_value,
+ string16* error) {
+ DictionaryValue* tints_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
+ // Validate that the tints are all reals.
+ for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
+ iter != tints_value->end_keys(); ++iter) {
+ ListValue* tint_list = NULL;
+ double v = 0.0;
+ if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
+ tint_list->GetSize() != 3 ||
+ !tint_list->GetDouble(0, &v) ||
+ !tint_list->GetDouble(1, &v) ||
+ !tint_list->GetDouble(2, &v)) {
+ *error = ASCIIToUTF16(errors::kInvalidThemeTints);
return false;
}
}
+ theme_tints_.reset(tints_value->DeepCopy());
}
+ return true;
+}
- if (!LoadBackgroundScripts(error))
- return false;
+bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value,
+ string16* error) {
+ DictionaryValue* display_properties_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
+ &display_properties_value)) {
+ theme_display_properties_.reset(
+ display_properties_value->DeepCopy());
+ }
+ return true;
+}
- if (!LoadBackgroundPage(api_permissions, error))
- return false;
+// static
+bool Extension::IsTrustedId(const std::string& id) {
+ // See http://b/4946060 for more details.
+ return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
+}
- if (!LoadBackgroundPersistent(api_permissions, error))
- return false;
+Extension::Extension(const FilePath& path,
+ scoped_ptr<extensions::Manifest> manifest)
+ : manifest_version_(0),
+ incognito_split_mode_(false),
+ offline_enabled_(false),
+ converted_from_user_script_(false),
+ background_page_persists_(true),
+ allow_background_js_access_(true),
+ manifest_(manifest.release()),
+ is_storage_isolated_(false),
+ launch_container_(extension_misc::LAUNCH_TAB),
+ launch_width_(0),
+ launch_height_(0),
+ launch_min_width_(0),
+ launch_min_height_(0),
+ launch_max_width_(0),
+ launch_max_height_(0),
+ wants_file_access_(false),
+ creation_flags_(0) {
+ DCHECK(path.empty() || path.IsAbsolute());
+ path_ = MaybeNormalizePath(path);
+}
+
+Extension::~Extension() {
+ if (manifest_)
+ delete manifest_;
+}
+
+ExtensionResource Extension::GetResource(
+ const std::string& relative_path) const {
+#if defined(OS_POSIX)
+ FilePath relative_file_path(relative_path);
+#elif defined(OS_WIN)
+ FilePath relative_file_path(UTF8ToWide(relative_path));
+#endif
+ return ExtensionResource(id(), path(), relative_file_path);
+}
+
+ExtensionResource Extension::GetResource(
+ const FilePath& relative_file_path) const {
+ return ExtensionResource(id(), path(), relative_file_path);
+}
- if (!LoadBackgroundAllowJsAccess(api_permissions, error))
+// TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
+// util class in base:
+// http://code.google.com/p/chromium/issues/detail?id=13572
+bool Extension::ParsePEMKeyBytes(const std::string& input,
+ std::string* output) {
+ DCHECK(output);
+ if (!output)
+ return false;
+ if (input.length() == 0)
return false;
- if (manifest_->HasKey(keys::kDefaultLocale)) {
- if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) ||
- !l10n_util::IsValidLocaleSyntax(default_locale_)) {
- *error = ASCIIToUTF16(errors::kInvalidDefaultLocale);
+ std::string working = input;
+ if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
+ working = CollapseWhitespaceASCII(working, true);
+ size_t header_pos = working.find(kKeyInfoEndMarker,
+ sizeof(kKeyBeginHeaderMarker) - 1);
+ if (header_pos == std::string::npos)
return false;
- }
- }
-
- // Chrome URL overrides (optional)
- if (manifest_->HasKey(keys::kChromeURLOverrides)) {
- DictionaryValue* overrides = NULL;
- if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
- *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
+ size_t end_pos = working.rfind(kKeyBeginFooterMarker);
+ if (end_pos == std::string::npos)
+ return false;
+ if (start_pos >= end_pos)
return false;
- }
-
- // Validate that the overrides are all strings
- for (DictionaryValue::key_iterator iter = overrides->begin_keys();
- iter != overrides->end_keys(); ++iter) {
- std::string page = *iter;
- std::string val;
- // Restrict override pages to a list of supported URLs.
- if ((page != chrome::kChromeUINewTabHost &&
-#if defined(USE_VIRTUAL_KEYBOARD)
- page != chrome::kChromeUIKeyboardHost &&
-#endif
-#if defined(OS_CHROMEOS)
- page != chrome::kChromeUIActivationMessageHost &&
-#endif
- page != chrome::kChromeUIBookmarksHost &&
- page != chrome::kChromeUIHistoryHost
-#if defined(FILE_MANAGER_EXTENSION)
- &&
- !(location() == COMPONENT &&
- page == chrome::kChromeUIFileManagerHost)
-#endif
- ) ||
- !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
- *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
- return false;
- }
- // Replace the entry with a fully qualified chrome-extension:// URL.
- chrome_url_overrides_[page] = GetResourceURL(val);
- }
- // An extension may override at most one page.
- if (overrides->size() > 1) {
- *error = ASCIIToUTF16(errors::kMultipleOverrides);
+ working = working.substr(start_pos, end_pos - start_pos);
+ if (working.length() == 0)
return false;
- }
}
- if (manifest_->HasKey(keys::kInputComponents)) {
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kInputComponents, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidInputComponents);
- return false;
- }
+ return base::Base64Decode(working, output);
+}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* module_value = NULL;
- std::string name_str;
- InputComponentType type;
- std::string id_str;
- std::string description_str;
- std::string language_str;
- std::set<std::string> layouts;
- std::string shortcut_keycode_str;
- bool shortcut_alt = false;
- bool shortcut_ctrl = false;
- bool shortcut_shift = false;
+bool Extension::ProducePEM(const std::string& input, std::string* output) {
+ DCHECK(output);
+ if (input.length() == 0)
+ return false;
- if (!list_value->GetDictionary(i, &module_value)) {
- *error = ASCIIToUTF16(errors::kInvalidInputComponents);
- return false;
- }
+ return base::Base64Encode(input, output);
+}
- // Get input_components[i].name.
- if (!module_value->GetString(keys::kName, &name_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentName, base::IntToString(i));
- return false;
- }
+bool Extension::FormatPEMForFileOutput(const std::string& input,
+ std::string* output,
+ bool is_public) {
+ DCHECK(output);
+ if (input.length() == 0)
+ return false;
+ *output = "";
+ output->append(kKeyBeginHeaderMarker);
+ output->append(" ");
+ output->append(is_public ? kPublic : kPrivate);
+ output->append(" ");
+ output->append(kKeyInfoEndMarker);
+ output->append("\n");
+ for (size_t i = 0; i < input.length(); ) {
+ int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
+ output->append(input.substr(i, slice));
+ output->append("\n");
+ i += slice;
+ }
+ output->append(kKeyBeginFooterMarker);
+ output->append(" ");
+ output->append(is_public ? kPublic : kPrivate);
+ output->append(" ");
+ output->append(kKeyInfoEndMarker);
+ output->append("\n");
- // Get input_components[i].type.
- std::string type_str;
- if (module_value->GetString(keys::kType, &type_str)) {
- if (type_str == "ime") {
- type = INPUT_COMPONENT_TYPE_IME;
- } else if (type_str == "virtual_keyboard") {
- if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
- // Virtual Keyboards require the experimental flag.
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentType, base::IntToString(i));
- return false;
- }
- type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD;
- } else {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentType, base::IntToString(i));
- return false;
- }
- } else {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentType, base::IntToString(i));
- return false;
- }
+ return true;
+}
- // Get input_components[i].id.
- if (!module_value->GetString(keys::kId, &id_str)) {
- id_str = "";
- }
+// static
+void Extension::DecodeIcon(const Extension* extension,
+ ExtensionIconSet::Icons preferred_icon_size,
+ ExtensionIconSet::MatchType match_type,
+ scoped_ptr<SkBitmap>* result) {
+ std::string path = extension->icons().Get(preferred_icon_size, match_type);
+ ExtensionIconSet::Icons size = extension->icons().GetIconSizeFromPath(path);
+ ExtensionResource icon_resource = extension->GetResource(path);
+ DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
+}
- // Get input_components[i].description.
- if (!module_value->GetString(keys::kDescription, &description_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentDescription, base::IntToString(i));
- return false;
- }
+// static
+void Extension::DecodeIcon(const Extension* extension,
+ ExtensionIconSet::Icons icon_size,
+ scoped_ptr<SkBitmap>* result) {
+ DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
+}
- // Get input_components[i].language.
- if (!module_value->GetString(keys::kLanguage, &language_str)) {
- language_str = "";
- }
+// static
+void Extension::DecodeIconFromPath(const FilePath& icon_path,
+ ExtensionIconSet::Icons icon_size,
+ scoped_ptr<SkBitmap>* result) {
+ if (icon_path.empty())
+ return;
- // Get input_components[i].layouts.
- ListValue* layouts_value = NULL;
- if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
- *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
- return false;
- }
+ std::string file_contents;
+ if (!file_util::ReadFileToString(icon_path, &file_contents)) {
+ DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
+ return;
+ }
- for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
- std::string layout_name_str;
- if (!layouts_value->GetString(j, &layout_name_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentLayoutName, base::IntToString(i),
- base::IntToString(j));
- return false;
- }
- layouts.insert(layout_name_str);
- }
+ // Decode the image using WebKit's image decoder.
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+ webkit_glue::ImageDecoder decoder;
+ scoped_ptr<SkBitmap> decoded(new SkBitmap());
+ *decoded = decoder.Decode(data, file_contents.length());
+ if (decoded->empty()) {
+ DLOG(ERROR) << "Could not decode icon file: "
+ << icon_path.LossyDisplayName();
+ return;
+ }
- if (module_value->HasKey(keys::kShortcutKey)) {
- DictionaryValue* shortcut_value = NULL;
- if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
- return false;
- }
+ if (decoded->width() != icon_size || decoded->height() != icon_size) {
+ DLOG(ERROR) << "Icon file has unexpected size: "
+ << base::IntToString(decoded->width()) << "x"
+ << base::IntToString(decoded->height());
+ return;
+ }
- // Get input_components[i].shortcut_keycode.
- if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentShortcutKeycode,
- base::IntToString(i));
- return false;
- }
+ result->swap(decoded);
+}
- // Get input_components[i].shortcut_alt.
- if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
- shortcut_alt = false;
- }
+// static
+const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
+ if (is_app) {
+ return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_APP_DEFAULT_ICON);
+ } else {
+ return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_EXTENSION_DEFAULT_ICON);
+ }
+}
- // Get input_components[i].shortcut_ctrl.
- if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
- shortcut_ctrl = false;
- }
+// static
+GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
+ return GURL(std::string(chrome::kExtensionScheme) +
+ chrome::kStandardSchemeSeparator + extension_id + "/");
+}
- // Get input_components[i].shortcut_shift.
- if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
- shortcut_shift = false;
- }
- }
+bool Extension::InitFromValue(int flags, string16* error) {
+ DCHECK(error);
- input_components_.push_back(InputComponentInfo());
- input_components_.back().name = name_str;
- input_components_.back().type = type;
- input_components_.back().id = id_str;
- input_components_.back().description = description_str;
- input_components_.back().language = language_str;
- input_components_.back().layouts.insert(layouts.begin(), layouts.end());
- input_components_.back().shortcut_keycode = shortcut_keycode_str;
- input_components_.back().shortcut_alt = shortcut_alt;
- input_components_.back().shortcut_ctrl = shortcut_ctrl;
- input_components_.back().shortcut_shift = shortcut_shift;
- }
- }
+ base::AutoLock auto_lock(runtime_data_lock_);
- if (manifest_->HasKey(keys::kOmnibox)) {
- if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
- omnibox_keyword_.empty()) {
- *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword);
- return false;
- }
- }
+ // Initialize permissions with an empty, default permission set.
+ runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
+ optional_permission_set_ = new ExtensionPermissionSet();
+ required_permission_set_ = new ExtensionPermissionSet();
- if (manifest_->HasKey(keys::kContentSecurityPolicy)) {
- std::string content_security_policy;
- if (!manifest_->GetString(keys::kContentSecurityPolicy,
- &content_security_policy)) {
- *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
- return false;
- }
- if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
- *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
- return false;
- }
- if (manifest_version_ >= 2 &&
- !ContentSecurityPolicyIsSecure(content_security_policy)) {
- *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
- return false;
- }
+ creation_flags_ = flags;
- content_security_policy_ = content_security_policy;
- } else if (manifest_version_ >= 2) {
- // Manifest version 2 introduced a default Content-Security-Policy.
- // TODO(abarth): Should we continue to let extensions override the
- // default Content-Security-Policy?
- content_security_policy_ = kDefaultContentSecurityPolicy;
- CHECK(ContentSecurityPolicyIsSecure(content_security_policy_));
- }
+ // Validate minimum Chrome version. We don't need to store this, since the
+ // extension is not valid if it is incorrect
+ if (!CheckMinimumChromeVersion(error))
+ return false;
- // Initialize devtools page url (optional).
- if (manifest_->HasKey(keys::kDevToolsPage)) {
- std::string devtools_str;
- if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) {
- *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
- return false;
- }
- devtools_url_ = GetResourceURL(devtools_str);
- }
+ if (!LoadRequiredFeatures(error))
+ return false;
- // Initialize text-to-speech voices (optional).
- if (manifest_->HasKey(keys::kTtsEngine)) {
- DictionaryValue* tts_dict = NULL;
- if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) {
- *error = ASCIIToUTF16(errors::kInvalidTts);
- return false;
- }
+ // We don't ned to validate because InitExtensionID already did that.
+ manifest_->GetString(keys::kPublicKey, &public_key_);
- if (tts_dict->HasKey(keys::kTtsVoices)) {
- ListValue* tts_voices = NULL;
- if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
- return false;
- }
+ // Initialize permissions with an empty, default permission set.
+ runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
+ optional_permission_set_ = new ExtensionPermissionSet();
+ required_permission_set_ = new ExtensionPermissionSet();
- for (size_t i = 0; i < tts_voices->GetSize(); i++) {
- DictionaryValue* one_tts_voice = NULL;
- if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
- return false;
- }
+ extension_url_ = Extension::GetBaseURLFromExtensionId(id());
- TtsVoice voice_data;
- if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
- if (!one_tts_voice->GetString(
- keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName);
- return false;
- }
- }
- if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) {
- if (!one_tts_voice->GetString(
- keys::kTtsVoicesLang, &voice_data.lang) ||
- !l10n_util::IsValidLocaleSyntax(voice_data.lang)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang);
- return false;
- }
- }
- if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
- if (!one_tts_voice->GetString(
- keys::kTtsVoicesGender, &voice_data.gender) ||
- (voice_data.gender != keys::kTtsGenderMale &&
- voice_data.gender != keys::kTtsGenderFemale)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender);
- return false;
- }
- }
- if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) {
- ListValue* event_types_list;
- if (!one_tts_voice->GetList(
- keys::kTtsVoicesEventTypes, &event_types_list)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
- return false;
- }
- for (size_t i = 0; i < event_types_list->GetSize(); i++) {
- std::string event_type;
- if (!event_types_list->GetString(i, &event_type)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
- return false;
- }
- if (event_type != keys::kTtsVoicesEventTypeEnd &&
- event_type != keys::kTtsVoicesEventTypeError &&
- event_type != keys::kTtsVoicesEventTypeMarker &&
- event_type != keys::kTtsVoicesEventTypeSentence &&
- event_type != keys::kTtsVoicesEventTypeStart &&
- event_type != keys::kTtsVoicesEventTypeWord) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
- return false;
- }
- if (voice_data.event_types.find(event_type) !=
- voice_data.event_types.end()) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
- return false;
- }
- voice_data.event_types.insert(event_type);
- }
- }
+ // 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() && !LoadAppFeatures(error))
+ return false;
- tts_voices_.push_back(voice_data);
- }
- }
+ ExtensionAPIPermissionSet api_permissions;
+ URLPatternSet host_permissions;
+ if (!ParsePermissions(keys::kPermissions,
+ error,
+ &api_permissions,
+ &host_permissions)) {
+ return false;
}
- // Initialize web intents (optional).
- if (!LoadWebIntentServices(error))
+ ExtensionAPIPermissionSet optional_api_permissions;
+ URLPatternSet optional_host_permissions;
+ if (!ParsePermissions(keys::kOptionalPermissions,
+ error,
+ &optional_api_permissions,
+ &optional_host_permissions)) {
return false;
-
- // Initialize incognito behavior. Apps default to split mode, extensions
- // default to spanning.
- incognito_split_mode_ = is_app();
- if (manifest_->HasKey(keys::kIncognito)) {
- std::string value;
- if (!manifest_->GetString(keys::kIncognito, &value)) {
- *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
- return false;
- }
- if (value == values::kIncognitoSpanning) {
- incognito_split_mode_ = false;
- } else if (value == values::kIncognitoSplit) {
- incognito_split_mode_ = true;
- } else {
- *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
- return false;
- }
}
- // Initialize offline-enabled status. Defaults to false.
- if (manifest_->HasKey(keys::kOfflineEnabled)) {
- if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
- *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
- return false;
- }
- }
+ // App isolation.
+ if (api_permissions.count(ExtensionAPIPermission::kExperimental) &&
+ is_app() && !LoadAppIsolation(error))
+ return false;
- // Initialize requirements (optional). Not actually persisted (they're only
- // used by the store), but still validated.
- if (manifest_->HasKey(keys::kRequirements)) {
- DictionaryValue* requirements_value = NULL;
- if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
- *error = ASCIIToUTF16(errors::kInvalidRequirements);
- return false;
- }
+ if (!LoadSharedFeatures(api_permissions, error))
+ return false;
- for (DictionaryValue::key_iterator it = requirements_value->begin_keys();
- it != requirements_value->end_keys(); ++it) {
- DictionaryValue* requirement_value;
- if (!requirements_value->GetDictionaryWithoutPathExpansion(
- *it, &requirement_value)) {
- *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
- }
- }
+
+ if (!LoadExtensionFeatures(api_permissions, error))
+ return false;
+
+ if (!LoadThemeFeatures(error))
+ return false;
if (HasMultipleUISurfaces()) {
*error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
@@ -2928,7 +3065,6 @@ GURL Extension::GetIconURL(int size,
}
bool Extension::ParsePermissions(const char* key,
- int flags,
string16* error,
ExtensionAPIPermissionSet* api_permissions,
URLPatternSet* host_permissions) {
@@ -2979,7 +3115,7 @@ bool Extension::ParsePermissions(const char* key,
if (pattern.MatchesScheme(chrome::kFileScheme) &&
!CanExecuteScriptEverywhere()) {
wants_file_access_ = true;
- if (!(flags & ALLOW_FILE_ACCESS))
+ if (!(creation_flags_ & ALLOW_FILE_ACCESS))
pattern.SetValidSchemes(
pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
}
@@ -3168,7 +3304,6 @@ bool Extension::CanSpecifyAPIPermission(
string16* error) const {
if (location() == Extension::COMPONENT)
return true;
-
bool access_denied = false;
if (permission->HasWhitelist()) {
if (permission->IsWhitelisted(id()))
@@ -3346,7 +3481,7 @@ Extension::SyncType Extension::GetSyncType() const {
bool Extension::IsSyncable() const {
// TODO(akalin): Figure out if we need to allow some other types.
- // We want to sync any extensions that are shown in the luancher because
+ // We want to sync any extensions that are shown in the launcher because
// their positions should sync.
return location() == Extension::INTERNAL ||
ShouldDisplayInLauncher();
« no previous file with comments | « chrome/common/extensions/extension.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698