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

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

Issue 11280296: Refactor extension.cc to match ordering of extension.h. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: // static added to some missing members. Created 8 years 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 | « no previous file | 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 41ace00dcbf2e49fa221bf63962c65c144f7188d..3559155a84fe1f24a760941a2b8115b4b325c570 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -281,6 +281,11 @@ bool ReadLaunchDimension(const extensions::Manifest* manifest,
return true;
}
+std::string SizeToString(const gfx::Size& max_size) {
+ return base::IntToString(max_size.width()) + "x" +
+ base::IntToString(max_size.height());
+}
+
} // namespace
const FilePath::CharType Extension::kManifestFilename[] =
@@ -342,6 +347,10 @@ Extension::FileHandlerInfo::~FileHandlerInfo() {}
// Extension
//
+bool Extension::InstallWarning::operator==(const InstallWarning& other) const {
+ return format == other.format && message == other.message;
+}
+
// static
scoped_refptr<Extension> Extension::Create(const FilePath& path,
Location location,
@@ -411,69 +420,6 @@ Extension::Location Extension::GetHigherPriorityLocation(
return (loc1_rank > loc2_rank ? loc1 : loc2 );
}
-void Extension::OverrideLaunchUrl(const GURL& override_url) {
- GURL new_url(override_url);
- if (!new_url.is_valid()) {
- DLOG(WARNING) << "Invalid override url given for " << name();
- } else {
- if (new_url.has_port()) {
- DLOG(WARNING) << "Override URL passed for " << name()
- << " should not contain a port. Removing it.";
-
- GURL::Replacements remove_port;
- remove_port.ClearPort();
- new_url = new_url.ReplaceComponents(remove_port);
- }
-
- launch_web_url_ = new_url.spec();
-
- URLPattern pattern(kValidWebExtentSchemes);
- URLPattern::ParseResult result = pattern.Parse(new_url.spec());
- DCHECK_EQ(result, URLPattern::PARSE_SUCCESS);
- pattern.SetPath(pattern.path() + '*');
- extent_.AddPattern(pattern);
- }
-}
-
-FilePath Extension::MaybeNormalizePath(const FilePath& path) {
-#if defined(OS_WIN)
- // Normalize any drive letter to upper-case. We do this for consistency with
- // net_utils::FilePathToFileURL(), which does the same thing, to make string
- // comparisons simpler.
- std::wstring path_str = path.value();
- if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
- path_str[1] == ':')
- path_str[0] += ('A' - 'a');
-
- return FilePath(path_str);
-#else
- return path;
-#endif
-}
-
-Extension::Location Extension::location() const {
- return manifest_->location();
-}
-
-const std::string& Extension::id() const {
- return manifest_->extension_id();
-}
-
-const std::string Extension::VersionString() const {
- return version()->GetString();
-}
-
-void Extension::AddInstallWarnings(
- const InstallWarningVector& new_warnings) {
- install_warnings_.insert(install_warnings_.end(),
- new_warnings.begin(), new_warnings.end());
-}
-
-// static
-bool Extension::IsExtension(const FilePath& file_name) {
- return file_name.MatchesExtension(chrome::kExtensionFileExtension);
-}
-
// static
bool Extension::IdIsValid(const std::string& id) {
// Verify that the id is legal.
@@ -500,6 +446,11 @@ std::string Extension::GenerateIdForPath(const FilePath& path) {
return GenerateId(path_bytes, &id) ? id : "";
}
+// static
+bool Extension::IsExtension(const FilePath& file_name) {
+ return file_name.MatchesExtension(chrome::kExtensionFileExtension);
+}
+
void Extension::GetBasicInfo(bool enabled,
DictionaryValue* info) const {
info->SetString(info_keys::kIdKey, id());
@@ -541,28 +492,6 @@ GURL Extension::GetResourceURL(const GURL& extension_url,
return ret_val;
}
-bool Extension::is_platform_app() const {
- return manifest_->is_platform_app();
-}
-
-bool Extension::is_hosted_app() const {
- return manifest()->is_hosted_app();
-}
-
-bool Extension::is_legacy_packaged_app() const {
- return manifest()->is_legacy_packaged_app();
-}
-
-bool Extension::is_theme() const {
- return manifest()->is_theme();
-}
-
-GURL Extension::GetBackgroundURL() const {
- if (background_scripts_.empty())
- return background_url_;
- return GetResourceURL(extension_filenames::kGeneratedBackgroundPageFilename);
-}
-
bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
const std::string& resource) const {
return pattern_set.MatchesURL(extension_url_.Resolve(resource));
@@ -578,10 +507,6 @@ bool Extension::IsResourceWebAccessible(const std::string& relative_path)
return ResourceMatches(web_accessible_resources_, relative_path);
}
-bool Extension::HasWebAccessibleResources() const {
- return web_accessible_resources_.size() > 0;
-}
-
bool Extension::IsSandboxedPage(const std::string& relative_path) const {
return ResourceMatches(sandboxed_pages_, relative_path);
}
@@ -592,2837 +517,3011 @@ std::string Extension::GetResourceContentSecurityPolicy(
sandboxed_pages_content_security_policy_ : content_security_policy();
}
-bool Extension::GenerateId(const std::string& input, std::string* output) {
- DCHECK(output);
- uint8 hash[Extension::kIdSize];
- crypto::SHA256HashString(input, hash, sizeof(hash));
- *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
- ConvertHexadecimalToIDAlphabet(output);
-
- return true;
+bool Extension::HasWebAccessibleResources() const {
+ return web_accessible_resources_.size() > 0;
}
-// Helper method that loads a UserScript object from a dictionary in the
-// content_script list of the manifest.
-bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
- int definition_index,
- string16* error,
- UserScript* result) {
- // run_at
- if (content_script->HasKey(keys::kRunAt)) {
- std::string run_location;
- if (!content_script->GetString(keys::kRunAt, &run_location)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRunAt,
- base::IntToString(definition_index));
- return false;
- }
-
- if (run_location == values::kRunAtDocumentStart) {
- result->set_run_location(UserScript::DOCUMENT_START);
- } else if (run_location == values::kRunAtDocumentEnd) {
- result->set_run_location(UserScript::DOCUMENT_END);
- } else if (run_location == values::kRunAtDocumentIdle) {
- result->set_run_location(UserScript::DOCUMENT_IDLE);
- } else {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRunAt,
- base::IntToString(definition_index));
- return false;
- }
+ExtensionResource Extension::GetResource(
+ const std::string& relative_path) const {
+ std::string new_path = relative_path;
+ // We have some legacy data where resources have leading slashes.
+ // See: http://crbug.com/121164
+ if (!new_path.empty() && new_path.at(0) == '/')
+ new_path.erase(0, 1);
+#if defined(OS_POSIX)
+ FilePath relative_file_path(new_path);
+#elif defined(OS_WIN)
+ FilePath relative_file_path(UTF8ToWide(new_path));
+#endif
+ ExtensionResource r(id(), path(), relative_file_path);
+ if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
+ r.set_follow_symlinks_anywhere();
}
+ return r;
+}
- // all frames
- if (content_script->HasKey(keys::kAllFrames)) {
- bool all_frames = false;
- if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidAllFrames, base::IntToString(definition_index));
- return false;
- }
- result->set_match_all_frames(all_frames);
+ExtensionResource Extension::GetResource(
+ const FilePath& relative_file_path) const {
+ ExtensionResource r(id(), path(), relative_file_path);
+ if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
+ r.set_follow_symlinks_anywhere();
}
+ return r;
+}
- // matches (required)
- const ListValue* matches = NULL;
- if (!content_script->GetList(keys::kMatches, &matches)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidMatches,
- base::IntToString(definition_index));
+// TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
+// util class in base:
+// http://code.google.com/p/chromium/issues/detail?id=13572
+// static
+bool Extension::ParsePEMKeyBytes(const std::string& input,
+ std::string* output) {
+ DCHECK(output);
+ if (!output)
return false;
- }
-
- if (matches->GetSize() == 0) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidMatchCount,
- base::IntToString(definition_index));
+ if (input.length() == 0)
return false;
- }
- for (size_t j = 0; j < matches->GetSize(); ++j) {
- std::string match_str;
- if (!matches->GetString(j, &match_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidMatch,
- base::IntToString(definition_index),
- base::IntToString(j),
- errors::kExpectString);
- return false;
- }
-
- URLPattern pattern(UserScript::kValidUserScriptSchemes);
- if (CanExecuteScriptEverywhere())
- pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
- URLPattern::ParseResult parse_result = pattern.Parse(match_str);
- if (parse_result != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidMatch,
- base::IntToString(definition_index),
- base::IntToString(j),
- URLPattern::GetParseResultString(parse_result));
+ 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;
- }
-
- if (pattern.MatchesScheme(chrome::kFileScheme) &&
- !CanExecuteScriptEverywhere()) {
- wants_file_access_ = true;
- if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
- pattern.SetValidSchemes(
- pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
- }
- }
- result->add_url_pattern(pattern);
+ working = working.substr(start_pos, end_pos - start_pos);
+ if (working.length() == 0)
+ return false;
}
- // exclude_matches
- if (content_script->HasKey(keys::kExcludeMatches)) { // optional
- const ListValue* exclude_matches = NULL;
- if (!content_script->GetList(keys::kExcludeMatches, &exclude_matches)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidExcludeMatches,
- base::IntToString(definition_index));
- return false;
- }
+ return base::Base64Decode(working, output);
+}
- for (size_t j = 0; j < exclude_matches->GetSize(); ++j) {
- std::string match_str;
- if (!exclude_matches->GetString(j, &match_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidExcludeMatch,
- base::IntToString(definition_index),
- base::IntToString(j),
- errors::kExpectString);
- return false;
- }
+// static
+bool Extension::ProducePEM(const std::string& input, std::string* output) {
+ DCHECK(output);
+ return (input.length() == 0) ? false : base::Base64Encode(input, output);
+}
- URLPattern pattern(UserScript::kValidUserScriptSchemes);
- if (CanExecuteScriptEverywhere())
- pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
- URLPattern::ParseResult parse_result = pattern.Parse(match_str);
- if (parse_result != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidExcludeMatch,
- base::IntToString(definition_index), base::IntToString(j),
- URLPattern::GetParseResultString(parse_result));
- return false;
- }
+// static
+bool Extension::GenerateId(const std::string& input, std::string* output) {
+ DCHECK(output);
+ uint8 hash[Extension::kIdSize];
+ crypto::SHA256HashString(input, hash, sizeof(hash));
+ *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
+ ConvertHexadecimalToIDAlphabet(output);
- result->add_exclude_url_pattern(pattern);
- }
- }
+ return true;
+}
- // include/exclude globs (mostly for Greasemonkey compatibility)
- if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
- error, &UserScript::add_glob, result)) {
- return false;
+// static
+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");
- if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
- error, &UserScript::add_exclude_glob, result)) {
- return false;
- }
+ return true;
+}
- // js and css keys
- const ListValue* js = NULL;
- if (content_script->HasKey(keys::kJs) &&
- !content_script->GetList(keys::kJs, &js)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidJsList,
- base::IntToString(definition_index));
- return false;
- }
+// static
+void Extension::DecodeIcon(const Extension* extension,
+ int preferred_icon_size,
+ ExtensionIconSet::MatchType match_type,
+ scoped_ptr<SkBitmap>* result) {
+ std::string path = extension->icons().Get(preferred_icon_size, match_type);
+ int size = extension->icons().GetIconSizeFromPath(path);
+ ExtensionResource icon_resource = extension->GetResource(path);
+ DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
+}
- const ListValue* css = NULL;
- if (content_script->HasKey(keys::kCss) &&
- !content_script->GetList(keys::kCss, &css)) {
- *error = ErrorUtils::
- FormatErrorMessageUTF16(errors::kInvalidCssList,
- base::IntToString(definition_index));
- return false;
- }
+// static
+void Extension::DecodeIcon(const Extension* extension,
+ int icon_size,
+ scoped_ptr<SkBitmap>* result) {
+ DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
+}
- // The manifest needs to have at least one js or css user script definition.
- if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kMissingFile,
- base::IntToString(definition_index));
- return false;
+// static
+void Extension::DecodeIconFromPath(const FilePath& icon_path,
+ int 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;
}
- if (js) {
- for (size_t script_index = 0; script_index < js->GetSize();
- ++script_index) {
- const Value* value;
- std::string relative;
- if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidJs,
- base::IntToString(definition_index),
- base::IntToString(script_index));
- return false;
- }
- GURL url = GetResourceURL(relative);
- ExtensionResource resource = GetResource(relative);
- result->js_scripts().push_back(UserScript::File(
- resource.extension_root(), resource.relative_path(), url));
- }
+ // 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 (css) {
- for (size_t script_index = 0; script_index < css->GetSize();
- ++script_index) {
- const Value* value;
- std::string relative;
- if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidCss,
- base::IntToString(definition_index),
- base::IntToString(script_index));
- return false;
- }
- GURL url = GetResourceURL(relative);
- ExtensionResource resource = GetResource(relative);
- result->css_scripts().push_back(UserScript::File(
- resource.extension_root(), resource.relative_path(), url));
- }
+ 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;
}
- return true;
+ result->swap(decoded);
}
-bool Extension::LoadGlobsHelper(
- const DictionaryValue* content_script,
- int content_script_index,
- const char* globs_property_name,
- string16* error,
- void(UserScript::*add_method)(const std::string& glob),
- UserScript* instance) {
- if (!content_script->HasKey(globs_property_name))
- return true; // they are optional
+// static
+const gfx::ImageSkia& Extension::GetDefaultIcon(bool is_app) {
+ int id = is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON;
+ return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
+}
- const ListValue* list = NULL;
- if (!content_script->GetList(globs_property_name, &list)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidGlobList,
- base::IntToString(content_script_index),
- globs_property_name);
- return false;
+// static
+GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
+ return GURL(std::string(extensions::kExtensionScheme) +
+ content::kStandardSchemeSeparator + extension_id + "/");
+}
+
+// static
+void Extension::SetScriptingWhitelist(
+ const Extension::ScriptingWhitelist& whitelist) {
+ ScriptingWhitelist* current_whitelist =
+ ExtensionConfig::GetInstance()->whitelist();
+ current_whitelist->clear();
+ for (ScriptingWhitelist::const_iterator it = whitelist.begin();
+ it != whitelist.end(); ++it) {
+ current_whitelist->push_back(*it);
}
+}
- for (size_t i = 0; i < list->GetSize(); ++i) {
- std::string glob;
- if (!list->GetString(i, &glob)) {
+// static
+const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
+ return ExtensionConfig::GetInstance()->whitelist();
+}
+
+bool Extension::ParsePermissions(const char* key,
+ string16* error,
+ APIPermissionSet* api_permissions,
+ URLPatternSet* host_permissions) {
+ if (manifest_->HasKey(key)) {
+ ListValue* permissions = NULL;
+ if (!manifest_->GetList(key, &permissions)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidGlob,
- base::IntToString(content_script_index),
- globs_property_name,
- base::IntToString(i));
+ errors::kInvalidPermissions, "");
return false;
}
- (instance->*add_method)(glob);
- }
+ // NOTE: We need to get the APIPermission before we check if features
+ // associated with them are available because the feature system does not
+ // know about aliases.
- return true;
-}
+ std::vector<std::string> host_data;
+ if (!APIPermissionSet::ParseFromJSON(permissions, api_permissions,
+ error, &host_data))
+ return false;
-scoped_ptr<Extension::ActionInfo> Extension::LoadExtensionActionInfoHelper(
- const DictionaryValue* extension_action,
- ActionInfo::Type action_type,
- string16* error) {
- scoped_ptr<ActionInfo> result(new ActionInfo());
+ // Verify feature availability of permissions.
+ std::vector<APIPermission::ID> to_remove;
+ SimpleFeatureProvider* permission_features =
+ SimpleFeatureProvider::GetPermissionFeatures();
+ for (APIPermissionSet::const_iterator it = api_permissions->begin();
+ it != api_permissions->end(); ++it) {
+ extensions::Feature* feature =
+ permission_features->GetFeature(it->name());
- if (manifest_version_ == 1) {
- // kPageActionIcons is obsolete, and used by very few extensions. Continue
- // loading it, but only take the first icon as the default_icon path.
- const ListValue* icons = NULL;
- if (extension_action->HasKey(keys::kPageActionIcons) &&
- extension_action->GetList(keys::kPageActionIcons, &icons)) {
- for (ListValue::const_iterator iter = icons->begin();
- iter != icons->end(); ++iter) {
- std::string path;
- if (!(*iter)->GetAsString(&path) || !NormalizeAndValidatePath(&path)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
- return scoped_ptr<ActionInfo>();
- }
+ // The feature should exist since we just got an APIPermission
+ // for it. The two systems should be updated together whenever a
+ // permission is added.
+ CHECK(feature);
- result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
- break;
+ Feature::Availability availability =
+ feature->IsAvailableToManifest(
+ id(),
+ GetType(),
+ Feature::ConvertLocation(location()),
+ manifest_version());
+ if (!availability.is_available()) {
+ // Don't fail, but warn the developer that the manifest contains
+ // unrecognized permissions. This may happen legitimately if the
+ // extensions requests platform- or channel-specific permissions.
+ install_warnings_.push_back(InstallWarning(InstallWarning::FORMAT_TEXT,
+ availability.message()));
+ to_remove.push_back(it->id());
+ continue;
}
- }
- std::string id;
- if (extension_action->HasKey(keys::kPageActionId)) {
- if (!extension_action->GetString(keys::kPageActionId, &id)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionId);
- return scoped_ptr<ActionInfo>();
+ if (it->id() == APIPermission::kExperimental) {
+ if (!CanSpecifyExperimentalPermission()) {
+ *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
+ return false;
+ }
}
- result->id = id;
}
- }
- // Read the page action |default_icon| (optional).
- // The |default_icon| value can be either dictionary {icon size -> icon path}
- // or non empty string value.
- if (extension_action->HasKey(keys::kPageActionDefaultIcon)) {
- const DictionaryValue* icons_value = NULL;
- std::string default_icon;
- if (extension_action->GetDictionary(keys::kPageActionDefaultIcon,
- &icons_value)) {
- if (!LoadIconsFromDictionary(icons_value,
- extension_misc::kExtensionActionIconSizes,
- extension_misc::kNumExtensionActionIconSizes,
- &result->default_icon,
- error)) {
- return scoped_ptr<ActionInfo>();
- }
- } else if (extension_action->GetString(keys::kPageActionDefaultIcon,
- &default_icon) &&
- NormalizeAndValidatePath(&default_icon)) {
- result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
- default_icon);
- } else {
- *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
- return scoped_ptr<ActionInfo>();
+ // Remove permissions that are not available to this extension.
+ for (std::vector<APIPermission::ID>::const_iterator it = to_remove.begin();
+ it != to_remove.end(); ++it) {
+ api_permissions->erase(*it);
}
- }
- // Read the page action title from |default_title| if present, |name| if not
- // (both optional).
- if (extension_action->HasKey(keys::kPageActionDefaultTitle)) {
- if (!extension_action->GetString(keys::kPageActionDefaultTitle,
- &result->default_title)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
- return scoped_ptr<ActionInfo>();
- }
- } else if (manifest_version_ == 1 && extension_action->HasKey(keys::kName)) {
- if (!extension_action->GetString(keys::kName, &result->default_title)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionName);
- return scoped_ptr<ActionInfo>();
- }
- }
+ // Parse host pattern permissions.
+ const int kAllowedSchemes = CanExecuteScriptEverywhere() ?
+ URLPattern::SCHEME_ALL : kValidHostPermissionSchemes;
- // Read the action's |popup| (optional).
- const char* popup_key = NULL;
- if (extension_action->HasKey(keys::kPageActionDefaultPopup))
- popup_key = keys::kPageActionDefaultPopup;
+ for (std::vector<std::string>::const_iterator it = host_data.begin();
+ it != host_data.end(); ++it) {
+ const std::string& permission_str = *it;
- if (manifest_version_ == 1 &&
- extension_action->HasKey(keys::kPageActionPopup)) {
- if (popup_key) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPageActionOldAndNewKeys,
- keys::kPageActionDefaultPopup,
- keys::kPageActionPopup);
- return scoped_ptr<ActionInfo>();
- }
- popup_key = keys::kPageActionPopup;
- }
+ // Check if it's a host pattern permission.
+ URLPattern pattern = URLPattern(kAllowedSchemes);
+ URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
+ if (parse_result == URLPattern::PARSE_SUCCESS) {
+ if (!CanSpecifyHostPermission(pattern, *api_permissions)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPermissionScheme, permission_str);
+ return false;
+ }
- if (popup_key) {
- const DictionaryValue* popup = NULL;
- std::string url_str;
+ // The path component is not used for host permissions, so we force it
+ // to match all paths.
+ pattern.SetPath("/*");
- if (extension_action->GetString(popup_key, &url_str)) {
- // On success, |url_str| is set. Nothing else to do.
- } else if (manifest_version_ == 1 &&
- extension_action->GetDictionary(popup_key, &popup)) {
- if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPageActionPopupPath, "<missing>");
- return scoped_ptr<ActionInfo>();
- }
- } else {
- *error = ASCIIToUTF16(errors::kInvalidPageActionPopup);
- return scoped_ptr<ActionInfo>();
- }
+ if (pattern.MatchesScheme(chrome::kFileScheme) &&
+ !CanExecuteScriptEverywhere()) {
+ wants_file_access_ = true;
+ if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
+ pattern.SetValidSchemes(
+ pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+ }
+ }
- if (!url_str.empty()) {
- // An empty string is treated as having no popup.
- result->default_popup_url = GetResourceURL(url_str);
- if (!result->default_popup_url.is_valid()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPageActionPopupPath, url_str);
- return scoped_ptr<ActionInfo>();
+ host_permissions->AddPattern(pattern);
+ continue;
}
- } else {
- DCHECK(result->default_popup_url.is_empty())
- << "Shouldn't be possible for the popup to be set.";
+
+ // It's probably an unknown API permission. Do not throw an error so
+ // extensions can retain backwards compatability (http://crbug.com/42742).
+ install_warnings_.push_back(InstallWarning(
+ InstallWarning::FORMAT_TEXT,
+ base::StringPrintf(
+ "Permission '%s' is unknown or URL pattern is malformed.",
+ permission_str.c_str())));
}
}
+ return true;
+}
- return result.Pass();
+bool Extension::HasAPIPermission(APIPermission::ID permission) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->HasAPIPermission(permission);
}
-// 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;
- }
+bool Extension::HasAPIPermission(const std::string& function_name) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->
+ HasAccessToFunction(function_name);
+}
- 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;
- }
- manifest->set_extension_id(extension_id);
+bool Extension::HasAPIPermissionForTab(int tab_id,
+ APIPermission::ID permission) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ if (runtime_data_.GetActivePermissions()->HasAPIPermission(permission))
return true;
- }
+ scoped_refptr<const PermissionSet> tab_specific_permissions =
+ runtime_data_.GetTabSpecificPermissions(tab_id);
+ return tab_specific_permissions.get() &&
+ tab_specific_permissions->HasAPIPermission(permission);
+}
- 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;
- }
+bool Extension::CheckAPIPermissionWithParam(APIPermission::ID permission,
+ const APIPermission::CheckParam* param) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->
+ CheckAPIPermissionWithParam(permission, param);
}
-bool Extension::LoadRequiredFeatures(string16* error) {
- if (!LoadName(error) ||
- !LoadVersion(error))
- return false;
- return true;
+const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->effective_hosts();
}
-bool Extension::LoadName(string16* error) {
- string16 localized_name;
- if (!manifest_->GetString(keys::kName, &localized_name)) {
- *error = ASCIIToUTF16(errors::kInvalidName);
- return false;
- }
- non_localized_name_ = UTF16ToUTF8(localized_name);
- base::i18n::AdjustStringForLocaleDirection(&localized_name);
- name_ = UTF16ToUTF8(localized_name);
- return true;
+bool Extension::CanSilentlyIncreasePermissions() const {
+ return location() != INTERNAL;
}
-bool Extension::LoadDescription(string16* error) {
- if (manifest_->HasKey(keys::kDescription) &&
- !manifest_->GetString(keys::kDescription, &description_)) {
- *error = ASCIIToUTF16(errors::kInvalidDescription);
+bool Extension::HasHostPermission(const GURL& url) const {
+ if (url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() != chrome::kChromeUIFaviconHost &&
+ url.host() != chrome::kChromeUIThumbnailHost &&
+ location() != Extension::COMPONENT) {
return false;
}
- return true;
-}
-bool Extension::LoadAppFeatures(string16* error) {
- if (!LoadExtent(keys::kWebURLs, &extent_,
- errors::kInvalidWebURLs, errors::kInvalidWebURL, error) ||
- !LoadLaunchURL(error) ||
- !LoadLaunchContainer(error)) {
- return false;
- }
- if (manifest_->HasKey(keys::kDisplayInLauncher) &&
- !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
- *error = ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
- return false;
- }
- if (manifest_->HasKey(keys::kDisplayInNewTabPage)) {
- if (!manifest_->GetBoolean(keys::kDisplayInNewTabPage,
- &display_in_new_tab_page_)) {
- *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
- return false;
- }
- } else {
- // Inherit default from display_in_launcher property.
- display_in_new_tab_page_ = display_in_launcher_;
- }
- return true;
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->
+ HasExplicitAccessToOrigin(url);
}
-bool Extension::LoadOAuth2Info(string16* error) {
- if (!manifest_->HasKey(keys::kOAuth2))
- return true;
+bool Extension::HasEffectiveAccessToAllHosts() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->HasEffectiveAccessToAllHosts();
+}
- if (!manifest_->GetString(keys::kOAuth2ClientId, &oauth2_info_.client_id) ||
- oauth2_info_.client_id.empty()) {
- *error = ASCIIToUTF16(errors::kInvalidOAuth2ClientId);
- return false;
- }
+bool Extension::HasFullPermissions() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions()->HasEffectiveFullAccess();
+}
- ListValue* list = NULL;
- if (!manifest_->GetList(keys::kOAuth2Scopes, &list)) {
- *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
- return false;
+PermissionMessages Extension::GetPermissionMessages() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ if (IsTrustedId(id())) {
+ return PermissionMessages();
+ } else {
+ return runtime_data_.GetActivePermissions()->GetPermissionMessages(
+ GetType());
}
+}
- for (size_t i = 0; i < list->GetSize(); ++i) {
- std::string scope;
- if (!list->GetString(i, &scope)) {
- *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
- return false;
- }
- oauth2_info_.scopes.push_back(scope);
- }
+std::vector<string16> Extension::GetPermissionMessageStrings() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ if (IsTrustedId(id()))
+ return std::vector<string16>();
+ else
+ return runtime_data_.GetActivePermissions()->GetWarningMessages(GetType());
+}
- return true;
+bool Extension::ShouldSkipPermissionWarnings() const {
+ return IsTrustedId(id());
}
-bool Extension::LoadExtent(const char* key,
- URLPatternSet* extent,
- const char* list_error,
- const char* value_error,
- string16* error) {
- Value* temp_pattern_value = NULL;
- if (!manifest_->Get(key, &temp_pattern_value))
- return true;
+void Extension::SetActivePermissions(
+ const PermissionSet* permissions) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ runtime_data_.SetActivePermissions(permissions);
+}
- if (temp_pattern_value->GetType() != Value::TYPE_LIST) {
- *error = ASCIIToUTF16(list_error);
- return false;
- }
+scoped_refptr<const PermissionSet>
+ Extension::GetActivePermissions() const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetActivePermissions();
+}
- ListValue* pattern_list = static_cast<ListValue*>(temp_pattern_value);
- for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
- std::string pattern_string;
- if (!pattern_list->GetString(i, &pattern_string)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(value_error,
- base::UintToString(i),
- errors::kExpectString);
- return false;
- }
+bool Extension::ShowConfigureContextMenus() const {
+ // Don't show context menu for component extensions. We might want to show
+ // options for component extension button but now there is no component
+ // extension with options. All other menu items like uninstall have
+ // no sense for component extensions.
+ return location() != Extension::COMPONENT;
+}
- URLPattern pattern(kValidWebExtentSchemes);
- URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
- if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
- pattern_string += "/";
- parse_result = pattern.Parse(pattern_string);
- }
+GURL Extension::GetHomepageURL() const {
+ if (homepage_url_.is_valid())
+ return homepage_url_;
- if (parse_result != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error,
- base::UintToString(i),
- URLPattern::GetParseResultString(parse_result));
- return false;
- }
+ return UpdatesFromGallery() ?
+ GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id()) : GURL();
+}
- // Do not allow authors to claim "<all_urls>".
- if (pattern.match_all_urls()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error,
- base::UintToString(i),
- errors::kCannotClaimAllURLsInExtent);
- return false;
- }
+std::set<FilePath> Extension::GetBrowserImages() const {
+ std::set<FilePath> image_paths;
+ // TODO(viettrungluu): These |FilePath::FromWStringHack(UTF8ToWide())|
+ // indicate that we're doing something wrong.
- // Do not allow authors to claim "*" for host.
- if (pattern.host().empty()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error,
- base::UintToString(i),
- errors::kCannotClaimAllHostsInExtent);
- return false;
+ // Extension icons.
+ for (ExtensionIconSet::IconMap::const_iterator iter = icons().map().begin();
+ iter != icons().map().end(); ++iter) {
+ image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
+ }
+
+ // Theme images.
+ DictionaryValue* theme_images = GetThemeImages();
+ if (theme_images) {
+ for (DictionaryValue::key_iterator it = theme_images->begin_keys();
+ it != theme_images->end_keys(); ++it) {
+ std::string val;
+ if (theme_images->GetStringWithoutPathExpansion(*it, &val))
+ image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(val)));
}
+ }
- // We do not allow authors to put wildcards in their paths. Instead, we
- // imply one at the end.
- if (pattern.path().find('*') != std::string::npos) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error,
- base::UintToString(i),
- errors::kNoWildCardsInPaths);
- return false;
+ if (page_action_info() && !page_action_info()->default_icon.empty()) {
+ for (ExtensionIconSet::IconMap::const_iterator iter =
+ page_action_info()->default_icon.map().begin();
+ iter != page_action_info()->default_icon.map().end();
+ ++iter) {
+ image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
}
- pattern.SetPath(pattern.path() + '*');
+ }
- extent->AddPattern(pattern);
+ if (browser_action_info() && !browser_action_info()->default_icon.empty()) {
+ for (ExtensionIconSet::IconMap::const_iterator iter =
+ browser_action_info()->default_icon.map().begin();
+ iter != browser_action_info()->default_icon.map().end();
+ ++iter) {
+ image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
+ }
}
- return true;
+ return image_paths;
}
-bool Extension::LoadLaunchURL(string16* error) {
- Value* temp = NULL;
+ExtensionResource Extension::GetIconResource(
+ int size, ExtensionIconSet::MatchType match_type) const {
+ std::string path = icons().Get(size, match_type);
+ return path.empty() ? ExtensionResource() : GetResource(path);
+}
- // launch URL can be either local (to chrome-extension:// root) or an absolute
- // web URL.
- if (manifest_->Get(keys::kLaunchLocalPath, &temp)) {
- if (manifest_->Get(keys::kLaunchWebURL, NULL)) {
- *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
- return false;
- }
+GURL Extension::GetIconURL(int size,
+ ExtensionIconSet::MatchType match_type) const {
+ std::string path = icons().Get(size, match_type);
+ return path.empty() ? GURL() : GetResourceURL(path);
+}
- if (manifest_->Get(keys::kWebURLs, NULL)) {
- *error = ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive);
- return false;
- }
+GURL Extension::GetFullLaunchURL() const {
+ return launch_local_path().empty() ? GURL(launch_web_url()) :
+ url().Resolve(launch_local_path());
+}
- std::string launch_path;
- if (!temp->GetAsString(&launch_path)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- keys::kLaunchLocalPath);
- return false;
- }
+void Extension::SetCachedImage(const ExtensionResource& source,
+ const SkBitmap& image,
+ const gfx::Size& original_size) const {
+ DCHECK(source.extension_root() == path()); // The resource must come from
+ // this extension.
+ const FilePath& path = source.relative_path();
+ gfx::Size actual_size(image.width(), image.height());
+ std::string location;
+ if (actual_size != original_size)
+ location = SizeToString(actual_size);
+ image_cache_[ImageCacheKey(path, location)] = image;
+}
- // Ensure the launch path is a valid relative URL.
- GURL resolved = url().Resolve(launch_path);
- if (!resolved.is_valid() || resolved.GetOrigin() != url()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- keys::kLaunchLocalPath);
- return false;
- }
+bool Extension::HasCachedImage(const ExtensionResource& source,
+ const gfx::Size& max_size) const {
+ DCHECK(source.extension_root() == path()); // The resource must come from
+ // this extension.
+ return GetCachedImageImpl(source, max_size) != NULL;
+}
- launch_local_path_ = launch_path;
- } else if (manifest_->Get(keys::kLaunchWebURL, &temp)) {
- std::string launch_url;
- if (!temp->GetAsString(&launch_url)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- keys::kLaunchWebURL);
- return false;
- }
-
- // Ensure the launch URL is a valid absolute URL and web extent scheme.
- GURL url(launch_url);
- URLPattern pattern(kValidWebExtentSchemes);
- if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- keys::kLaunchWebURL);
- return false;
- }
+SkBitmap Extension::GetCachedImage(const ExtensionResource& source,
+ const gfx::Size& max_size) const {
+ DCHECK(source.extension_root() == path()); // The resource must come from
+ // this extension.
+ SkBitmap* image = GetCachedImageImpl(source, max_size);
+ return image ? *image : SkBitmap();
+}
- launch_web_url_ = launch_url;
- } else if (is_legacy_packaged_app() || is_hosted_app()) {
- *error = ASCIIToUTF16(errors::kLaunchURLRequired);
+bool Extension::CanExecuteScriptOnPage(const GURL& document_url,
+ const GURL& top_frame_url,
+ int tab_id,
+ const UserScript* script,
+ std::string* error) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ // The gallery is special-cased as a restricted URL for scripting to prevent
+ // access to special JS bindings we expose to the gallery (and avoid things
+ // like extensions removing the "report abuse" link).
+ // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
+ // against the store app extent?
+ GURL store_url(extension_urls::GetWebstoreLaunchURL());
+ if ((document_url.host() == store_url.host()) &&
+ !CanExecuteScriptEverywhere() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowScriptingGallery)) {
+ if (error)
+ *error = errors::kCannotScriptGallery;
return false;
}
- // If there is no extent, we default the extent based on the launch URL.
- if (web_extent().is_empty() && !launch_web_url().empty()) {
- GURL launch_url(launch_web_url());
- URLPattern pattern(kValidWebExtentSchemes);
- if (!pattern.SetScheme("*")) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidLaunchValue,
- keys::kLaunchWebURL);
- return false;
- }
- pattern.SetHost(launch_url.host());
- pattern.SetPath("/*");
- extent_.AddPattern(pattern);
- }
-
- // In order for the --apps-gallery-url switch to work with the gallery
- // process isolation, we must insert any provided value into the component
- // app's launch url and web extent.
- if (id() == extension_misc::kWebStoreAppId) {
- std::string gallery_url_str = CommandLine::ForCurrentProcess()->
- GetSwitchValueASCII(switches::kAppsGalleryURL);
-
- // Empty string means option was not used.
- if (!gallery_url_str.empty()) {
- GURL gallery_url(gallery_url_str);
- OverrideLaunchUrl(gallery_url);
- }
- } else if (id() == extension_misc::kCloudPrintAppId) {
- // In order for the --cloud-print-service switch to work, we must update
- // the launch URL and web extent.
- // TODO(sanjeevr): Ideally we want to use CloudPrintURL here but that is
- // currently under chrome/browser.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
- switches::kCloudPrintServiceURL));
- if (!cloud_print_service_url.is_empty()) {
- std::string path(
- cloud_print_service_url.path() + "/enable_chrome_connector");
- GURL::Replacements replacements;
- replacements.SetPathStr(path);
- GURL cloud_print_enable_connector_url =
- cloud_print_service_url.ReplaceComponents(replacements);
- OverrideLaunchUrl(cloud_print_enable_connector_url);
- }
- } else if (id() == extension_misc::kChromeAppId) {
- // Override launch url to new tab.
- launch_web_url_ = chrome::kChromeUINewTabURL;
- extent_.ClearPatterns();
+ if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
+ !CanExecuteScriptEverywhere()) {
+ return false;
}
- return true;
-}
-
-bool Extension::LoadLaunchContainer(string16* error) {
- Value* tmp_launcher_container = NULL;
- if (!manifest_->Get(keys::kLaunchContainer, &tmp_launcher_container))
- return true;
-
- std::string launch_container_string;
- if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
- *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
+ if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
+ top_frame_url.GetOrigin() !=
+ GetBaseURLFromExtensionId(id()).GetOrigin() &&
+ !CanExecuteScriptEverywhere()) {
return false;
}
- if (launch_container_string == values::kLaunchContainerPanel) {
- launch_container_ = extension_misc::LAUNCH_PANEL;
- } else if (launch_container_string == values::kLaunchContainerTab) {
- launch_container_ = extension_misc::LAUNCH_TAB;
- } else {
- *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
- return false;
+ // If a tab ID is specified, try the tab-specific permissions.
+ if (tab_id >= 0) {
+ scoped_refptr<const PermissionSet> tab_permissions =
+ runtime_data_.GetTabSpecificPermissions(tab_id);
+ if (tab_permissions.get() &&
+ tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
+ return true;
+ }
}
- bool can_specify_initial_size =
- launch_container_ == extension_misc::LAUNCH_PANEL ||
- launch_container_ == extension_misc::LAUNCH_WINDOW;
+ // If a script is specified, use its matches.
+ if (script)
+ return script->MatchesURL(document_url);
- // Validate the container width if present.
- if (!ReadLaunchDimension(manifest_.get(),
- keys::kLaunchWidth,
- &launch_width_,
- can_specify_initial_size,
- error)) {
- return false;
+ // Otherwise, see if this extension has permission to execute script
+ // programmatically on pages.
+ if (runtime_data_.GetActivePermissions()->HasExplicitAccessToOrigin(
+ document_url)) {
+ return true;
}
- // Validate container height if present.
- if (!ReadLaunchDimension(manifest_.get(),
- keys::kLaunchHeight,
- &launch_height_,
- can_specify_initial_size,
- error)) {
- return false;
+ if (error) {
+ *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
+ document_url.spec());
}
- return true;
+ return false;
}
-bool Extension::LoadSharedFeatures(
- const APIPermissionSet& api_permissions,
- string16* error) {
- if (!LoadDescription(error) ||
- !LoadHomepageURL(error) ||
- !LoadUpdateURL(error) ||
- !LoadIcons(error) ||
- !LoadCommands(error) ||
- !LoadPlugins(error) ||
- !LoadNaClModules(error) ||
- !LoadWebAccessibleResources(error) ||
- !LoadSandboxedPages(error) ||
- !LoadRequirements(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) ||
- !LoadOAuth2Info(error))
- return false;
+bool Extension::CanExecuteScriptEverywhere() const {
+ if (location() == Extension::COMPONENT)
+ return true;
- return true;
-}
+ ScriptingWhitelist* whitelist = ExtensionConfig::GetInstance()->whitelist();
-bool Extension::LoadVersion(string16* error) {
- std::string version_str;
- if (!manifest_->GetString(keys::kVersion, &version_str)) {
- *error = ASCIIToUTF16(errors::kInvalidVersion);
- return false;
- }
- version_.reset(new Version(version_str));
- if (!version_->IsValid() || version_->components().size() > 4) {
- *error = ASCIIToUTF16(errors::kInvalidVersion);
- return false;
+ for (ScriptingWhitelist::const_iterator it = whitelist->begin();
+ it != whitelist->end(); ++it) {
+ if (id() == *it) {
+ return true;
+ }
}
- return true;
+
+ return false;
}
-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;
+bool Extension::CanCaptureVisiblePage(const GURL& page_url,
+ int tab_id,
+ std::string* error) const {
+ if (tab_id >= 0) {
+ scoped_refptr<const PermissionSet> tab_permissions =
+ GetTabSpecificPermissions(tab_id);
+ if (tab_permissions.get() &&
+ tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
+ return true;
}
}
- manifest_version_ = manifest_->GetManifestVersion();
- if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
- manifest_version_ < kModernManifestVersion &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowLegacyExtensionManifests)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidManifestVersionOld,
- base::IntToString(kModernManifestVersion));
- return false;
+ if (HasHostPermission(page_url) || page_url.GetOrigin() == url())
+ return true;
+
+ if (error) {
+ *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
+ page_url.spec());
}
+ return false;
+}
- return true;
+bool Extension::UpdatesFromGallery() const {
+ return extension_urls::IsWebstoreUpdateUrl(update_url());
}
-bool Extension::LoadHomepageURL(string16* error) {
- if (!manifest_->HasKey(keys::kHomepageURL))
+bool Extension::OverlapsWithOrigin(const GURL& origin) const {
+ if (url() == origin)
return true;
- std::string tmp_homepage_url;
- if (!manifest_->GetString(keys::kHomepageURL, &tmp_homepage_url)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidHomepageURL, "");
- return false;
- }
- homepage_url_ = GURL(tmp_homepage_url);
- if (!homepage_url_.is_valid() ||
- (!homepage_url_.SchemeIs("http") &&
- !homepage_url_.SchemeIs("https"))) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidHomepageURL, tmp_homepage_url);
+
+ if (web_extent().is_empty())
return false;
- }
- return true;
-}
-bool Extension::LoadUpdateURL(string16* error) {
- if (!manifest_->HasKey(keys::kUpdateURL))
- return true;
- std::string tmp_update_url;
- if (!manifest_->GetString(keys::kUpdateURL, &tmp_update_url)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidUpdateURL, "");
- return false;
- }
- update_url_ = GURL(tmp_update_url);
- if (!update_url_.is_valid() ||
- update_url_.has_ref()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidUpdateURL, tmp_update_url);
+ // Note: patterns and extents ignore port numbers.
+ URLPattern origin_only_pattern(kValidWebExtentSchemes);
+ if (!origin_only_pattern.SetScheme(origin.scheme()))
return false;
- }
- return true;
-}
+ origin_only_pattern.SetHost(origin.host());
+ origin_only_pattern.SetPath("/*");
-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;
- }
+ URLPatternSet origin_only_pattern_list;
+ origin_only_pattern_list.AddPattern(origin_only_pattern);
- return LoadIconsFromDictionary(icons_value,
- extension_misc::kExtensionIconSizes,
- extension_misc::kNumExtensionIconSizes,
- &icons_,
- error);
+ return web_extent().OverlapsWith(origin_only_pattern_list);
}
-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;
- }
+Extension::SyncType Extension::GetSyncType() const {
+ if (!IsSyncable()) {
+ // We have a non-standard location.
+ return SYNC_TYPE_NONE;
+ }
- if (commands->size() > kMaxCommandsPerExtension) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidKeyBindingTooMany,
- base::IntToString(kMaxCommandsPerExtension));
- return false;
- }
+ // Disallow extensions with non-gallery auto-update URLs for now.
+ //
+ // TODO(akalin): Relax this restriction once we've put in UI to
+ // approve synced extensions.
+ if (!update_url().is_empty() && !UpdatesFromGallery())
+ return SYNC_TYPE_NONE;
- int command_index = 0;
- for (DictionaryValue::key_iterator iter = commands->begin_keys();
- iter != commands->end_keys(); ++iter) {
- ++command_index;
+ // Disallow extensions with native code plugins.
+ //
+ // TODO(akalin): Relax this restriction once we've put in UI to
+ // approve synced extensions.
+ if (!plugins().empty()) {
+ return SYNC_TYPE_NONE;
+ }
- DictionaryValue* command = NULL;
- if (!commands->GetDictionary(*iter, &command)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidKeyBindingDictionary,
- base::IntToString(command_index));
- return false;
- }
+ switch (GetType()) {
+ case Extension::TYPE_EXTENSION:
+ return SYNC_TYPE_EXTENSION;
- scoped_ptr<extensions::Command> binding(new extensions::Command());
- if (!binding->Parse(command, *iter, command_index, error))
- return false; // |error| already set.
+ case Extension::TYPE_USER_SCRIPT:
+ // We only want to sync user scripts with gallery update URLs.
+ if (UpdatesFromGallery())
+ return SYNC_TYPE_EXTENSION;
+ else
+ return SYNC_TYPE_NONE;
- std::string command_name = binding->command_name();
- if (command_name == values::kPageActionCommandEvent) {
- page_action_command_.reset(binding.release());
- } else if (command_name == values::kBrowserActionCommandEvent) {
- browser_action_command_.reset(binding.release());
- } else if (command_name == values::kScriptBadgeCommandEvent) {
- script_badge_command_.reset(binding.release());
- } else {
- if (command_name[0] != '_') // All commands w/underscore are reserved.
- named_commands_[command_name] = *binding.get();
- }
- }
- }
+ case Extension::TYPE_HOSTED_APP:
+ case Extension::TYPE_LEGACY_PACKAGED_APP:
+ case Extension::TYPE_PLATFORM_APP:
+ return SYNC_TYPE_APP;
- if (manifest_->HasKey(keys::kBrowserAction) &&
- !browser_action_command_.get()) {
- // If the extension defines a browser action, but no command for it, then
- // we synthesize a generic one, so the user can configure a shortcut for it.
- // No keyboard shortcut will be assigned to it, until the user selects one.
- browser_action_command_.reset(
- new extensions::Command(
- values::kBrowserActionCommandEvent, string16(), ""));
+ default:
+ return SYNC_TYPE_NONE;
}
-
- return true;
}
-bool Extension::LoadPlugins(string16* error) {
- if (!manifest_->HasKey(keys::kPlugins))
- return true;
+bool Extension::IsSyncable() const {
+ // TODO(akalin): Figure out if we need to allow some other types.
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kPlugins, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPlugins);
- return false;
- }
+ // Default apps are not synced because otherwise they will pollute profiles
+ // that don't already have them. Specially, if a user doesn't have default
+ // apps, creates a new profile (which get default apps) and then enables sync
+ // for it, then their profile everywhere gets the default apps.
+ bool is_syncable = (location() == Extension::INTERNAL &&
+ !was_installed_by_default());
+ // Sync the chrome web store to maintain its position on the new tab page.
+ is_syncable |= (id() == extension_misc::kWebStoreAppId);
+ return is_syncable;
+}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* plugin_value = NULL;
- if (!list_value->GetDictionary(i, &plugin_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPlugins);
- return false;
- }
- // Get plugins[i].path.
- std::string path_str;
- if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPluginsPath, base::IntToString(i));
- return false;
- }
+bool Extension::RequiresSortOrdinal() const {
+ return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
+}
- // Get plugins[i].content (optional).
- bool is_public = false;
- if (plugin_value->HasKey(keys::kPluginsPublic)) {
- if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPluginsPublic, base::IntToString(i));
- return false;
- }
- }
+bool Extension::ShouldDisplayInAppLauncher() const {
+ // Only apps should be displayed in the launcher.
+ return is_app() && display_in_launcher_;
+}
- // We don't allow extensions to load NPAPI plugins on Chrome OS, or under
- // Windows 8 Metro mode, but still parse the entries to display consistent
- // error messages. If the extension actually requires the plugins then
- // LoadRequirements will prevent it loading.
-#if defined(OS_CHROMEOS)
- continue;
-#elif defined(OS_WIN)
- if (base::win::IsMetroProcess()) {
- continue;
- }
-#endif // defined(OS_WIN).
- plugins_.push_back(PluginInfo());
- plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
- plugins_.back().is_public = is_public;
- }
- return true;
+bool Extension::ShouldDisplayInNewTabPage() const {
+ // Only apps should be displayed on the NTP.
+ return is_app() && display_in_new_tab_page_;
}
-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);
+bool Extension::ShouldDisplayInExtensionSettings() const {
+ // Don't show for themes since the settings UI isn't really useful for them.
+ if (is_theme())
+ return false;
+
+ // Don't show component extensions because they are only extensions as an
+ // implementation detail of Chrome.
+ if (location() == Extension::COMPONENT &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowComponentExtensionOptions)) {
return false;
}
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* module_value = NULL;
- if (!list_value->GetDictionary(i, &module_value)) {
- *error = ASCIIToUTF16(errors::kInvalidNaClModules);
- return false;
- }
+ // Always show unpacked extensions and apps.
+ if (location() == Extension::LOAD)
+ return true;
- // Get nacl_modules[i].path.
- std::string path_str;
- if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidNaClModulesPath, base::IntToString(i));
- return false;
- }
+ // Unless they are unpacked, never show hosted apps. Note: We intentionally
+ // show packaged apps and platform apps because there are some pieces of
+ // functionality that are only available in chrome://extensions/ but which
+ // are needed for packaged and platform apps. For example, inspecting
+ // background pages. See http://crbug.com/116134.
+ if (is_hosted_app())
+ return false;
- // Get nacl_modules[i].mime_type.
- std::string mime_type;
- if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
- 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::HasContentScriptAtURL(const GURL& url) const {
+ for (UserScriptList::const_iterator it = content_scripts_.begin();
+ it != content_scripts_.end(); ++it) {
+ if (it->MatchesURL(url))
+ return true;
}
+ return false;
+}
- return true;
+scoped_refptr<const PermissionSet> Extension::GetTabSpecificPermissions(
+ int tab_id) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ return runtime_data_.GetTabSpecificPermissions(tab_id);
}
-bool Extension::LoadWebAccessibleResources(string16* error) {
- if (!manifest_->HasKey(keys::kWebAccessibleResources))
- return true;
- ListValue* list_value = NULL;
- 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 = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidWebAccessibleResource, base::IntToString(i));
- return false;
- }
- URLPattern pattern(URLPattern::SCHEME_EXTENSION);
- if (pattern.Parse(extension_url_.spec()) != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, extension_url_.spec());
- return false;
- }
- while (relative_path[0] == '/')
- relative_path = relative_path.substr(1, relative_path.length() - 1);
- pattern.SetPath(pattern.path() + relative_path);
- web_accessible_resources_.AddPattern(pattern);
- }
+void Extension::UpdateTabSpecificPermissions(
+ int tab_id,
+ scoped_refptr<const PermissionSet> permissions) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ runtime_data_.UpdateTabSpecificPermissions(tab_id, permissions);
+}
- return true;
+void Extension::ClearTabSpecificPermissions(int tab_id) const {
+ base::AutoLock auto_lock(runtime_data_lock_);
+ runtime_data_.ClearTabSpecificPermissions(tab_id);
}
-bool Extension::LoadSandboxedPages(string16* error) {
- if (!manifest_->HasPath(keys::kSandboxedPages))
- return true;
+Extension::Location Extension::location() const {
+ return manifest_->location();
+}
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kSandboxedPages, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesList);
- return false;
- }
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- std::string relative_path;
- if (!list_value->GetString(i, &relative_path)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidSandboxedPage, base::IntToString(i));
- return false;
- }
- URLPattern pattern(URLPattern::SCHEME_EXTENSION);
- if (pattern.Parse(extension_url_.spec()) != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, extension_url_.spec());
- return false;
- }
- while (relative_path[0] == '/')
- relative_path = relative_path.substr(1, relative_path.length() - 1);
- pattern.SetPath(pattern.path() + relative_path);
- sandboxed_pages_.AddPattern(pattern);
- }
+const std::string& Extension::id() const {
+ return manifest_->extension_id();
+}
- if (manifest_->HasPath(keys::kSandboxedPagesCSP)) {
- if (!manifest_->GetString(
- keys::kSandboxedPagesCSP, &sandboxed_pages_content_security_policy_)) {
- *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
- return false;
- }
+const std::string Extension::VersionString() const {
+ return version()->GetString();
+}
- if (!ContentSecurityPolicyIsLegal(
- sandboxed_pages_content_security_policy_) ||
- !ContentSecurityPolicyIsSandboxed(
- sandboxed_pages_content_security_policy_, GetType())) {
- *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
- return false;
- }
- } else {
- sandboxed_pages_content_security_policy_ =
- kDefaultSandboxedPageContentSecurityPolicy;
- CHECK(ContentSecurityPolicyIsSandboxed(
- sandboxed_pages_content_security_policy_, GetType()));
- }
+void Extension::AddInstallWarnings(
+ const InstallWarningVector& new_warnings) {
+ install_warnings_.insert(install_warnings_.end(),
+ new_warnings.begin(), new_warnings.end());
+}
- return true;
+bool Extension::is_platform_app() const {
+ return manifest_->is_platform_app();
}
-bool Extension::LoadRequirements(string16* error) {
- // Before parsing requirements from the manifest, automatically default the
- // NPAPI plugin requirement based on whether it includes NPAPI plugins.
- ListValue* list_value = NULL;
- requirements_.npapi =
- manifest_->GetList(keys::kPlugins, &list_value) && !list_value->empty();
+bool Extension::is_hosted_app() const {
+ return manifest()->is_hosted_app();
+}
- if (!manifest_->HasKey(keys::kRequirements))
- return true;
+bool Extension::is_legacy_packaged_app() const {
+ return manifest()->is_legacy_packaged_app();
+}
- DictionaryValue* requirements_value = NULL;
- if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
- *error = ASCIIToUTF16(errors::kInvalidRequirements);
- return false;
- }
+bool Extension::is_theme() const {
+ return manifest()->is_theme();
+}
- 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 = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
+GURL Extension::GetBackgroundURL() const {
+ if (background_scripts_.empty())
+ return background_url_;
+ return GetResourceURL(extension_filenames::kGeneratedBackgroundPageFilename);
+}
- if (*it == "plugins") {
- for (DictionaryValue::key_iterator plugin_it =
- requirement_value->begin_keys();
- plugin_it != requirement_value->end_keys(); ++plugin_it) {
- bool plugin_required = false;
- if (!requirement_value->GetBoolean(*plugin_it, &plugin_required)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
- if (*plugin_it == "npapi") {
- requirements_.npapi = plugin_required;
- } else {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
- }
- } else if (*it == "3D") {
- ListValue* features = NULL;
- if (!requirement_value->GetListWithoutPathExpansion("features",
- &features) ||
- !features) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
+Extension::RuntimeData::RuntimeData() {}
+Extension::RuntimeData::RuntimeData(const PermissionSet* active)
+ : active_permissions_(active) {}
+Extension::RuntimeData::~RuntimeData() {}
- for (base::ListValue::iterator feature_it = features->begin();
- feature_it != features->end();
- ++feature_it) {
- std::string feature;
- if ((*feature_it)->GetAsString(&feature)) {
- if (feature == "webgl") {
- requirements_.webgl = true;
- } else if (feature == "css3d") {
- requirements_.css3d = true;
- } else {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidRequirement, *it);
- return false;
- }
- }
- }
- } else {
- *error = ASCIIToUTF16(errors::kInvalidRequirements);
- return false;
- }
- }
- return true;
+void Extension::RuntimeData::SetActivePermissions(
+ const PermissionSet* active) {
+ active_permissions_ = active;
}
-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;
+scoped_refptr<const PermissionSet>
+ Extension::RuntimeData::GetActivePermissions() const {
+ return active_permissions_;
}
-bool Extension::LoadOfflineEnabled(string16* error) {
- // Defaults to false, except for platform apps which are offline by default.
- if (!manifest_->HasKey(keys::kOfflineEnabled)) {
- offline_enabled_ = is_platform_app();
- return true;
- }
- if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
- *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
- return false;
- }
- return true;
+scoped_refptr<const PermissionSet>
+ Extension::RuntimeData::GetTabSpecificPermissions(int tab_id) const {
+ CHECK_GE(tab_id, 0);
+ TabPermissionsMap::const_iterator it = tab_specific_permissions_.find(tab_id);
+ return (it != tab_specific_permissions_.end()) ? it->second : NULL;
}
-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;
+void Extension::RuntimeData::UpdateTabSpecificPermissions(
+ int tab_id,
+ scoped_refptr<const PermissionSet> permissions) {
+ CHECK_GE(tab_id, 0);
+ if (tab_specific_permissions_.count(tab_id)) {
+ tab_specific_permissions_[tab_id] = PermissionSet::CreateUnion(
+ tab_specific_permissions_[tab_id],
+ permissions.get());
} 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;
- }
+ tab_specific_permissions_[tab_id] = permissions;
}
+}
- return true;
+void Extension::RuntimeData::ClearTabSpecificPermissions(int tab_id) {
+ CHECK_GE(tab_id, 0);
+ tab_specific_permissions_.erase(tab_id);
}
-bool Extension::LoadBackgroundScripts(string16* error) {
- const std::string& key = is_platform_app() ?
- keys::kPlatformAppBackgroundScripts : keys::kBackgroundScripts;
- return LoadBackgroundScripts(key, error);
-}
-
-bool Extension::LoadBackgroundScripts(const std::string& key, string16* error) {
- Value* background_scripts_value = NULL;
- if (!manifest_->Get(key, &background_scripts_value))
+// 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;
+ }
- CHECK(background_scripts_value);
- if (background_scripts_value->GetType() != Value::TYPE_LIST) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts);
- 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);
+ return false;
+ }
+ manifest->set_extension_id(extension_id);
+ return true;
}
- ListValue* background_scripts =
- static_cast<ListValue*>(background_scripts_value);
- for (size_t i = 0; i < background_scripts->GetSize(); ++i) {
- std::string script;
- if (!background_scripts->GetString(i, &script)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidBackgroundScript, base::IntToString(i));
+ 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;
}
- background_scripts_.push_back(script);
+ manifest->set_extension_id(extension_id);
+ return true;
}
+}
- return true;
+// static
+FilePath Extension::MaybeNormalizePath(const FilePath& path) {
+#if defined(OS_WIN)
+ // Normalize any drive letter to upper-case. We do this for consistency with
+ // net_utils::FilePathToFileURL(), which does the same thing, to make string
+ // comparisons simpler.
+ std::wstring path_str = path.value();
+ if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
+ path_str[1] == ':')
+ path_str[0] += ('A' - 'a');
+
+ return FilePath(path_str);
+#else
+ return path;
+#endif
}
-bool Extension::LoadBackgroundPage(
- const APIPermissionSet& api_permissions,
- string16* error) {
- if (is_platform_app()) {
- return LoadBackgroundPage(
- keys::kPlatformAppBackgroundPage, api_permissions, error);
- }
+// static
+bool Extension::IsTrustedId(const std::string& id) {
+ // See http://b/4946060 for more details.
+ return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
+}
- if (!LoadBackgroundPage(keys::kBackgroundPage, api_permissions, error))
- return false;
- if (background_url_.is_empty()) {
- return LoadBackgroundPage(
- keys::kBackgroundPageLegacy, api_permissions, error);
- }
- return true;
+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_is_persistent_(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),
+ display_in_launcher_(true),
+ display_in_new_tab_page_(true),
+ wants_file_access_(false),
+ creation_flags_(0) {
+ DCHECK(path.empty() || path.IsAbsolute());
+ path_ = MaybeNormalizePath(path);
}
-bool Extension::LoadBackgroundPage(
- const std::string& key,
- const APIPermissionSet& api_permissions,
- string16* error) {
- base::Value* background_page_value = NULL;
- if (!manifest_->Get(key, &background_page_value))
- return true;
+Extension::~Extension() {
+}
- if (!background_scripts_.empty()) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundCombination);
+bool Extension::InitFromValue(int flags, string16* error) {
+ DCHECK(error);
+
+ base::AutoLock auto_lock(runtime_data_lock_);
+
+ // Initialize permissions with an empty, default permission set.
+ runtime_data_.SetActivePermissions(new PermissionSet());
+ optional_permission_set_ = new PermissionSet();
+ required_permission_set_ = new PermissionSet();
+
+ creation_flags_ = flags;
+
+ // Important to load manifest version first because many other features
+ // depend on its value.
+ if (!LoadManifestVersion(error))
return false;
- }
+ // 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;
- std::string background_str;
- if (!background_page_value->GetAsString(&background_str)) {
- *error = ASCIIToUTF16(errors::kInvalidBackground);
+ if (!LoadRequiredFeatures(error))
return false;
- }
- if (is_hosted_app()) {
- background_url_ = GURL(background_str);
+ // We don't need to validate because InitExtensionID already did that.
+ manifest_->GetString(keys::kPublicKey, &public_key_);
- // Make sure "background" permission is set.
- if (!api_permissions.count(APIPermission::kBackground)) {
- *error = ASCIIToUTF16(errors::kBackgroundPermissionNeeded);
- return false;
- }
- // Hosted apps require an absolute URL.
- if (!background_url_.is_valid()) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
- return false;
- }
+ extension_url_ = Extension::GetBaseURLFromExtensionId(id());
- if (!(background_url_.SchemeIs("https") ||
- (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowHTTPBackgroundPage) &&
- background_url_.SchemeIs("http")))) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
- return false;
- }
- } else {
- background_url_ = GetResourceURL(background_str);
- }
+ // 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;
- return true;
-}
+ APIPermissionSet api_permissions;
+ URLPatternSet host_permissions;
+ if (!ParsePermissions(keys::kPermissions,
+ error,
+ &api_permissions,
+ &host_permissions)) {
+ return false;
+ }
-bool Extension::LoadBackgroundPersistent(
- const APIPermissionSet& api_permissions,
- string16* error) {
+ // TODO(jeremya/kalman) do this via the features system by exposing the
+ // app.window API to platform apps, with no dependency on any permissions.
+ // See http://crbug.com/120069.
if (is_platform_app()) {
- background_page_is_persistent_ = false;
- return true;
+ api_permissions.insert(APIPermission::kAppCurrentWindowInternal);
+ api_permissions.insert(APIPermission::kAppRuntime);
+ api_permissions.insert(APIPermission::kAppWindow);
}
- Value* background_persistent = NULL;
- if (!manifest_->Get(keys::kBackgroundPersistent, &background_persistent))
- return true;
+ if (from_webstore()) {
+ details_url_ =
+ GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id());
+ }
- if (!background_persistent->GetAsBoolean(&background_page_is_persistent_)) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistent);
+ APIPermissionSet optional_api_permissions;
+ URLPatternSet optional_host_permissions;
+ if (!ParsePermissions(keys::kOptionalPermissions,
+ error,
+ &optional_api_permissions,
+ &optional_host_permissions)) {
return false;
}
- if (!has_background_page()) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage);
+ if (!LoadAppIsolation(api_permissions, error))
return false;
- }
- return true;
-}
+ if (!LoadSharedFeatures(api_permissions, error))
+ return false;
-bool Extension::LoadBackgroundAllowJSAccess(
- const APIPermissionSet& api_permissions,
- string16* error) {
- Value* allow_js_access = NULL;
- if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access))
- return true;
+ if (!LoadExtensionFeatures(&api_permissions, error))
+ return false;
- if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) ||
- !allow_js_access->GetAsBoolean(&allow_background_js_access_)) {
- *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess);
+ if (!LoadThemeFeatures(error))
+ return false;
+
+ if (HasMultipleUISurfaces()) {
+ *error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
return false;
}
+ runtime_data_.SetActivePermissions(new PermissionSet(
+ this, api_permissions, host_permissions));
+ required_permission_set_ = new PermissionSet(
+ this, api_permissions, host_permissions);
+ optional_permission_set_ = new PermissionSet(
+ optional_api_permissions, optional_host_permissions, URLPatternSet());
+
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;
+bool Extension::LoadAppIsolation(const APIPermissionSet& api_permissions,
+ string16* error) {
+ // Platform apps always get isolated storage.
+ if (is_platform_app()) {
+ is_storage_isolated_ = true;
+ return true;
+ }
- service.action = UTF8ToUTF16(action_name);
+ // Other apps only get it if it is requested _and_ experimental APIs are
+ // enabled.
+ if (!api_permissions.count(APIPermission::kExperimental) || !is_app())
+ return true;
- const ListValue* mime_types = NULL;
- if (!intent_service.HasKey(keys::kIntentType) ||
- !intent_service.GetList(keys::kIntentType, &mime_types) ||
- mime_types->GetSize() == 0) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentType, action_name);
+ Value* tmp_isolation = NULL;
+ if (!manifest_->Get(keys::kIsolation, &tmp_isolation))
+ return true;
+
+ if (tmp_isolation->GetType() != Value::TYPE_LIST) {
+ *error = ASCIIToUTF16(errors::kInvalidIsolation);
return false;
}
- std::string href;
- if (intent_service.HasKey(keys::kIntentPath)) {
- if (!intent_service.GetString(keys::kIntentPath, &href)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentHref);
+ ListValue* isolation_list = static_cast<ListValue*>(tmp_isolation);
+ for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
+ std::string isolation_string;
+ if (!isolation_list->GetString(i, &isolation_string)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIsolationValue,
+ base::UintToString(i));
return false;
}
- }
- if (intent_service.HasKey(keys::kIntentHref)) {
- if (!href.empty()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentHrefOldAndNewKey, action_name,
- keys::kIntentPath, keys::kIntentHref);
- return false;
- }
- if (!intent_service.GetString(keys::kIntentHref, &href)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentHref);
- 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;
}
}
+ return true;
+}
- // For packaged/hosted apps, empty href implies the respective launch URLs.
- if (href.empty()) {
- if (is_hosted_app()) {
- href = launch_web_url();
- } else if (is_legacy_packaged_app()) {
- href = launch_local_path();
- }
+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;
}
+ non_localized_name_ = UTF16ToUTF8(localized_name);
+ base::i18n::AdjustStringForLocaleDirection(&localized_name);
+ name_ = UTF16ToUTF8(localized_name);
+ return true;
+}
- // If there still is not an href, the manifest is malformed, unless this is a
- // platform app in which case the href should not be present.
- if (href.empty() && !is_platform_app()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentHrefEmpty, action_name);
+bool Extension::LoadVersion(string16* error) {
+ std::string version_str;
+ if (!manifest_->GetString(keys::kVersion, &version_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
return false;
- } else if (!href.empty() && is_platform_app()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentHrefInPlatformApp, action_name);
+ }
+ version_.reset(new Version(version_str));
+ if (!version_->IsValid() || version_->components().size() > 4) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
return false;
}
+ return true;
+}
- 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 = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentPageInHostedApp, action_name);
+bool Extension::LoadAppFeatures(string16* error) {
+ if (!LoadExtent(keys::kWebURLs, &extent_,
+ errors::kInvalidWebURLs, errors::kInvalidWebURL, error) ||
+ !LoadLaunchURL(error) ||
+ !LoadLaunchContainer(error)) {
+ return false;
+ }
+ if (manifest_->HasKey(keys::kDisplayInLauncher) &&
+ !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
+ return false;
+ }
+ if (manifest_->HasKey(keys::kDisplayInNewTabPage)) {
+ if (!manifest_->GetBoolean(keys::kDisplayInNewTabPage,
+ &display_in_new_tab_page_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
return false;
}
- service.service_url = service_url;
- } else if (is_platform_app()) {
- service.service_url = GetBackgroundURL();
} else {
- // We do not allow absolute intent URLs in non-hosted apps.
- if (service_url.is_valid()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kCannotAccessPage, href);
- return false;
- }
- service.service_url = GetResourceURL(href);
+ // Inherit default from display_in_launcher property.
+ display_in_new_tab_page_ = display_in_launcher_;
}
+ return true;
+}
- if (intent_service.HasKey(keys::kIntentTitle) &&
- !intent_service.GetString(keys::kIntentTitle, &service.title)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
+bool Extension::LoadExtent(const char* key,
+ URLPatternSet* extent,
+ const char* list_error,
+ const char* value_error,
+ string16* error) {
+ Value* temp_pattern_value = NULL;
+ if (!manifest_->Get(key, &temp_pattern_value))
+ return true;
+
+ if (temp_pattern_value->GetType() != Value::TYPE_LIST) {
+ *error = ASCIIToUTF16(list_error);
return false;
}
- if (intent_service.HasKey(keys::kIntentDisposition)) {
- if (is_platform_app()) {
+ ListValue* pattern_list = static_cast<ListValue*>(temp_pattern_value);
+ for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
+ std::string pattern_string;
+ if (!pattern_list->GetString(i, &pattern_string)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(value_error,
+ base::UintToString(i),
+ errors::kExpectString);
+ return false;
+ }
+
+ URLPattern pattern(kValidWebExtentSchemes);
+ URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
+ if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
+ pattern_string += "/";
+ parse_result = pattern.Parse(pattern_string);
+ }
+
+ if (parse_result != URLPattern::PARSE_SUCCESS) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentDispositionInPlatformApp, action_name);
+ value_error,
+ base::UintToString(i),
+ URLPattern::GetParseResultString(parse_result));
return false;
}
- if (!intent_service.GetString(keys::kIntentDisposition, &value) ||
- (value != values::kIntentDispositionWindow &&
- value != values::kIntentDispositionInline)) {
- *error = ASCIIToUTF16(errors::kInvalidIntentDisposition);
+
+ // Do not allow authors to claim "<all_urls>".
+ if (pattern.match_all_urls()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ errors::kCannotClaimAllURLsInExtent);
return false;
}
- if (value == values::kIntentDispositionInline) {
- service.disposition =
- webkit_glue::WebIntentServiceData::DISPOSITION_INLINE;
- } else {
- service.disposition =
- webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW;
+
+ // Do not allow authors to claim "*" for host.
+ if (pattern.host().empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ errors::kCannotClaimAllHostsInExtent);
+ return false;
}
- }
- for (size_t i = 0; i < mime_types->GetSize(); ++i) {
- if (!mime_types->GetString(i, &service.type)) {
+ // We do not allow authors to put wildcards in their paths. Instead, we
+ // imply one at the end.
+ if (pattern.path().find('*') != std::string::npos) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIntentTypeElement, action_name,
- std::string(base::IntToString(i)));
+ value_error,
+ base::UintToString(i),
+ errors::kNoWildCardsInPaths);
return false;
}
- intents_services_.push_back(service);
+ pattern.SetPath(pattern.path() + '*');
+
+ extent->AddPattern(pattern);
}
+
return true;
}
-bool Extension::LoadWebIntentServices(string16* error) {
- DCHECK(error);
-
- if (!manifest_->HasKey(keys::kIntents))
+bool Extension::LoadLaunchContainer(string16* error) {
+ Value* tmp_launcher_container = NULL;
+ if (!manifest_->Get(keys::kLaunchContainer, &tmp_launcher_container))
return true;
- DictionaryValue* all_services = NULL;
- if (!manifest_->GetDictionary(keys::kIntents, &all_services)) {
- *error = ASCIIToUTF16(errors::kInvalidIntents);
+ std::string launch_container_string;
+ if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
+ *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
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;
- }
+ if (launch_container_string == values::kLaunchContainerPanel) {
+ launch_container_ = extension_misc::LAUNCH_PANEL;
+ } else if (launch_container_string == values::kLaunchContainerTab) {
+ launch_container_ = extension_misc::LAUNCH_TAB;
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
+ return false;
}
- return true;
-}
-bool Extension::LoadFileHandler(const std::string& handler_id,
- const DictionaryValue& handler_info,
- string16* error) {
- DCHECK(error);
- DCHECK(is_platform_app());
- FileHandlerInfo handler;
-
- handler.id = handler_id;
-
- const ListValue* mime_types = NULL;
- // TODO(benwells): handle file extensions.
- if (!handler_info.HasKey(keys::kFileHandlerTypes) ||
- !handler_info.GetList(keys::kFileHandlerTypes, &mime_types) ||
- mime_types->GetSize() == 0) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidFileHandlerType, handler_id);
- return false;
- }
+ bool can_specify_initial_size =
+ launch_container_ == extension_misc::LAUNCH_PANEL ||
+ launch_container_ == extension_misc::LAUNCH_WINDOW;
- if (handler_info.HasKey(keys::kFileHandlerTitle) &&
- !handler_info.GetString(keys::kFileHandlerTitle, &handler.title)) {
- *error = ASCIIToUTF16(errors::kInvalidFileHandlerTitle);
- return false;
+ // Validate the container width if present.
+ if (!ReadLaunchDimension(manifest_.get(),
+ keys::kLaunchWidth,
+ &launch_width_,
+ can_specify_initial_size,
+ error)) {
+ return false;
}
- std::string type;
- for (size_t i = 0; i < mime_types->GetSize(); ++i) {
- if (!mime_types->GetString(i, &type)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidFileHandlerTypeElement, handler_id,
- std::string(base::IntToString(i)));
+ // Validate container height if present.
+ if (!ReadLaunchDimension(manifest_.get(),
+ keys::kLaunchHeight,
+ &launch_height_,
+ can_specify_initial_size,
+ error)) {
return false;
- }
- handler.types.insert(type);
}
- file_handlers_.push_back(handler);
return true;
}
-bool Extension::LoadFileHandlers(string16* error) {
- DCHECK(error);
-
- if (!manifest_->HasKey(keys::kFileHandlers))
- return true;
-
- DictionaryValue* all_handlers = NULL;
- if (!manifest_->GetDictionary(keys::kFileHandlers, &all_handlers)) {
- *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
- return false;
- }
+bool Extension::LoadLaunchURL(string16* error) {
+ Value* temp = NULL;
- for (DictionaryValue::key_iterator iter(all_handlers->begin_keys());
- iter != all_handlers->end_keys(); ++iter) {
- // A file handler entry is a title and a list of MIME types to handle.
- DictionaryValue* handler = NULL;
- if (all_handlers->GetDictionaryWithoutPathExpansion(*iter, &handler)) {
- if (!LoadFileHandler(*iter, *handler, error))
- return false;
- } else {
- *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
+ // launch URL can be either local (to chrome-extension:// root) or an absolute
+ // web URL.
+ if (manifest_->Get(keys::kLaunchLocalPath, &temp)) {
+ if (manifest_->Get(keys::kLaunchWebURL, NULL)) {
+ *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
return false;
}
- }
- return true;
-}
-
-bool Extension::LoadExtensionFeatures(APIPermissionSet* api_permissions,
- string16* error) {
- if (manifest_->HasKey(keys::kConvertedFromUserScript))
- manifest_->GetBoolean(keys::kConvertedFromUserScript,
- &converted_from_user_script_);
-
- if (!LoadDevToolsPage(error) ||
- !LoadInputComponents(*api_permissions, error) ||
- !LoadContentScripts(error) ||
- !LoadPageAction(error) ||
- !LoadBrowserAction(error) ||
- !LoadSystemIndicator(api_permissions, error) ||
- !LoadScriptBadge(error) ||
- !LoadFileBrowserHandlers(error) ||
- !LoadChromeURLOverrides(error) ||
- !LoadOmnibox(error) ||
- !LoadTextToSpeechVoices(error) ||
- !LoadIncognitoMode(error) ||
- !LoadFileHandlers(error) ||
- !LoadContentSecurityPolicy(error))
- return false;
-
- return true;
-}
-
-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;
- }
- devtools_url_ = GetResourceURL(devtools_str);
- return true;
-}
-
-bool Extension::LoadInputComponents(const APIPermissionSet& 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;
- }
-
- 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);
+ if (manifest_->Get(keys::kWebURLs, NULL)) {
+ *error = ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive);
return false;
}
- // Get input_components[i].name.
- if (!module_value->GetString(keys::kName, &name_str)) {
+ std::string launch_path;
+ if (!temp->GetAsString(&launch_path)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentName, base::IntToString(i));
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath);
return false;
}
- // 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 {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentType, base::IntToString(i));
- return false;
- }
- } else {
+ // Ensure the launch path is a valid relative URL.
+ GURL resolved = url().Resolve(launch_path);
+ if (!resolved.is_valid() || resolved.GetOrigin() != url()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentType, base::IntToString(i));
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath);
return false;
}
- // Get input_components[i].id.
- if (!module_value->GetString(keys::kId, &id_str)) {
- id_str = "";
+ launch_local_path_ = launch_path;
+ } else if (manifest_->Get(keys::kLaunchWebURL, &temp)) {
+ std::string launch_url;
+ if (!temp->GetAsString(&launch_url)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
+ return false;
}
- // Get input_components[i].description.
- if (!module_value->GetString(keys::kDescription, &description_str)) {
+ // Ensure the launch URL is a valid absolute URL and web extent scheme.
+ GURL url(launch_url);
+ URLPattern pattern(kValidWebExtentSchemes);
+ if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentDescription, base::IntToString(i));
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
return false;
}
- // Get input_components[i].language.
- if (!module_value->GetString(keys::kLanguage, &language_str)) {
- language_str = "";
- }
- // Get input_components[i].layouts.
- ListValue* layouts_value = NULL;
- if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
- *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
+ launch_web_url_ = launch_url;
+ } else if (is_legacy_packaged_app() || is_hosted_app()) {
+ *error = ASCIIToUTF16(errors::kLaunchURLRequired);
+ return false;
+ }
+
+ // If there is no extent, we default the extent based on the launch URL.
+ if (web_extent().is_empty() && !launch_web_url().empty()) {
+ GURL launch_url(launch_web_url());
+ URLPattern pattern(kValidWebExtentSchemes);
+ if (!pattern.SetScheme("*")) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
return false;
}
+ pattern.SetHost(launch_url.host());
+ pattern.SetPath("/*");
+ extent_.AddPattern(pattern);
+ }
- for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
- std::string layout_name_str;
- if (!layouts_value->GetString(j, &layout_name_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentLayoutName, base::IntToString(i),
- base::IntToString(j));
- return false;
- }
- layouts.insert(layout_name_str);
+ // In order for the --apps-gallery-url switch to work with the gallery
+ // process isolation, we must insert any provided value into the component
+ // app's launch url and web extent.
+ if (id() == extension_misc::kWebStoreAppId) {
+ std::string gallery_url_str = CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kAppsGalleryURL);
+
+ // Empty string means option was not used.
+ if (!gallery_url_str.empty()) {
+ GURL gallery_url(gallery_url_str);
+ OverrideLaunchUrl(gallery_url);
+ }
+ } else if (id() == extension_misc::kCloudPrintAppId) {
+ // In order for the --cloud-print-service switch to work, we must update
+ // the launch URL and web extent.
+ // TODO(sanjeevr): Ideally we want to use CloudPrintURL here but that is
+ // currently under chrome/browser.
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
+ switches::kCloudPrintServiceURL));
+ if (!cloud_print_service_url.is_empty()) {
+ std::string path(
+ cloud_print_service_url.path() + "/enable_chrome_connector");
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ GURL cloud_print_enable_connector_url =
+ cloud_print_service_url.ReplaceComponents(replacements);
+ OverrideLaunchUrl(cloud_print_enable_connector_url);
}
+ } else if (id() == extension_misc::kChromeAppId) {
+ // Override launch url to new tab.
+ launch_web_url_ = chrome::kChromeUINewTabURL;
+ extent_.ClearPatterns();
+ }
- if (module_value->HasKey(keys::kShortcutKey)) {
- DictionaryValue* shortcut_value = NULL;
- if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
- return false;
- }
+ return true;
+}
- // Get input_components[i].shortcut_keycode.
- if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidInputComponentShortcutKeycode,
- base::IntToString(i));
- return false;
- }
-
- // Get input_components[i].shortcut_alt.
- if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
- shortcut_alt = false;
- }
-
- // Get input_components[i].shortcut_ctrl.
- if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
- shortcut_ctrl = false;
- }
-
- // Get input_components[i].shortcut_shift.
- if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
- shortcut_shift = 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;
- }
+bool Extension::LoadSharedFeatures(
+ const APIPermissionSet& api_permissions,
+ string16* error) {
+ if (!LoadDescription(error) ||
+ !LoadHomepageURL(error) ||
+ !LoadUpdateURL(error) ||
+ !LoadIcons(error) ||
+ !LoadCommands(error) ||
+ !LoadPlugins(error) ||
+ !LoadNaClModules(error) ||
+ !LoadWebAccessibleResources(error) ||
+ !LoadSandboxedPages(error) ||
+ !LoadRequirements(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) ||
+ !LoadOAuth2Info(error))
+ return false;
return true;
}
-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);
+bool Extension::LoadDescription(string16* error) {
+ if (manifest_->HasKey(keys::kDescription) &&
+ !manifest_->GetString(keys::kDescription, &description_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDescription);
return false;
}
-
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* content_script = NULL;
- if (!list_value->GetDictionary(i, &content_script)) {
- *error = ErrorUtils::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;
-
- if (manifest_->HasKey(keys::kPageActions)) {
- ListValue* list_value = NULL;
- if (!manifest_->GetList(keys::kPageActions, &list_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
- 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);
- return false;
- }
- } else if (manifest_->HasKey(keys::kPageAction)) {
- if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) {
- *error = ASCIIToUTF16(errors::kInvalidPageAction);
+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;
}
}
- // If page_action_value is not NULL, then there was a valid page action.
- if (page_action_value) {
- page_action_info_ = LoadExtensionActionInfoHelper(
- page_action_value, Extension::ActionInfo::TYPE_PAGE, error);
- if (!page_action_info_.get())
- return false; // Failed to parse page action definition.
+ manifest_version_ = manifest_->GetManifestVersion();
+ if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
+ manifest_version_ < kModernManifestVersion &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowLegacyExtensionManifests)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidManifestVersionOld,
+ base::IntToString(kModernManifestVersion));
+ return false;
}
return true;
}
-bool Extension::LoadBrowserAction(string16* error) {
- if (!manifest_->HasKey(keys::kBrowserAction))
+bool Extension::LoadHomepageURL(string16* error) {
+ if (!manifest_->HasKey(keys::kHomepageURL))
return true;
- DictionaryValue* browser_action_value = NULL;
- if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) {
- *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
+ std::string tmp_homepage_url;
+ if (!manifest_->GetString(keys::kHomepageURL, &tmp_homepage_url)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidHomepageURL, "");
+ return false;
+ }
+ homepage_url_ = GURL(tmp_homepage_url);
+ if (!homepage_url_.is_valid() ||
+ (!homepage_url_.SchemeIs("http") &&
+ !homepage_url_.SchemeIs("https"))) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidHomepageURL, tmp_homepage_url);
return false;
}
-
- browser_action_info_ = LoadExtensionActionInfoHelper(
- browser_action_value, Extension::ActionInfo::TYPE_BROWSER, error);
- if (!browser_action_info_.get())
- return false; // Failed to parse browser action definition.
return true;
}
-bool Extension::LoadSystemIndicator(APIPermissionSet* api_permissions,
- string16* error) {
- if (!manifest_->HasKey(keys::kSystemIndicator)) {
- // There was no manifest entry for the system indicator.
+bool Extension::LoadUpdateURL(string16* error) {
+ if (!manifest_->HasKey(keys::kUpdateURL))
return true;
+ std::string tmp_update_url;
+ if (!manifest_->GetString(keys::kUpdateURL, &tmp_update_url)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidUpdateURL, "");
+ return false;
}
-
- DictionaryValue* system_indicator_value = NULL;
- if (!manifest_->GetDictionary(keys::kSystemIndicator,
- &system_indicator_value)) {
- *error = ASCIIToUTF16(errors::kInvalidSystemIndicator);
+ update_url_ = GURL(tmp_update_url);
+ if (!update_url_.is_valid() ||
+ update_url_.has_ref()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidUpdateURL, tmp_update_url);
return false;
}
+ return true;
+}
- system_indicator_info_ = LoadExtensionActionInfoHelper(
- system_indicator_value,
- Extension::ActionInfo::TYPE_SYSTEM_INDICATOR,
- error);
-
- if (!system_indicator_info_.get()) {
+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;
}
- // Because the manifest was successfully parsed, auto-grant the permission.
- // TODO(dewittj) Add this for all extension action APIs.
- api_permissions->insert(APIPermission::kSystemIndicator);
-
- return true;
+ return LoadIconsFromDictionary(icons_value,
+ extension_misc::kExtensionIconSizes,
+ extension_misc::kNumExtensionIconSizes,
+ &icons_,
+ error);
}
-bool Extension::LoadScriptBadge(string16* error) {
- if (manifest_->HasKey(keys::kScriptBadge)) {
- if (!FeatureSwitch::script_badges()->IsEnabled()) {
- // So as to not confuse developers if they specify a script badge section
- // in the manifest, show a warning if the script badge declaration isn't
- // going to have any effect.
- install_warnings_.push_back(
- InstallWarning(InstallWarning::FORMAT_TEXT,
- errors::kScriptBadgeRequiresFlag));
+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;
}
- DictionaryValue* script_badge_value = NULL;
- if (!manifest_->GetDictionary(keys::kScriptBadge, &script_badge_value)) {
- *error = ASCIIToUTF16(errors::kInvalidScriptBadge);
+ if (commands->size() > kMaxCommandsPerExtension) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingTooMany,
+ base::IntToString(kMaxCommandsPerExtension));
return false;
}
- script_badge_info_ = LoadExtensionActionInfoHelper(
- script_badge_value, Extension::ActionInfo::TYPE_SCRIPT_BADGE, error);
- if (!script_badge_info_.get())
- return false; // Failed to parse script badge definition.
- } else {
- script_badge_info_.reset(new ActionInfo());
- }
+ int command_index = 0;
+ for (DictionaryValue::key_iterator iter = commands->begin_keys();
+ iter != commands->end_keys(); ++iter) {
+ ++command_index;
- // Script badges always use their extension's title and icon so users can rely
- // on the visual appearance to know which extension is running. This isn't
- // bulletproof since an malicious extension could use a different 16x16 icon
- // that matches the icon of a trusted extension, and users wouldn't be warned
- // during installation.
+ DictionaryValue* command = NULL;
+ if (!commands->GetDictionary(*iter, &command)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingDictionary,
+ base::IntToString(command_index));
+ return false;
+ }
- if (!script_badge_info_->default_title.empty()) {
- install_warnings_.push_back(
- InstallWarning(InstallWarning::FORMAT_TEXT,
- errors::kScriptBadgeTitleIgnored));
- }
- script_badge_info_->default_title = name();
+ scoped_ptr<extensions::Command> binding(new extensions::Command());
+ if (!binding->Parse(command, *iter, command_index, error))
+ return false; // |error| already set.
- if (!script_badge_info_->default_icon.empty()) {
- install_warnings_.push_back(
- InstallWarning(InstallWarning::FORMAT_TEXT,
- errors::kScriptBadgeIconIgnored));
+ std::string command_name = binding->command_name();
+ if (command_name == values::kPageActionCommandEvent) {
+ page_action_command_.reset(binding.release());
+ } else if (command_name == values::kBrowserActionCommandEvent) {
+ browser_action_command_.reset(binding.release());
+ } else if (command_name == values::kScriptBadgeCommandEvent) {
+ script_badge_command_.reset(binding.release());
+ } else {
+ if (command_name[0] != '_') // All commands w/underscore are reserved.
+ named_commands_[command_name] = *binding.get();
+ }
+ }
}
- script_badge_info_->default_icon.Clear();
- for (size_t i = 0; i < extension_misc::kNumScriptBadgeIconSizes; i++) {
- std::string path = icons().Get(extension_misc::kScriptBadgeIconSizes[i],
- ExtensionIconSet::MATCH_BIGGER);
- if (!path.empty())
- script_badge_info_->default_icon.Add(
- extension_misc::kScriptBadgeIconSizes[i], path);
+ if (manifest_->HasKey(keys::kBrowserAction) &&
+ !browser_action_command_.get()) {
+ // If the extension defines a browser action, but no command for it, then
+ // we synthesize a generic one, so the user can configure a shortcut for it.
+ // No keyboard shortcut will be assigned to it, until the user selects one.
+ browser_action_command_.reset(
+ new extensions::Command(
+ values::kBrowserActionCommandEvent, string16(), ""));
}
return true;
}
-bool Extension::LoadFileBrowserHandlers(string16* error) {
- if (!manifest_->HasKey(keys::kFileBrowserHandlers))
+bool Extension::LoadPlugins(string16* error) {
+ if (!manifest_->HasKey(keys::kPlugins))
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();
-}
-
-FileBrowserHandler* Extension::LoadFileBrowserHandler(
- const DictionaryValue* file_browser_handler, string16* error) {
- scoped_ptr<FileBrowserHandler> result(new FileBrowserHandler());
- result->set_extension_id(id());
-
- 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);
- // 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;
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kPlugins, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPlugins);
+ return false;
}
- result->set_title(title);
- // Initialize access permissions (optional).
- const ListValue* access_list_value = NULL;
- if (file_browser_handler->HasKey(keys::kFileAccessList)) {
- if (!file_browser_handler->GetList(keys::kFileAccessList,
- &access_list_value) ||
- access_list_value->empty()) {
- *error = ASCIIToUTF16(errors::kInvalidFileAccessList);
- return NULL;
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* plugin_value = NULL;
+ if (!list_value->GetDictionary(i, &plugin_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPlugins);
+ return false;
}
- for (size_t i = 0; i < access_list_value->GetSize(); ++i) {
- std::string access;
- if (!access_list_value->GetString(i, &access) ||
- result->AddFileAccessPermission(access)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidFileAccessValue, base::IntToString(i));
- return NULL;
- }
+ // Get plugins[i].path.
+ std::string path_str;
+ if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPluginsPath, base::IntToString(i));
+ return false;
}
- }
- if (!result->ValidateFileAccessPermissions()) {
- *error = ASCIIToUTF16(errors::kInvalidFileAccessList);
- return NULL;
- }
- // Initialize file filters (mandatory, unless "create" access is specified,
- // in which case is ignored).
- if (!result->HasCreateAccessPermission()) {
- const 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 = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidFileFilterValue, base::IntToString(i));
- return NULL;
- }
- StringToLowerASCII(&filter);
- if (!StartsWithASCII(filter,
- std::string(chrome::kFileSystemScheme) + ':',
- true)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, filter);
- return NULL;
- }
- // The user inputs filesystem:*; we don't actually implement scheme
- // wildcards in URLPattern, so transform to what will match correctly.
- filter.replace(0, 11, "chrome-extension://*/");
- URLPattern pattern(URLPattern::SCHEME_EXTENSION);
- if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, filter);
- return NULL;
- }
- std::string path = pattern.path();
- bool allowed = path == "/*" || path == "/*.*" ||
- (path.compare(0, 3, "/*.") == 0 &&
- path.find_first_of('*', 3) == std::string::npos);
- if (!allowed) {
+ // Get plugins[i].content (optional).
+ bool is_public = false;
+ if (plugin_value->HasKey(keys::kPluginsPublic)) {
+ if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, filter);
- return NULL;
+ errors::kInvalidPluginsPublic, base::IntToString(i));
+ return false;
}
- result->AddPattern(pattern);
}
- }
- 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;
+ // We don't allow extensions to load NPAPI plugins on Chrome OS, or under
+ // Windows 8 Metro mode, but still parse the entries to display consistent
+ // error messages. If the extension actually requires the plugins then
+ // LoadRequirements will prevent it loading.
+#if defined(OS_CHROMEOS)
+ continue;
+#elif defined(OS_WIN)
+ if (base::win::IsMetroProcess()) {
+ continue;
}
- result->set_icon_path(default_icon);
+#endif // defined(OS_WIN).
+ plugins_.push_back(PluginInfo());
+ plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
+ plugins_.back().is_public = is_public;
}
-
- return result.release();
+ return true;
}
-bool Extension::LoadChromeURLOverrides(string16* error) {
- if (!manifest_->HasKey(keys::kChromeURLOverrides))
+bool Extension::LoadNaClModules(string16* error) {
+ if (!manifest_->HasKey(keys::kNaClModules))
return true;
- DictionaryValue* overrides = NULL;
- if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
- *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kNaClModules, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidNaClModules);
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.
- bool is_override = (page != chrome::kChromeUINewTabHost &&
- page != chrome::kChromeUIBookmarksHost &&
- page != chrome::kChromeUIHistoryHost);
-#if defined(OS_CHROMEOS)
- is_override = (is_override &&
- page != chrome::kChromeUIActivationMessageHost);
-#endif
-#if defined(FILE_MANAGER_EXTENSION)
- is_override = (is_override &&
- !(location() == COMPONENT &&
- page == chrome::kChromeUIFileManagerHost));
-#endif
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* module_value = NULL;
+ if (!list_value->GetDictionary(i, &module_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidNaClModules);
+ return false;
+ }
- if (is_override || !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
- *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ // Get nacl_modules[i].path.
+ std::string path_str;
+ if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidNaClModulesPath, base::IntToString(i));
return false;
}
- // Replace the entry with a fully qualified chrome-extension:// URL.
- chrome_url_overrides_[page] = GetResourceURL(val);
- // For component extensions, add override URL to extent patterns.
- if (is_legacy_packaged_app() && location() == COMPONENT) {
- URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
- std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
- page.c_str());
- if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidURLPatternError, url);
- return false;
- }
- extent_.AddPattern(pattern);
+ // Get nacl_modules[i].mime_type.
+ std::string mime_type;
+ if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
+ *error = ErrorUtils::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;
}
- // An extension may override at most one page.
- if (overrides->size() > 1) {
- *error = ASCIIToUTF16(errors::kMultipleOverrides);
+ return true;
+}
+
+bool Extension::LoadWebAccessibleResources(string16* error) {
+ if (!manifest_->HasKey(keys::kWebAccessibleResources))
+ return true;
+ ListValue* list_value = NULL;
+ 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 = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAccessibleResource, base::IntToString(i));
+ return false;
+ }
+ URLPattern pattern(URLPattern::SCHEME_EXTENSION);
+ if (pattern.Parse(extension_url_.spec()) != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, extension_url_.spec());
+ return false;
+ }
+ while (relative_path[0] == '/')
+ relative_path = relative_path.substr(1, relative_path.length() - 1);
+ pattern.SetPath(pattern.path() + relative_path);
+ web_accessible_resources_.AddPattern(pattern);
+ }
return true;
}
-bool Extension::LoadOmnibox(string16* error) {
- if (!manifest_->HasKey(keys::kOmnibox))
+bool Extension::LoadSandboxedPages(string16* error) {
+ if (!manifest_->HasPath(keys::kSandboxedPages))
return true;
- if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
- omnibox_keyword_.empty()) {
- *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword);
+
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kSandboxedPages, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesList);
return false;
}
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ std::string relative_path;
+ if (!list_value->GetString(i, &relative_path)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidSandboxedPage, base::IntToString(i));
+ return false;
+ }
+ URLPattern pattern(URLPattern::SCHEME_EXTENSION);
+ if (pattern.Parse(extension_url_.spec()) != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, extension_url_.spec());
+ return false;
+ }
+ while (relative_path[0] == '/')
+ relative_path = relative_path.substr(1, relative_path.length() - 1);
+ pattern.SetPath(pattern.path() + relative_path);
+ sandboxed_pages_.AddPattern(pattern);
+ }
+
+ if (manifest_->HasPath(keys::kSandboxedPagesCSP)) {
+ if (!manifest_->GetString(
+ keys::kSandboxedPagesCSP, &sandboxed_pages_content_security_policy_)) {
+ *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
+ return false;
+ }
+
+ if (!ContentSecurityPolicyIsLegal(
+ sandboxed_pages_content_security_policy_) ||
+ !ContentSecurityPolicyIsSandboxed(
+ sandboxed_pages_content_security_policy_, GetType())) {
+ *error = ASCIIToUTF16(errors::kInvalidSandboxedPagesCSP);
+ return false;
+ }
+ } else {
+ sandboxed_pages_content_security_policy_ =
+ kDefaultSandboxedPageContentSecurityPolicy;
+ CHECK(ContentSecurityPolicyIsSandboxed(
+ sandboxed_pages_content_security_policy_, GetType()));
+ }
+
return true;
}
-bool Extension::LoadTextToSpeechVoices(string16* error) {
- if (!manifest_->HasKey(keys::kTtsEngine))
+bool Extension::LoadRequirements(string16* error) {
+ // Before parsing requirements from the manifest, automatically default the
+ // NPAPI plugin requirement based on whether it includes NPAPI plugins.
+ ListValue* list_value = NULL;
+ requirements_.npapi =
+ manifest_->GetList(keys::kPlugins, &list_value) && !list_value->empty();
+
+ if (!manifest_->HasKey(keys::kRequirements))
return true;
- DictionaryValue* tts_dict = NULL;
- if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) {
- *error = ASCIIToUTF16(errors::kInvalidTts);
+
+ DictionaryValue* requirements_value = NULL;
+ if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidRequirements);
return false;
}
- if (tts_dict->HasKey(keys::kTtsVoices)) {
- ListValue* tts_voices = NULL;
- if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
- *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
+ 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 = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
return false;
}
- 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;
- }
-
- 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);
+ if (*it == "plugins") {
+ for (DictionaryValue::key_iterator plugin_it =
+ requirement_value->begin_keys();
+ plugin_it != requirement_value->end_keys(); ++plugin_it) {
+ bool plugin_required = false;
+ if (!requirement_value->GetBoolean(*plugin_it, &plugin_required)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
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);
+ if (*plugin_it == "npapi") {
+ requirements_.npapi = plugin_required;
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
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;
- }
+ } else if (*it == "3D") {
+ ListValue* features = NULL;
+ if (!requirement_value->GetListWithoutPathExpansion("features",
+ &features) ||
+ !features) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
+ 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);
+
+ for (base::ListValue::iterator feature_it = features->begin();
+ feature_it != features->end();
+ ++feature_it) {
+ std::string feature;
+ if ((*feature_it)->GetAsString(&feature)) {
+ if (feature == "webgl") {
+ requirements_.webgl = true;
+ } else if (feature == "css3d") {
+ requirements_.css3d = true;
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRequirement, *it);
return false;
}
- voice_data.event_types.insert(event_type);
}
}
-
- tts_voices_.push_back(voice_data);
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidRequirements);
+ return false;
}
}
return true;
}
-bool Extension::LoadIncognitoMode(string16* error) {
- // Apps default to split mode, extensions default to spanning.
- incognito_split_mode_ = is_app();
- if (!manifest_->HasKey(keys::kIncognito))
+bool Extension::LoadDefaultLocale(string16* error) {
+ if (!manifest_->HasKey(keys::kDefaultLocale))
return true;
- std::string value;
- if (!manifest_->GetString(keys::kIncognito, &value)) {
- *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
+ if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) ||
+ !l10n_util::IsValidLocaleSyntax(default_locale_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDefaultLocale);
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 true;
+}
+
+bool Extension::LoadOfflineEnabled(string16* error) {
+ // Defaults to false, except for platform apps which are offline by default.
+ if (!manifest_->HasKey(keys::kOfflineEnabled)) {
+ offline_enabled_ = is_platform_app();
+ return true;
+ }
+ if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
+ *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
return false;
}
return true;
}
-bool Extension::LoadContentSecurityPolicy(string16* error) {
- const std::string& key = is_platform_app() ?
- keys::kPlatformAppContentSecurityPolicy : keys::kContentSecurityPolicy;
+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 (manifest_->HasPath(key)) {
- std::string content_security_policy;
- if (!manifest_->GetString(key, &content_security_policy)) {
- *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
+ 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;
}
- if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
- *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
+ options_url_ = options_url;
+ } else {
+ GURL absolute(options_str);
+ if (absolute.is_valid()) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
return false;
}
- if (manifest_version_ >= 2 &&
- !ContentSecurityPolicyIsSecure(content_security_policy, GetType())) {
- *error = ASCIIToUTF16(errors::kInsecureContentSecurityPolicy);
+ options_url_ = GetResourceURL(options_str);
+ if (!options_url_.is_valid()) {
+ *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
return false;
}
-
- 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_ = is_platform_app() ?
- kDefaultPlatformAppContentSecurityPolicy :
- kDefaultContentSecurityPolicy;
- CHECK(ContentSecurityPolicyIsSecure(content_security_policy_, GetType()));
}
+
return true;
}
-bool Extension::LoadAppIsolation(const APIPermissionSet& api_permissions,
- string16* error) {
- // Platform apps always get isolated storage.
- if (is_platform_app()) {
- is_storage_isolated_ = true;
- return true;
- }
-
- // Other apps only get it if it is requested _and_ experimental APIs are
- // enabled.
- if (!api_permissions.count(APIPermission::kExperimental) || !is_app())
- return true;
+bool Extension::LoadBackgroundScripts(string16* error) {
+ const std::string& key = is_platform_app() ?
+ keys::kPlatformAppBackgroundScripts : keys::kBackgroundScripts;
+ return LoadBackgroundScripts(key, error);
+}
- Value* tmp_isolation = NULL;
- if (!manifest_->Get(keys::kIsolation, &tmp_isolation))
+bool Extension::LoadBackgroundScripts(const std::string& key, string16* error) {
+ Value* background_scripts_value = NULL;
+ if (!manifest_->Get(key, &background_scripts_value))
return true;
- if (tmp_isolation->GetType() != Value::TYPE_LIST) {
- *error = ASCIIToUTF16(errors::kInvalidIsolation);
+ CHECK(background_scripts_value);
+ if (background_scripts_value->GetType() != Value::TYPE_LIST) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts);
return false;
}
- ListValue* isolation_list = static_cast<ListValue*>(tmp_isolation);
- for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
- std::string isolation_string;
- if (!isolation_list->GetString(i, &isolation_string)) {
+ ListValue* background_scripts =
+ static_cast<ListValue*>(background_scripts_value);
+ for (size_t i = 0; i < background_scripts->GetSize(); ++i) {
+ std::string script;
+ if (!background_scripts->GetString(i, &script)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidIsolationValue,
- base::UintToString(i));
+ errors::kInvalidBackgroundScript, base::IntToString(i));
return false;
}
+ background_scripts_.push_back(script);
+ }
- // 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;
+}
+
+bool Extension::LoadBackgroundPage(
+ const APIPermissionSet& api_permissions,
+ string16* error) {
+ if (is_platform_app()) {
+ return LoadBackgroundPage(
+ keys::kPlatformAppBackgroundPage, api_permissions, error);
+ }
+
+ if (!LoadBackgroundPage(keys::kBackgroundPage, api_permissions, error))
+ return false;
+ if (background_url_.is_empty()) {
+ return LoadBackgroundPage(
+ keys::kBackgroundPageLegacy, api_permissions, error);
}
return true;
}
-bool Extension::LoadThemeFeatures(string16* error) {
- if (!manifest_->HasKey(keys::kTheme))
+bool Extension::LoadBackgroundPage(
+ const std::string& key,
+ const APIPermissionSet& api_permissions,
+ string16* error) {
+ base::Value* background_page_value = NULL;
+ if (!manifest_->Get(key, &background_page_value))
return true;
- DictionaryValue* theme_value = NULL;
- if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
- *error = ASCIIToUTF16(errors::kInvalidTheme);
+
+ if (!background_scripts_.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundCombination);
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))
+
+
+ std::string background_str;
+ if (!background_page_value->GetAsString(&background_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidBackground);
return false;
+ }
- return true;
-}
+ if (is_hosted_app()) {
+ background_url_ = GURL(background_str);
-bool Extension::LoadThemeImages(const DictionaryValue* theme_value,
- string16* error) {
- const 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;
- }
+ // Make sure "background" permission is set.
+ if (!api_permissions.count(APIPermission::kBackground)) {
+ *error = ASCIIToUTF16(errors::kBackgroundPermissionNeeded);
+ return false;
+ }
+ // Hosted apps require an absolute URL.
+ if (!background_url_.is_valid()) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
+ return false;
}
- theme_images_.reset(images_value->DeepCopy());
- }
- return true;
-}
-bool Extension::LoadThemeColors(const DictionaryValue* theme_value,
- string16* error) {
- const 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) {
- const 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;
- }
+ if (!(background_url_.SchemeIs("https") ||
+ (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowHTTPBackgroundPage) &&
+ background_url_.SchemeIs("http")))) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
+ return false;
}
- theme_colors_.reset(colors_value->DeepCopy());
+ } else {
+ background_url_ = GetResourceURL(background_str);
}
+
return true;
}
-bool Extension::LoadThemeTints(const DictionaryValue* theme_value,
- string16* error) {
- const DictionaryValue* tints_value = NULL;
- if (!theme_value->GetDictionary(keys::kThemeTints, &tints_value))
+bool Extension::LoadBackgroundPersistent(
+ const APIPermissionSet& api_permissions,
+ string16* error) {
+ if (is_platform_app()) {
+ background_page_is_persistent_ = false;
return true;
+ }
- // Validate that the tints are all reals.
- for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
- iter != tints_value->end_keys(); ++iter) {
- const 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;
- }
+ Value* background_persistent = NULL;
+ if (!manifest_->Get(keys::kBackgroundPersistent, &background_persistent))
+ return true;
+
+ if (!background_persistent->GetAsBoolean(&background_page_is_persistent_)) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistent);
+ return false;
}
- theme_tints_.reset(tints_value->DeepCopy());
+
+ if (!has_background_page()) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage);
+ return false;
+ }
+
return true;
}
-bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value,
- string16* error) {
- const DictionaryValue* display_properties_value = NULL;
- if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
- &display_properties_value)) {
- theme_display_properties_.reset(
- display_properties_value->DeepCopy());
+bool Extension::LoadBackgroundAllowJSAccess(
+ const APIPermissionSet& api_permissions,
+ string16* error) {
+ Value* allow_js_access = NULL;
+ if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access))
+ return true;
+
+ if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) ||
+ !allow_js_access->GetAsBoolean(&allow_background_js_access_)) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess);
+ return false;
}
+
return true;
}
-// static
-bool Extension::IsTrustedId(const std::string& id) {
- // See http://b/4946060 for more details.
- return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
-}
+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(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_is_persistent_(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),
- display_in_launcher_(true),
- display_in_new_tab_page_(true),
- wants_file_access_(false),
- creation_flags_(0) {
- DCHECK(path.empty() || path.IsAbsolute());
- path_ = MaybeNormalizePath(path);
-}
+ service.action = UTF8ToUTF16(action_name);
-Extension::~Extension() {
-}
+ const ListValue* mime_types = NULL;
+ if (!intent_service.HasKey(keys::kIntentType) ||
+ !intent_service.GetList(keys::kIntentType, &mime_types) ||
+ mime_types->GetSize() == 0) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentType, action_name);
+ return false;
+ }
-ExtensionResource Extension::GetResource(
- const std::string& relative_path) const {
- std::string new_path = relative_path;
- // We have some legacy data where resources have leading slashes.
- // See: http://crbug.com/121164
- if (!new_path.empty() && new_path.at(0) == '/')
- new_path.erase(0, 1);
-#if defined(OS_POSIX)
- FilePath relative_file_path(new_path);
-#elif defined(OS_WIN)
- FilePath relative_file_path(UTF8ToWide(new_path));
-#endif
- ExtensionResource r(id(), path(), relative_file_path);
- if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
- r.set_follow_symlinks_anywhere();
+ std::string href;
+ if (intent_service.HasKey(keys::kIntentPath)) {
+ if (!intent_service.GetString(keys::kIntentPath, &href)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentHref);
+ return false;
+ }
}
- return r;
-}
-ExtensionResource Extension::GetResource(
- const FilePath& relative_file_path) const {
- ExtensionResource r(id(), path(), relative_file_path);
- if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
- r.set_follow_symlinks_anywhere();
+ if (intent_service.HasKey(keys::kIntentHref)) {
+ if (!href.empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentHrefOldAndNewKey, action_name,
+ keys::kIntentPath, keys::kIntentHref);
+ return false;
+ }
+ if (!intent_service.GetString(keys::kIntentHref, &href)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentHref);
+ return false;
+ }
}
- return r;
-}
-// 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)
+ // For packaged/hosted apps, empty href implies the respective launch URLs.
+ if (href.empty()) {
+ if (is_hosted_app()) {
+ href = launch_web_url();
+ } else if (is_legacy_packaged_app()) {
+ href = launch_local_path();
+ }
+ }
+
+ // If there still is not an href, the manifest is malformed, unless this is a
+ // platform app in which case the href should not be present.
+ if (href.empty() && !is_platform_app()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentHrefEmpty, action_name);
return false;
- if (input.length() == 0)
+ } else if (!href.empty() && is_platform_app()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentHrefInPlatformApp, action_name);
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)
+ 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 = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentPageInHostedApp, action_name);
return false;
- if (start_pos >= end_pos)
+ }
+ service.service_url = service_url;
+ } else if (is_platform_app()) {
+ service.service_url = GetBackgroundURL();
+ } else {
+ // We do not allow absolute intent URLs in non-hosted apps.
+ if (service_url.is_valid()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kCannotAccessPage, href);
return false;
+ }
+ service.service_url = GetResourceURL(href);
+ }
- working = working.substr(start_pos, end_pos - start_pos);
- if (working.length() == 0)
+ if (intent_service.HasKey(keys::kIntentTitle) &&
+ !intent_service.GetString(keys::kIntentTitle, &service.title)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
+ return false;
+ }
+
+ if (intent_service.HasKey(keys::kIntentDisposition)) {
+ if (is_platform_app()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentDispositionInPlatformApp, action_name);
return false;
+ }
+ if (!intent_service.GetString(keys::kIntentDisposition, &value) ||
+ (value != values::kIntentDispositionWindow &&
+ value != values::kIntentDispositionInline)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntentDisposition);
+ return false;
+ }
+ if (value == values::kIntentDispositionInline) {
+ service.disposition =
+ webkit_glue::WebIntentServiceData::DISPOSITION_INLINE;
+ } else {
+ service.disposition =
+ webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW;
+ }
}
- return base::Base64Decode(working, output);
+ for (size_t i = 0; i < mime_types->GetSize(); ++i) {
+ if (!mime_types->GetString(i, &service.type)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidIntentTypeElement, action_name,
+ std::string(base::IntToString(i)));
+ return false;
+ }
+ intents_services_.push_back(service);
+ }
+ return true;
}
-bool Extension::ProducePEM(const std::string& input, std::string* output) {
- DCHECK(output);
- return (input.length() == 0) ? false : base::Base64Encode(input, output);
-}
+bool Extension::LoadWebIntentServices(string16* error) {
+ DCHECK(error);
-bool Extension::FormatPEMForFileOutput(const std::string& input,
- std::string* output,
- bool is_public) {
- DCHECK(output);
- if (input.length() == 0)
+ if (!manifest_->HasKey(keys::kIntents))
+ return true;
+
+ DictionaryValue* all_services = NULL;
+ if (!manifest_->GetDictionary(keys::kIntents, &all_services)) {
+ *error = ASCIIToUTF16(errors::kInvalidIntents);
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");
+ 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;
+ }
+ }
return true;
}
-// static
-void Extension::DecodeIcon(const Extension* extension,
- int preferred_icon_size,
- ExtensionIconSet::MatchType match_type,
- scoped_ptr<SkBitmap>* result) {
- std::string path = extension->icons().Get(preferred_icon_size, match_type);
- int size = extension->icons().GetIconSizeFromPath(path);
- ExtensionResource icon_resource = extension->GetResource(path);
- DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
-}
-
-// static
-void Extension::DecodeIcon(const Extension* extension,
- int icon_size,
- scoped_ptr<SkBitmap>* result) {
- DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
-}
+bool Extension::LoadFileHandler(const std::string& handler_id,
+ const DictionaryValue& handler_info,
+ string16* error) {
+ DCHECK(error);
+ DCHECK(is_platform_app());
+ FileHandlerInfo handler;
-// static
-void Extension::DecodeIconFromPath(const FilePath& icon_path,
- int icon_size,
- scoped_ptr<SkBitmap>* result) {
- if (icon_path.empty())
- return;
+ handler.id = handler_id;
- std::string file_contents;
- if (!file_util::ReadFileToString(icon_path, &file_contents)) {
- DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
- return;
+ const ListValue* mime_types = NULL;
+ // TODO(benwells): handle file extensions.
+ if (!handler_info.HasKey(keys::kFileHandlerTypes) ||
+ !handler_info.GetList(keys::kFileHandlerTypes, &mime_types) ||
+ mime_types->GetSize() == 0) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileHandlerType, handler_id);
+ return false;
+ }
+
+ if (handler_info.HasKey(keys::kFileHandlerTitle) &&
+ !handler_info.GetString(keys::kFileHandlerTitle, &handler.title)) {
+ *error = ASCIIToUTF16(errors::kInvalidFileHandlerTitle);
+ return false;
+ }
+
+ std::string type;
+ for (size_t i = 0; i < mime_types->GetSize(); ++i) {
+ if (!mime_types->GetString(i, &type)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileHandlerTypeElement, handler_id,
+ std::string(base::IntToString(i)));
+ return false;
+ }
+ handler.types.insert(type);
+ }
+
+ file_handlers_.push_back(handler);
+ return true;
+}
+
+bool Extension::LoadFileHandlers(string16* error) {
+ DCHECK(error);
+
+ if (!manifest_->HasKey(keys::kFileHandlers))
+ return true;
+
+ DictionaryValue* all_handlers = NULL;
+ if (!manifest_->GetDictionary(keys::kFileHandlers, &all_handlers)) {
+ *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
+ return false;
+ }
+
+ for (DictionaryValue::key_iterator iter(all_handlers->begin_keys());
+ iter != all_handlers->end_keys(); ++iter) {
+ // A file handler entry is a title and a list of MIME types to handle.
+ DictionaryValue* handler = NULL;
+ if (all_handlers->GetDictionaryWithoutPathExpansion(*iter, &handler)) {
+ if (!LoadFileHandler(*iter, *handler, error))
+ return false;
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Extension::LoadExtensionFeatures(APIPermissionSet* api_permissions,
+ string16* error) {
+ if (manifest_->HasKey(keys::kConvertedFromUserScript))
+ manifest_->GetBoolean(keys::kConvertedFromUserScript,
+ &converted_from_user_script_);
+
+ if (!LoadDevToolsPage(error) ||
+ !LoadInputComponents(*api_permissions, error) ||
+ !LoadContentScripts(error) ||
+ !LoadPageAction(error) ||
+ !LoadBrowserAction(error) ||
+ !LoadSystemIndicator(api_permissions, error) ||
+ !LoadScriptBadge(error) ||
+ !LoadFileBrowserHandlers(error) ||
+ !LoadChromeURLOverrides(error) ||
+ !LoadOmnibox(error) ||
+ !LoadTextToSpeechVoices(error) ||
+ !LoadIncognitoMode(error) ||
+ !LoadFileHandlers(error) ||
+ !LoadContentSecurityPolicy(error))
+ return false;
+
+ return true;
+}
+
+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;
+ }
+ devtools_url_ = GetResourceURL(devtools_str);
+ return true;
+}
+
+bool Extension::LoadInputComponents(const APIPermissionSet& 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;
+ }
+
+ 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;
+ }
+
+ // Get input_components[i].name.
+ if (!module_value->GetString(keys::kName, &name_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentName, base::IntToString(i));
+ return false;
+ }
+
+ // 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 {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentType, base::IntToString(i));
+ return false;
+ }
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentType, base::IntToString(i));
+ return false;
+ }
+
+ // Get input_components[i].id.
+ if (!module_value->GetString(keys::kId, &id_str)) {
+ id_str = "";
+ }
+
+ // Get input_components[i].description.
+ if (!module_value->GetString(keys::kDescription, &description_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentDescription, base::IntToString(i));
+ return false;
+ }
+ // Get input_components[i].language.
+ if (!module_value->GetString(keys::kLanguage, &language_str)) {
+ language_str = "";
+ }
+
+ // Get input_components[i].layouts.
+ ListValue* layouts_value = NULL;
+ if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
+ 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 = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentLayoutName, base::IntToString(i),
+ base::IntToString(j));
+ return false;
+ }
+ layouts.insert(layout_name_str);
+ }
+
+ if (module_value->HasKey(keys::kShortcutKey)) {
+ DictionaryValue* shortcut_value = NULL;
+ if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
+ return false;
+ }
+
+ // Get input_components[i].shortcut_keycode.
+ if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidInputComponentShortcutKeycode,
+ base::IntToString(i));
+ return false;
+ }
+
+ // Get input_components[i].shortcut_alt.
+ if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
+ shortcut_alt = false;
+ }
+
+ // Get input_components[i].shortcut_ctrl.
+ if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
+ shortcut_ctrl = false;
+ }
+
+ // Get input_components[i].shortcut_shift.
+ if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
+ shortcut_shift = 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;
+ }
+
+ return true;
+}
+
+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;
+ }
+
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* content_script = NULL;
+ if (!list_value->GetDictionary(i, &content_script)) {
+ *error = ErrorUtils::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;
+
+ if (manifest_->HasKey(keys::kPageActions)) {
+ ListValue* list_value = NULL;
+ if (!manifest_->GetList(keys::kPageActions, &list_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
+ 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);
+ return false;
+ }
+ } 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_info_ = LoadExtensionActionInfoHelper(
+ page_action_value, Extension::ActionInfo::TYPE_PAGE, error);
+ if (!page_action_info_.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;
+ }
+
+ browser_action_info_ = LoadExtensionActionInfoHelper(
+ browser_action_value, Extension::ActionInfo::TYPE_BROWSER, error);
+ if (!browser_action_info_.get())
+ return false; // Failed to parse browser action definition.
+ return true;
+}
+
+bool Extension::LoadScriptBadge(string16* error) {
+ if (manifest_->HasKey(keys::kScriptBadge)) {
+ if (!FeatureSwitch::script_badges()->IsEnabled()) {
+ // So as to not confuse developers if they specify a script badge section
+ // in the manifest, show a warning if the script badge declaration isn't
+ // going to have any effect.
+ install_warnings_.push_back(
+ InstallWarning(InstallWarning::FORMAT_TEXT,
+ errors::kScriptBadgeRequiresFlag));
+ }
+
+ DictionaryValue* script_badge_value = NULL;
+ if (!manifest_->GetDictionary(keys::kScriptBadge, &script_badge_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidScriptBadge);
+ return false;
+ }
+
+ script_badge_info_ = LoadExtensionActionInfoHelper(
+ script_badge_value, Extension::ActionInfo::TYPE_SCRIPT_BADGE, error);
+ if (!script_badge_info_.get())
+ return false; // Failed to parse script badge definition.
+ } else {
+ script_badge_info_.reset(new ActionInfo());
+ }
+
+ // Script badges always use their extension's title and icon so users can rely
+ // on the visual appearance to know which extension is running. This isn't
+ // bulletproof since an malicious extension could use a different 16x16 icon
+ // that matches the icon of a trusted extension, and users wouldn't be warned
+ // during installation.
+
+ if (!script_badge_info_->default_title.empty()) {
+ install_warnings_.push_back(
+ InstallWarning(InstallWarning::FORMAT_TEXT,
+ errors::kScriptBadgeTitleIgnored));
+ }
+ script_badge_info_->default_title = name();
+
+ if (!script_badge_info_->default_icon.empty()) {
+ install_warnings_.push_back(
+ InstallWarning(InstallWarning::FORMAT_TEXT,
+ errors::kScriptBadgeIconIgnored));
+ }
+
+ script_badge_info_->default_icon.Clear();
+ for (size_t i = 0; i < extension_misc::kNumScriptBadgeIconSizes; i++) {
+ std::string path = icons().Get(extension_misc::kScriptBadgeIconSizes[i],
+ ExtensionIconSet::MATCH_BIGGER);
+ if (!path.empty())
+ script_badge_info_->default_icon.Add(
+ extension_misc::kScriptBadgeIconSizes[i], path);
+ }
+
+ return true;
+}
+
+bool Extension::LoadSystemIndicator(APIPermissionSet* api_permissions,
+ string16* error) {
+ if (!manifest_->HasKey(keys::kSystemIndicator)) {
+ // There was no manifest entry for the system indicator.
+ return true;
}
- // 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;
+ DictionaryValue* system_indicator_value = NULL;
+ if (!manifest_->GetDictionary(keys::kSystemIndicator,
+ &system_indicator_value)) {
+ *error = ASCIIToUTF16(errors::kInvalidSystemIndicator);
+ 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;
+ system_indicator_info_ = LoadExtensionActionInfoHelper(
+ system_indicator_value,
+ Extension::ActionInfo::TYPE_SYSTEM_INDICATOR,
+ error);
+
+ if (!system_indicator_info_.get()) {
+ return false;
}
- result->swap(decoded);
+ // Because the manifest was successfully parsed, auto-grant the permission.
+ // TODO(dewittj) Add this for all extension action APIs.
+ api_permissions->insert(APIPermission::kSystemIndicator);
+
+ return true;
}
-// static
-const gfx::ImageSkia& Extension::GetDefaultIcon(bool is_app) {
- int id = is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON;
- return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
+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;
}
-// static
-GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
- return GURL(std::string(extensions::kExtensionScheme) +
- content::kStandardSchemeSeparator + extension_id + "/");
+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();
}
-bool Extension::InitFromValue(int flags, string16* error) {
- DCHECK(error);
+FileBrowserHandler* Extension::LoadFileBrowserHandler(
+ const DictionaryValue* file_browser_handler, string16* error) {
+ scoped_ptr<FileBrowserHandler> result(new FileBrowserHandler());
+ result->set_extension_id(id());
- base::AutoLock auto_lock(runtime_data_lock_);
+ 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);
- // Initialize permissions with an empty, default permission set.
- runtime_data_.SetActivePermissions(new PermissionSet());
- optional_permission_set_ = new PermissionSet();
- required_permission_set_ = new PermissionSet();
+ // 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);
- creation_flags_ = flags;
+ // Initialize access permissions (optional).
+ const ListValue* access_list_value = NULL;
+ if (file_browser_handler->HasKey(keys::kFileAccessList)) {
+ if (!file_browser_handler->GetList(keys::kFileAccessList,
+ &access_list_value) ||
+ access_list_value->empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidFileAccessList);
+ return NULL;
+ }
+ for (size_t i = 0; i < access_list_value->GetSize(); ++i) {
+ std::string access;
+ if (!access_list_value->GetString(i, &access) ||
+ result->AddFileAccessPermission(access)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileAccessValue, base::IntToString(i));
+ return NULL;
+ }
+ }
+ }
+ if (!result->ValidateFileAccessPermissions()) {
+ *error = ASCIIToUTF16(errors::kInvalidFileAccessList);
+ return NULL;
+ }
- // Important to load manifest version first because many other features
- // depend on its value.
- if (!LoadManifestVersion(error))
- return false;
+ // Initialize file filters (mandatory, unless "create" access is specified,
+ // in which case is ignored).
+ if (!result->HasCreateAccessPermission()) {
+ const 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 = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileFilterValue, base::IntToString(i));
+ return NULL;
+ }
+ StringToLowerASCII(&filter);
+ if (!StartsWithASCII(filter,
+ std::string(chrome::kFileSystemScheme) + ':',
+ true)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ // The user inputs filesystem:*; we don't actually implement scheme
+ // wildcards in URLPattern, so transform to what will match correctly.
+ filter.replace(0, 11, "chrome-extension://*/");
+ URLPattern pattern(URLPattern::SCHEME_EXTENSION);
+ if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ std::string path = pattern.path();
+ bool allowed = path == "/*" || path == "/*.*" ||
+ (path.compare(0, 3, "/*.") == 0 &&
+ path.find_first_of('*', 3) == std::string::npos);
+ if (!allowed) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ result->AddPattern(pattern);
+ }
+ }
- // 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;
+ 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 (!LoadRequiredFeatures(error))
- return false;
+ return result.release();
+}
- // We don't need to validate because InitExtensionID already did that.
- manifest_->GetString(keys::kPublicKey, &public_key_);
+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;
+ }
- extension_url_ = Extension::GetBaseURLFromExtensionId(id());
+ // 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.
+ bool is_override = (page != chrome::kChromeUINewTabHost &&
+ page != chrome::kChromeUIBookmarksHost &&
+ page != chrome::kChromeUIHistoryHost);
+#if defined(OS_CHROMEOS)
+ is_override = (is_override &&
+ page != chrome::kChromeUIActivationMessageHost);
+#endif
+#if defined(FILE_MANAGER_EXTENSION)
+ is_override = (is_override &&
+ !(location() == COMPONENT &&
+ page == chrome::kChromeUIFileManagerHost));
+#endif
- // 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;
+ if (is_override || !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);
- APIPermissionSet api_permissions;
- URLPatternSet host_permissions;
- if (!ParsePermissions(keys::kPermissions,
- error,
- &api_permissions,
- &host_permissions)) {
- return false;
+ // For component extensions, add override URL to extent patterns.
+ if (is_legacy_packaged_app() && location() == COMPONENT) {
+ URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
+ std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
+ page.c_str());
+ if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, url);
+ return false;
+ }
+ extent_.AddPattern(pattern);
+ }
}
- // TODO(jeremya/kalman) do this via the features system by exposing the
- // app.window API to platform apps, with no dependency on any permissions.
- // See http://crbug.com/120069.
- if (is_platform_app()) {
- api_permissions.insert(APIPermission::kAppCurrentWindowInternal);
- api_permissions.insert(APIPermission::kAppRuntime);
- api_permissions.insert(APIPermission::kAppWindow);
+ // An extension may override at most one page.
+ if (overrides->size() > 1) {
+ *error = ASCIIToUTF16(errors::kMultipleOverrides);
+ return false;
}
- if (from_webstore()) {
- details_url_ =
- GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id());
- }
+ return true;
+}
- APIPermissionSet optional_api_permissions;
- URLPatternSet optional_host_permissions;
- if (!ParsePermissions(keys::kOptionalPermissions,
- error,
- &optional_api_permissions,
- &optional_host_permissions)) {
+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;
+}
- if (!LoadAppIsolation(api_permissions, error))
+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;
+ }
- if (!LoadSharedFeatures(api_permissions, error))
- return false;
+ if (tts_dict->HasKey(keys::kTtsVoices)) {
+ ListValue* tts_voices = NULL;
+ if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
+ *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
+ return false;
+ }
- if (!LoadExtensionFeatures(&api_permissions, error))
- return false;
+ 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;
+ }
- if (!LoadThemeFeatures(error))
- return false;
+ 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);
+ }
+ }
- if (HasMultipleUISurfaces()) {
- *error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
+ tts_voices_.push_back(voice_data);
+ }
+ }
+ return true;
+}
+
+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;
+}
- runtime_data_.SetActivePermissions(new PermissionSet(
- this, api_permissions, host_permissions));
- required_permission_set_ = new PermissionSet(
- this, api_permissions, host_permissions);
- optional_permission_set_ = new PermissionSet(
- optional_api_permissions, optional_host_permissions, URLPatternSet());
+bool Extension::LoadContentSecurityPolicy(string16* error) {
+ const std::string& key = is_platform_app() ?
+ keys::kPlatformAppContentSecurityPolicy : keys::kContentSecurityPolicy;
+
+ if (manifest_->HasPath(key)) {
+ std::string content_security_policy;
+ if (!manifest_->GetString(key, &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, GetType())) {
+ *error = ASCIIToUTF16(errors::kInsecureContentSecurityPolicy);
+ return false;
+ }
+ 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_ = is_platform_app() ?
+ kDefaultPlatformAppContentSecurityPolicy :
+ kDefaultContentSecurityPolicy;
+ CHECK(ContentSecurityPolicyIsSecure(content_security_policy_, GetType()));
+ }
return true;
}
-GURL Extension::GetHomepageURL() const {
- if (homepage_url_.is_valid())
- return homepage_url_;
+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;
- return UpdatesFromGallery() ?
- GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id()) : GURL();
+ return true;
}
-std::set<FilePath> Extension::GetBrowserImages() const {
- std::set<FilePath> image_paths;
- // TODO(viettrungluu): These |FilePath::FromWStringHack(UTF8ToWide())|
- // indicate that we're doing something wrong.
-
- // Extension icons.
- for (ExtensionIconSet::IconMap::const_iterator iter = icons().map().begin();
- iter != icons().map().end(); ++iter) {
- image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
+bool Extension::LoadThemeImages(const DictionaryValue* theme_value,
+ string16* error) {
+ const 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());
}
+ return true;
+}
- // Theme images.
- DictionaryValue* theme_images = GetThemeImages();
- if (theme_images) {
- for (DictionaryValue::key_iterator it = theme_images->begin_keys();
- it != theme_images->end_keys(); ++it) {
- std::string val;
- if (theme_images->GetStringWithoutPathExpansion(*it, &val))
- image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(val)));
+bool Extension::LoadThemeColors(const DictionaryValue* theme_value,
+ string16* error) {
+ const 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) {
+ const 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());
}
+ return true;
+}
- if (page_action_info() && !page_action_info()->default_icon.empty()) {
- for (ExtensionIconSet::IconMap::const_iterator iter =
- page_action_info()->default_icon.map().begin();
- iter != page_action_info()->default_icon.map().end();
- ++iter) {
- image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
- }
- }
+bool Extension::LoadThemeTints(const DictionaryValue* theme_value,
+ string16* error) {
+ const DictionaryValue* tints_value = NULL;
+ if (!theme_value->GetDictionary(keys::kThemeTints, &tints_value))
+ return true;
- if (browser_action_info() && !browser_action_info()->default_icon.empty()) {
- for (ExtensionIconSet::IconMap::const_iterator iter =
- browser_action_info()->default_icon.map().begin();
- iter != browser_action_info()->default_icon.map().end();
- ++iter) {
- image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
+ // Validate that the tints are all reals.
+ for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
+ iter != tints_value->end_keys(); ++iter) {
+ const 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;
}
}
-
- return image_paths;
-}
-
-GURL Extension::GetFullLaunchURL() const {
- return launch_local_path().empty() ? GURL(launch_web_url()) :
- url().Resolve(launch_local_path());
-}
-
-static std::string SizeToString(const gfx::Size& max_size) {
- return base::IntToString(max_size.width()) + "x" +
- base::IntToString(max_size.height());
+ theme_tints_.reset(tints_value->DeepCopy());
+ return true;
}
-// static
-void Extension::SetScriptingWhitelist(
- const Extension::ScriptingWhitelist& whitelist) {
- ScriptingWhitelist* current_whitelist =
- ExtensionConfig::GetInstance()->whitelist();
- current_whitelist->clear();
- for (ScriptingWhitelist::const_iterator it = whitelist.begin();
- it != whitelist.end(); ++it) {
- current_whitelist->push_back(*it);
+bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value,
+ string16* error) {
+ const DictionaryValue* display_properties_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
+ &display_properties_value)) {
+ theme_display_properties_.reset(
+ display_properties_value->DeepCopy());
}
+ return true;
}
-
-// static
-const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
- return ExtensionConfig::GetInstance()->whitelist();
-}
-
-void Extension::SetCachedImage(const ExtensionResource& source,
- const SkBitmap& image,
- const gfx::Size& original_size) const {
- DCHECK(source.extension_root() == path()); // The resource must come from
- // this extension.
- const FilePath& path = source.relative_path();
- gfx::Size actual_size(image.width(), image.height());
- std::string location;
- if (actual_size != original_size)
- location = SizeToString(actual_size);
- image_cache_[ImageCacheKey(path, location)] = image;
-}
-
-bool Extension::HasCachedImage(const ExtensionResource& source,
- const gfx::Size& max_size) const {
- DCHECK(source.extension_root() == path()); // The resource must come from
- // this extension.
- return GetCachedImageImpl(source, max_size) != NULL;
-}
-
-SkBitmap Extension::GetCachedImage(const ExtensionResource& source,
- const gfx::Size& max_size) const {
- DCHECK(source.extension_root() == path()); // The resource must come from
- // this extension.
- SkBitmap* image = GetCachedImageImpl(source, max_size);
- return image ? *image : SkBitmap();
-}
-
SkBitmap* Extension::GetCachedImageImpl(const ExtensionResource& source,
const gfx::Size& max_size) const {
const FilePath& path = source.relative_path();
@@ -3447,568 +3546,487 @@ SkBitmap* Extension::GetCachedImageImpl(const ExtensionResource& source,
return NULL;
}
-ExtensionResource Extension::GetIconResource(
- int size, ExtensionIconSet::MatchType match_type) const {
- std::string path = icons().Get(size, match_type);
- return path.empty() ? ExtensionResource() : GetResource(path);
-}
-
-GURL Extension::GetIconURL(int size,
- ExtensionIconSet::MatchType match_type) const {
- std::string path = icons().Get(size, match_type);
- return path.empty() ? GURL() : GetResourceURL(path);
-}
-
-bool Extension::ParsePermissions(const char* key,
- string16* error,
- APIPermissionSet* api_permissions,
- URLPatternSet* host_permissions) {
- if (manifest_->HasKey(key)) {
- ListValue* permissions = NULL;
- if (!manifest_->GetList(key, &permissions)) {
+// Helper method that loads a UserScript object from a dictionary in the
+// content_script list of the manifest.
+bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
+ int definition_index,
+ string16* error,
+ UserScript* result) {
+ // run_at
+ if (content_script->HasKey(keys::kRunAt)) {
+ std::string run_location;
+ if (!content_script->GetString(keys::kRunAt, &run_location)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPermissions, "");
- return false;
- }
-
- // NOTE: We need to get the APIPermission before we check if features
- // associated with them are available because the feature system does not
- // know about aliases.
-
- std::vector<std::string> host_data;
- if (!APIPermissionSet::ParseFromJSON(permissions, api_permissions,
- error, &host_data))
+ errors::kInvalidRunAt,
+ base::IntToString(definition_index));
return false;
-
- // Verify feature availability of permissions.
- std::vector<APIPermission::ID> to_remove;
- SimpleFeatureProvider* permission_features =
- SimpleFeatureProvider::GetPermissionFeatures();
- for (APIPermissionSet::const_iterator it = api_permissions->begin();
- it != api_permissions->end(); ++it) {
- extensions::Feature* feature =
- permission_features->GetFeature(it->name());
-
- // The feature should exist since we just got an APIPermission
- // for it. The two systems should be updated together whenever a
- // permission is added.
- CHECK(feature);
-
- Feature::Availability availability =
- feature->IsAvailableToManifest(
- id(),
- GetType(),
- Feature::ConvertLocation(location()),
- manifest_version());
- if (!availability.is_available()) {
- // Don't fail, but warn the developer that the manifest contains
- // unrecognized permissions. This may happen legitimately if the
- // extensions requests platform- or channel-specific permissions.
- install_warnings_.push_back(InstallWarning(InstallWarning::FORMAT_TEXT,
- availability.message()));
- to_remove.push_back(it->id());
- continue;
- }
-
- if (it->id() == APIPermission::kExperimental) {
- if (!CanSpecifyExperimentalPermission()) {
- *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
- return false;
- }
- }
- }
-
- // Remove permissions that are not available to this extension.
- for (std::vector<APIPermission::ID>::const_iterator it = to_remove.begin();
- it != to_remove.end(); ++it) {
- api_permissions->erase(*it);
- }
-
- // Parse host pattern permissions.
- const int kAllowedSchemes = CanExecuteScriptEverywhere() ?
- URLPattern::SCHEME_ALL : kValidHostPermissionSchemes;
-
- for (std::vector<std::string>::const_iterator it = host_data.begin();
- it != host_data.end(); ++it) {
- const std::string& permission_str = *it;
-
- // Check if it's a host pattern permission.
- URLPattern pattern = URLPattern(kAllowedSchemes);
- URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
- if (parse_result == URLPattern::PARSE_SUCCESS) {
- if (!CanSpecifyHostPermission(pattern, *api_permissions)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidPermissionScheme, permission_str);
- return false;
- }
-
- // The path component is not used for host permissions, so we force it
- // to match all paths.
- pattern.SetPath("/*");
-
- if (pattern.MatchesScheme(chrome::kFileScheme) &&
- !CanExecuteScriptEverywhere()) {
- wants_file_access_ = true;
- if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
- pattern.SetValidSchemes(
- pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
- }
- }
-
- host_permissions->AddPattern(pattern);
- continue;
- }
-
- // It's probably an unknown API permission. Do not throw an error so
- // extensions can retain backwards compatability (http://crbug.com/42742).
- install_warnings_.push_back(InstallWarning(
- InstallWarning::FORMAT_TEXT,
- base::StringPrintf(
- "Permission '%s' is unknown or URL pattern is malformed.",
- permission_str.c_str())));
}
- }
- return true;
-}
-
-bool Extension::CanSilentlyIncreasePermissions() const {
- return location() != INTERNAL;
-}
-
-bool Extension::CanSpecifyHostPermission(const URLPattern& pattern,
- const APIPermissionSet& permissions) const {
- if (!pattern.match_all_urls() &&
- pattern.MatchesScheme(chrome::kChromeUIScheme)) {
- // Regular extensions are only allowed access to chrome://favicon.
- if (pattern.host() == chrome::kChromeUIFaviconHost)
- return true;
- // Experimental extensions are also allowed chrome://thumb.
- if (pattern.host() == chrome::kChromeUIThumbnailHost) {
- return permissions.find(APIPermission::kExperimental) !=
- permissions.end();
+ if (run_location == values::kRunAtDocumentStart) {
+ result->set_run_location(UserScript::DOCUMENT_START);
+ } else if (run_location == values::kRunAtDocumentEnd) {
+ result->set_run_location(UserScript::DOCUMENT_END);
+ } else if (run_location == values::kRunAtDocumentIdle) {
+ result->set_run_location(UserScript::DOCUMENT_IDLE);
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidRunAt,
+ base::IntToString(definition_index));
+ return false;
}
+ }
- // Component extensions can have access to all of chrome://*.
- if (CanExecuteScriptEverywhere())
- return true;
+ // all frames
+ if (content_script->HasKey(keys::kAllFrames)) {
+ bool all_frames = false;
+ if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidAllFrames, base::IntToString(definition_index));
+ return false;
+ }
+ result->set_match_all_frames(all_frames);
+ }
+ // matches (required)
+ const ListValue* matches = NULL;
+ if (!content_script->GetList(keys::kMatches, &matches)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidMatches,
+ base::IntToString(definition_index));
return false;
}
- // Otherwise, the valid schemes were handled by URLPattern.
- return true;
-}
-
-bool Extension::HasAPIPermission(APIPermission::ID permission) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->HasAPIPermission(permission);
-}
-
-bool Extension::HasAPIPermission(const std::string& function_name) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->
- HasAccessToFunction(function_name);
-}
-
-bool Extension::HasAPIPermissionForTab(int tab_id,
- APIPermission::ID permission) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- if (runtime_data_.GetActivePermissions()->HasAPIPermission(permission))
- return true;
- scoped_refptr<const PermissionSet> tab_specific_permissions =
- runtime_data_.GetTabSpecificPermissions(tab_id);
- return tab_specific_permissions.get() &&
- tab_specific_permissions->HasAPIPermission(permission);
-}
-
-bool Extension::CheckAPIPermissionWithParam(APIPermission::ID permission,
- const APIPermission::CheckParam* param) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->
- CheckAPIPermissionWithParam(permission, param);
-}
-
-const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->effective_hosts();
-}
-
-bool Extension::HasHostPermission(const GURL& url) const {
- if (url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() != chrome::kChromeUIFaviconHost &&
- url.host() != chrome::kChromeUIThumbnailHost &&
- location() != Extension::COMPONENT) {
+ if (matches->GetSize() == 0) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidMatchCount,
+ base::IntToString(definition_index));
return false;
}
+ for (size_t j = 0; j < matches->GetSize(); ++j) {
+ std::string match_str;
+ if (!matches->GetString(j, &match_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidMatch,
+ base::IntToString(definition_index),
+ base::IntToString(j),
+ errors::kExpectString);
+ return false;
+ }
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->
- HasExplicitAccessToOrigin(url);
-}
+ URLPattern pattern(UserScript::kValidUserScriptSchemes);
+ if (CanExecuteScriptEverywhere())
+ pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
-bool Extension::HasEffectiveAccessToAllHosts() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->HasEffectiveAccessToAllHosts();
-}
+ URLPattern::ParseResult parse_result = pattern.Parse(match_str);
+ if (parse_result != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidMatch,
+ base::IntToString(definition_index),
+ base::IntToString(j),
+ URLPattern::GetParseResultString(parse_result));
+ return false;
+ }
-bool Extension::HasFullPermissions() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions()->HasEffectiveFullAccess();
-}
+ if (pattern.MatchesScheme(chrome::kFileScheme) &&
+ !CanExecuteScriptEverywhere()) {
+ wants_file_access_ = true;
+ if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
+ pattern.SetValidSchemes(
+ pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+ }
+ }
-PermissionMessages Extension::GetPermissionMessages() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- if (IsTrustedId(id())) {
- return PermissionMessages();
- } else {
- return runtime_data_.GetActivePermissions()->GetPermissionMessages(
- GetType());
+ result->add_url_pattern(pattern);
}
-}
-
-std::vector<string16> Extension::GetPermissionMessageStrings() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- if (IsTrustedId(id()))
- return std::vector<string16>();
- else
- return runtime_data_.GetActivePermissions()->GetWarningMessages(GetType());
-}
-bool Extension::ShouldSkipPermissionWarnings() const {
- return IsTrustedId(id());
-}
-
-void Extension::SetActivePermissions(
- const PermissionSet* permissions) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- runtime_data_.SetActivePermissions(permissions);
-}
-
-scoped_refptr<const PermissionSet>
- Extension::GetActivePermissions() const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetActivePermissions();
-}
+ // exclude_matches
+ if (content_script->HasKey(keys::kExcludeMatches)) { // optional
+ const ListValue* exclude_matches = NULL;
+ if (!content_script->GetList(keys::kExcludeMatches, &exclude_matches)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidExcludeMatches,
+ base::IntToString(definition_index));
+ return false;
+ }
-bool Extension::HasMultipleUISurfaces() const {
- int num_surfaces = 0;
+ for (size_t j = 0; j < exclude_matches->GetSize(); ++j) {
+ std::string match_str;
+ if (!exclude_matches->GetString(j, &match_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidExcludeMatch,
+ base::IntToString(definition_index),
+ base::IntToString(j),
+ errors::kExpectString);
+ return false;
+ }
- if (page_action_info())
- ++num_surfaces;
+ URLPattern pattern(UserScript::kValidUserScriptSchemes);
+ if (CanExecuteScriptEverywhere())
+ pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
+ URLPattern::ParseResult parse_result = pattern.Parse(match_str);
+ if (parse_result != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidExcludeMatch,
+ base::IntToString(definition_index), base::IntToString(j),
+ URLPattern::GetParseResultString(parse_result));
+ return false;
+ }
- if (browser_action_info())
- ++num_surfaces;
+ result->add_exclude_url_pattern(pattern);
+ }
+ }
- if (is_app())
- ++num_surfaces;
+ // include/exclude globs (mostly for Greasemonkey compatibility)
+ if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
+ error, &UserScript::add_glob, result)) {
+ return false;
+ }
- return num_surfaces > 1;
-}
+ if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
+ error, &UserScript::add_exclude_glob, result)) {
+ return false;
+ }
-bool Extension::CanExecuteScriptOnPage(const GURL& document_url,
- const GURL& top_frame_url,
- int tab_id,
- const UserScript* script,
- std::string* error) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- // The gallery is special-cased as a restricted URL for scripting to prevent
- // access to special JS bindings we expose to the gallery (and avoid things
- // like extensions removing the "report abuse" link).
- // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
- // against the store app extent?
- GURL store_url(extension_urls::GetWebstoreLaunchURL());
- if ((document_url.host() == store_url.host()) &&
- !CanExecuteScriptEverywhere() &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowScriptingGallery)) {
- if (error)
- *error = errors::kCannotScriptGallery;
+ // js and css keys
+ const ListValue* js = NULL;
+ if (content_script->HasKey(keys::kJs) &&
+ !content_script->GetList(keys::kJs, &js)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidJsList,
+ base::IntToString(definition_index));
return false;
}
- if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
- !CanExecuteScriptEverywhere()) {
+ const ListValue* css = NULL;
+ if (content_script->HasKey(keys::kCss) &&
+ !content_script->GetList(keys::kCss, &css)) {
+ *error = ErrorUtils::
+ FormatErrorMessageUTF16(errors::kInvalidCssList,
+ base::IntToString(definition_index));
return false;
}
- if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
- top_frame_url.GetOrigin() !=
- GetBaseURLFromExtensionId(id()).GetOrigin() &&
- !CanExecuteScriptEverywhere()) {
+ // The manifest needs to have at least one js or css user script definition.
+ if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kMissingFile,
+ base::IntToString(definition_index));
return false;
}
- // If a tab ID is specified, try the tab-specific permissions.
- if (tab_id >= 0) {
- scoped_refptr<const PermissionSet> tab_permissions =
- runtime_data_.GetTabSpecificPermissions(tab_id);
- if (tab_permissions.get() &&
- tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
- return true;
+ if (js) {
+ for (size_t script_index = 0; script_index < js->GetSize();
+ ++script_index) {
+ const Value* value;
+ std::string relative;
+ if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidJs,
+ base::IntToString(definition_index),
+ base::IntToString(script_index));
+ return false;
+ }
+ GURL url = GetResourceURL(relative);
+ ExtensionResource resource = GetResource(relative);
+ result->js_scripts().push_back(UserScript::File(
+ resource.extension_root(), resource.relative_path(), url));
}
}
- // If a script is specified, use its matches.
- if (script)
- return script->MatchesURL(document_url);
-
- // Otherwise, see if this extension has permission to execute script
- // programmatically on pages.
- if (runtime_data_.GetActivePermissions()->HasExplicitAccessToOrigin(
- document_url)) {
- return true;
- }
-
- if (error) {
- *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
- document_url.spec());
+ if (css) {
+ for (size_t script_index = 0; script_index < css->GetSize();
+ ++script_index) {
+ const Value* value;
+ std::string relative;
+ if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidCss,
+ base::IntToString(definition_index),
+ base::IntToString(script_index));
+ return false;
+ }
+ GURL url = GetResourceURL(relative);
+ ExtensionResource resource = GetResource(relative);
+ result->css_scripts().push_back(UserScript::File(
+ resource.extension_root(), resource.relative_path(), url));
+ }
}
- return false;
-}
-
-bool Extension::ShowConfigureContextMenus() const {
- // Don't show context menu for component extensions. We might want to show
- // options for component extension button but now there is no component
- // extension with options. All other menu items like uninstall have
- // no sense for component extensions.
- return location() != Extension::COMPONENT;
+ return true;
}
-bool Extension::CanSpecifyExperimentalPermission() const {
- if (location() == Extension::COMPONENT)
- return true;
+bool Extension::LoadGlobsHelper(
+ const DictionaryValue* content_script,
+ int content_script_index,
+ const char* globs_property_name,
+ string16* error,
+ void(UserScript::*add_method)(const std::string& glob),
+ UserScript* instance) {
+ if (!content_script->HasKey(globs_property_name))
+ return true; // they are optional
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableExperimentalExtensionApis)) {
- return true;
+ const ListValue* list = NULL;
+ if (!content_script->GetList(globs_property_name, &list)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidGlobList,
+ base::IntToString(content_script_index),
+ globs_property_name);
+ return false;
}
- // We rely on the webstore to check access to experimental. This way we can
- // whitelist extensions to have access to experimental in just the store, and
- // not have to push a new version of the client.
- if (from_webstore())
- return true;
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ std::string glob;
+ if (!list->GetString(i, &glob)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidGlob,
+ base::IntToString(content_script_index),
+ globs_property_name,
+ base::IntToString(i));
+ return false;
+ }
- return false;
+ (instance->*add_method)(glob);
+ }
+
+ return true;
}
-bool Extension::CanExecuteScriptEverywhere() const {
- if (location() == Extension::COMPONENT)
- return true;
+scoped_ptr<Extension::ActionInfo> Extension::LoadExtensionActionInfoHelper(
+ const DictionaryValue* extension_action,
+ ActionInfo::Type action_type,
+ string16* error) {
+ scoped_ptr<ActionInfo> result(new ActionInfo());
- ScriptingWhitelist* whitelist = ExtensionConfig::GetInstance()->whitelist();
+ if (manifest_version_ == 1) {
+ // kPageActionIcons is obsolete, and used by very few extensions. Continue
+ // loading it, but only take the first icon as the default_icon path.
+ const ListValue* icons = NULL;
+ if (extension_action->HasKey(keys::kPageActionIcons) &&
+ extension_action->GetList(keys::kPageActionIcons, &icons)) {
+ for (ListValue::const_iterator iter = icons->begin();
+ iter != icons->end(); ++iter) {
+ std::string path;
+ if (!(*iter)->GetAsString(&path) || !NormalizeAndValidatePath(&path)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
+ return scoped_ptr<ActionInfo>();
+ }
- for (ScriptingWhitelist::const_iterator it = whitelist->begin();
- it != whitelist->end(); ++it) {
- if (id() == *it) {
- return true;
+ result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
+ break;
+ }
}
- }
-
- return false;
-}
-bool Extension::CanCaptureVisiblePage(const GURL& page_url,
- int tab_id,
- std::string* error) const {
- if (tab_id >= 0) {
- scoped_refptr<const PermissionSet> tab_permissions =
- GetTabSpecificPermissions(tab_id);
- if (tab_permissions.get() &&
- tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
- return true;
+ std::string id;
+ if (extension_action->HasKey(keys::kPageActionId)) {
+ if (!extension_action->GetString(keys::kPageActionId, &id)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionId);
+ return scoped_ptr<ActionInfo>();
+ }
+ result->id = id;
}
}
- if (HasHostPermission(page_url) || page_url.GetOrigin() == url())
- return true;
-
- if (error) {
- *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
- page_url.spec());
+ // Read the page action |default_icon| (optional).
+ // The |default_icon| value can be either dictionary {icon size -> icon path}
+ // or non empty string value.
+ if (extension_action->HasKey(keys::kPageActionDefaultIcon)) {
+ const DictionaryValue* icons_value = NULL;
+ std::string default_icon;
+ if (extension_action->GetDictionary(keys::kPageActionDefaultIcon,
+ &icons_value)) {
+ if (!LoadIconsFromDictionary(icons_value,
+ extension_misc::kExtensionActionIconSizes,
+ extension_misc::kNumExtensionActionIconSizes,
+ &result->default_icon,
+ error)) {
+ return scoped_ptr<ActionInfo>();
+ }
+ } else if (extension_action->GetString(keys::kPageActionDefaultIcon,
+ &default_icon) &&
+ NormalizeAndValidatePath(&default_icon)) {
+ result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
+ default_icon);
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
+ return scoped_ptr<ActionInfo>();
+ }
}
- return false;
-}
-
-bool Extension::UpdatesFromGallery() const {
- return extension_urls::IsWebstoreUpdateUrl(update_url());
-}
-
-bool Extension::OverlapsWithOrigin(const GURL& origin) const {
- if (url() == origin)
- return true;
- if (web_extent().is_empty())
- return false;
-
- // Note: patterns and extents ignore port numbers.
- URLPattern origin_only_pattern(kValidWebExtentSchemes);
- if (!origin_only_pattern.SetScheme(origin.scheme()))
- return false;
- origin_only_pattern.SetHost(origin.host());
- origin_only_pattern.SetPath("/*");
-
- URLPatternSet origin_only_pattern_list;
- origin_only_pattern_list.AddPattern(origin_only_pattern);
+ // Read the page action title from |default_title| if present, |name| if not
+ // (both optional).
+ if (extension_action->HasKey(keys::kPageActionDefaultTitle)) {
+ if (!extension_action->GetString(keys::kPageActionDefaultTitle,
+ &result->default_title)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
+ return scoped_ptr<ActionInfo>();
+ }
+ } else if (manifest_version_ == 1 && extension_action->HasKey(keys::kName)) {
+ if (!extension_action->GetString(keys::kName, &result->default_title)) {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionName);
+ return scoped_ptr<ActionInfo>();
+ }
+ }
- return web_extent().OverlapsWith(origin_only_pattern_list);
-}
+ // Read the action's |popup| (optional).
+ const char* popup_key = NULL;
+ if (extension_action->HasKey(keys::kPageActionDefaultPopup))
+ popup_key = keys::kPageActionDefaultPopup;
-Extension::SyncType Extension::GetSyncType() const {
- if (!IsSyncable()) {
- // We have a non-standard location.
- return SYNC_TYPE_NONE;
+ if (manifest_version_ == 1 &&
+ extension_action->HasKey(keys::kPageActionPopup)) {
+ if (popup_key) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPageActionOldAndNewKeys,
+ keys::kPageActionDefaultPopup,
+ keys::kPageActionPopup);
+ return scoped_ptr<ActionInfo>();
+ }
+ popup_key = keys::kPageActionPopup;
}
- // Disallow extensions with non-gallery auto-update URLs for now.
- //
- // TODO(akalin): Relax this restriction once we've put in UI to
- // approve synced extensions.
- if (!update_url().is_empty() && !UpdatesFromGallery())
- return SYNC_TYPE_NONE;
+ if (popup_key) {
+ const DictionaryValue* popup = NULL;
+ std::string url_str;
- // Disallow extensions with native code plugins.
- //
- // TODO(akalin): Relax this restriction once we've put in UI to
- // approve synced extensions.
- if (!plugins().empty()) {
- return SYNC_TYPE_NONE;
+ if (extension_action->GetString(popup_key, &url_str)) {
+ // On success, |url_str| is set. Nothing else to do.
+ } else if (manifest_version_ == 1 &&
+ extension_action->GetDictionary(popup_key, &popup)) {
+ if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPageActionPopupPath, "<missing>");
+ return scoped_ptr<ActionInfo>();
+ }
+ } else {
+ *error = ASCIIToUTF16(errors::kInvalidPageActionPopup);
+ return scoped_ptr<ActionInfo>();
+ }
+
+ if (!url_str.empty()) {
+ // An empty string is treated as having no popup.
+ result->default_popup_url = GetResourceURL(url_str);
+ if (!result->default_popup_url.is_valid()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPageActionPopupPath, url_str);
+ return scoped_ptr<ActionInfo>();
+ }
+ } else {
+ DCHECK(result->default_popup_url.is_empty())
+ << "Shouldn't be possible for the popup to be set.";
+ }
}
- switch (GetType()) {
- case Extension::TYPE_EXTENSION:
- return SYNC_TYPE_EXTENSION;
+ return result.Pass();
+}
- case Extension::TYPE_USER_SCRIPT:
- // We only want to sync user scripts with gallery update URLs.
- if (UpdatesFromGallery())
- return SYNC_TYPE_EXTENSION;
- else
- return SYNC_TYPE_NONE;
+bool Extension::LoadOAuth2Info(string16* error) {
+ if (!manifest_->HasKey(keys::kOAuth2))
+ return true;
- case Extension::TYPE_HOSTED_APP:
- case Extension::TYPE_LEGACY_PACKAGED_APP:
- case Extension::TYPE_PLATFORM_APP:
- return SYNC_TYPE_APP;
+ if (!manifest_->GetString(keys::kOAuth2ClientId, &oauth2_info_.client_id) ||
+ oauth2_info_.client_id.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidOAuth2ClientId);
+ return false;
+ }
- default:
- return SYNC_TYPE_NONE;
+ ListValue* list = NULL;
+ if (!manifest_->GetList(keys::kOAuth2Scopes, &list)) {
+ *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
+ return false;
}
-}
-bool Extension::IsSyncable() const {
- // TODO(akalin): Figure out if we need to allow some other types.
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ std::string scope;
+ if (!list->GetString(i, &scope)) {
+ *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
+ return false;
+ }
+ oauth2_info_.scopes.push_back(scope);
+ }
- // Default apps are not synced because otherwise they will pollute profiles
- // that don't already have them. Specially, if a user doesn't have default
- // apps, creates a new profile (which get default apps) and then enables sync
- // for it, then their profile everywhere gets the default apps.
- bool is_syncable = (location() == Extension::INTERNAL &&
- !was_installed_by_default());
- // Sync the chrome web store to maintain its position on the new tab page.
- is_syncable |= (id() == extension_misc::kWebStoreAppId);
- return is_syncable;
+ return true;
}
-bool Extension::RequiresSortOrdinal() const {
- return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
-}
+bool Extension::HasMultipleUISurfaces() const {
+ int num_surfaces = 0;
-bool Extension::ShouldDisplayInAppLauncher() const {
- // Only apps should be displayed in the launcher.
- return is_app() && display_in_launcher_;
-}
+ if (page_action_info())
+ ++num_surfaces;
-bool Extension::ShouldDisplayInNewTabPage() const {
- // Only apps should be displayed on the NTP.
- return is_app() && display_in_new_tab_page_;
-}
+ if (browser_action_info())
+ ++num_surfaces;
-bool Extension::InstallWarning::operator==(const InstallWarning& other) const {
- return format == other.format && message == other.message;
-}
+ if (is_app())
+ ++num_surfaces;
-void PrintTo(const Extension::InstallWarning& warning, ::std::ostream* os) {
- *os << "InstallWarning(";
- switch (warning.format) {
- case Extension::InstallWarning::FORMAT_TEXT:
- *os << "FORMAT_TEXT, \"";
- break;
- case Extension::InstallWarning::FORMAT_HTML:
- *os << "FORMAT_HTML, \"";
- break;
- }
- // This is just for test error messages, so no need to escape '"'
- // characters inside the message.
- *os << warning.message << "\")";
+ return num_surfaces > 1;
}
-ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
- const std::string& id,
- const FilePath& path,
- Extension::Location location)
- : extension_id(id),
- extension_path(path),
- extension_location(location) {
- if (manifest)
- extension_manifest.reset(manifest->DeepCopy());
-}
+void Extension::OverrideLaunchUrl(const GURL& override_url) {
+ GURL new_url(override_url);
+ if (!new_url.is_valid()) {
+ DLOG(WARNING) << "Invalid override url given for " << name();
+ } else {
+ if (new_url.has_port()) {
+ DLOG(WARNING) << "Override URL passed for " << name()
+ << " should not contain a port. Removing it.";
-bool Extension::ShouldDisplayInExtensionSettings() const {
- // Don't show for themes since the settings UI isn't really useful for them.
- if (is_theme())
- return false;
+ GURL::Replacements remove_port;
+ remove_port.ClearPort();
+ new_url = new_url.ReplaceComponents(remove_port);
+ }
- // Don't show component extensions because they are only extensions as an
- // implementation detail of Chrome.
- if (location() == Extension::COMPONENT &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowComponentExtensionOptions)) {
- return false;
+ launch_web_url_ = new_url.spec();
+
+ URLPattern pattern(kValidWebExtentSchemes);
+ URLPattern::ParseResult result = pattern.Parse(new_url.spec());
+ DCHECK_EQ(result, URLPattern::PARSE_SUCCESS);
+ pattern.SetPath(pattern.path() + '*');
+ extent_.AddPattern(pattern);
}
+}
- // Always show unpacked extensions and apps.
- if (location() == Extension::LOAD)
+bool Extension::CanSpecifyExperimentalPermission() const {
+ if (location() == Extension::COMPONENT)
return true;
- // Unless they are unpacked, never show hosted apps. Note: We intentionally
- // show packaged apps and platform apps because there are some pieces of
- // functionality that are only available in chrome://extensions/ but which
- // are needed for packaged and platform apps. For example, inspecting
- // background pages. See http://crbug.com/116134.
- if (is_hosted_app())
- return false;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis)) {
+ return true;
+ }
- return true;
-}
+ // We rely on the webstore to check access to experimental. This way we can
+ // whitelist extensions to have access to experimental in just the store, and
+ // not have to push a new version of the client.
+ if (from_webstore())
+ return true;
-bool Extension::HasContentScriptAtURL(const GURL& url) const {
- for (UserScriptList::const_iterator it = content_scripts_.begin();
- it != content_scripts_.end(); ++it) {
- if (it->MatchesURL(url))
- return true;
- }
return false;
}
-scoped_refptr<const PermissionSet> Extension::GetTabSpecificPermissions(
- int tab_id) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- return runtime_data_.GetTabSpecificPermissions(tab_id);
-}
+bool Extension::CanSpecifyHostPermission(const URLPattern& pattern,
+ const APIPermissionSet& permissions) const {
+ if (!pattern.match_all_urls() &&
+ pattern.MatchesScheme(chrome::kChromeUIScheme)) {
+ // Regular extensions are only allowed access to chrome://favicon.
+ if (pattern.host() == chrome::kChromeUIFaviconHost)
+ return true;
-void Extension::UpdateTabSpecificPermissions(
- int tab_id,
- scoped_refptr<const PermissionSet> permissions) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- runtime_data_.UpdateTabSpecificPermissions(tab_id, permissions);
-}
+ // Experimental extensions are also allowed chrome://thumb.
+ if (pattern.host() == chrome::kChromeUIThumbnailHost) {
+ return permissions.find(APIPermission::kExperimental) !=
+ permissions.end();
+ }
-void Extension::ClearTabSpecificPermissions(int tab_id) const {
- base::AutoLock auto_lock(runtime_data_lock_);
- runtime_data_.ClearTabSpecificPermissions(tab_id);
+ // Component extensions can have access to all of chrome://*.
+ if (CanExecuteScriptEverywhere())
+ return true;
+
+ return false;
+ }
+
+ // Otherwise, the valid schemes were handled by URLPattern.
+ return true;
}
bool Extension::CheckMinimumChromeVersion(string16* error) const {
@@ -4076,48 +4094,34 @@ bool Extension::CheckConflictingFeatures(std::string* utf8_error) const {
return true;
}
-ExtensionInfo::~ExtensionInfo() {}
-
-Extension::RuntimeData::RuntimeData() {}
-Extension::RuntimeData::RuntimeData(const PermissionSet* active)
- : active_permissions_(active) {}
-Extension::RuntimeData::~RuntimeData() {}
-
-scoped_refptr<const PermissionSet>
- Extension::RuntimeData::GetActivePermissions() const {
- return active_permissions_;
-}
-
-void Extension::RuntimeData::SetActivePermissions(
- const PermissionSet* active) {
- active_permissions_ = active;
-}
-
-scoped_refptr<const PermissionSet>
- Extension::RuntimeData::GetTabSpecificPermissions(int tab_id) const {
- CHECK_GE(tab_id, 0);
- TabPermissionsMap::const_iterator it = tab_specific_permissions_.find(tab_id);
- return (it != tab_specific_permissions_.end()) ? it->second : NULL;
-}
-
-void Extension::RuntimeData::UpdateTabSpecificPermissions(
- int tab_id,
- scoped_refptr<const PermissionSet> permissions) {
- CHECK_GE(tab_id, 0);
- if (tab_specific_permissions_.count(tab_id)) {
- tab_specific_permissions_[tab_id] = PermissionSet::CreateUnion(
- tab_specific_permissions_[tab_id],
- permissions.get());
- } else {
- tab_specific_permissions_[tab_id] = permissions;
+void PrintTo(const Extension::InstallWarning& warning, ::std::ostream* os) {
+ *os << "InstallWarning(";
+ switch (warning.format) {
+ case Extension::InstallWarning::FORMAT_TEXT:
+ *os << "FORMAT_TEXT, \"";
+ break;
+ case Extension::InstallWarning::FORMAT_HTML:
+ *os << "FORMAT_HTML, \"";
+ break;
}
+ // This is just for test error messages, so no need to escape '"'
+ // characters inside the message.
+ *os << warning.message << "\")";
}
-void Extension::RuntimeData::ClearTabSpecificPermissions(int tab_id) {
- CHECK_GE(tab_id, 0);
- tab_specific_permissions_.erase(tab_id);
+ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
+ const std::string& id,
+ const FilePath& path,
+ Extension::Location location)
+ : extension_id(id),
+ extension_path(path),
+ extension_location(location) {
+ if (manifest)
+ extension_manifest.reset(manifest->DeepCopy());
}
+ExtensionInfo::~ExtensionInfo() {}
+
UnloadedExtensionInfo::UnloadedExtensionInfo(
const Extension* extension,
extension_misc::UnloadedExtensionReason reason)
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698