123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- // Copyright (c) 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "extensions/common/extension.h"
- #include <stddef.h>
- #include <algorithm>
- #include <iterator>
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/base64.h"
- #include "base/command_line.h"
- #include "base/files/file_path.h"
- #include "base/i18n/rtl.h"
- #include "base/json/json_writer.h"
- #include "base/memory/singleton.h"
- #include "base/strings/strcat.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/timer/elapsed_timer.h"
- #include "base/values.h"
- #include "base/version.h"
- #include "components/crx_file/id_util.h"
- #include "content/public/common/url_constants.h"
- #include "extensions/common/constants.h"
- #include "extensions/common/error_utils.h"
- #include "extensions/common/manifest.h"
- #include "extensions/common/manifest_constants.h"
- #include "extensions/common/manifest_handler.h"
- #include "extensions/common/manifest_handlers/incognito_info.h"
- #include "extensions/common/manifest_handlers/permissions_parser.h"
- #include "extensions/common/permissions/permission_set.h"
- #include "extensions/common/permissions/permissions_data.h"
- #include "extensions/common/permissions/permissions_info.h"
- #include "extensions/common/switches.h"
- #include "extensions/common/url_pattern.h"
- #include "net/base/filename_util.h"
- #include "url/url_util.h"
- using extensions::mojom::ManifestLocation;
- namespace extensions {
- namespace keys = manifest_keys;
- namespace values = manifest_values;
- namespace errors = manifest_errors;
- namespace {
- constexpr int kMinimumSupportedManifestVersion = 2;
- constexpr int kMaximumSupportedManifestVersion = 3;
- constexpr int kPEMOutputColumns = 64;
- static_assert(kMaximumSupportedManifestVersion >=
- kMinimumSupportedManifestVersion,
- "The modern manifest version must be supported.");
- bool g_silence_deprecated_manifest_version_warnings = false;
- // KEY MARKERS
- constexpr char kKeyBeginHeaderMarker[] = "-----BEGIN";
- constexpr char kKeyBeginFooterMarker[] = "-----END";
- constexpr char kKeyInfoEndMarker[] = "KEY-----";
- constexpr char kPublic[] = "PUBLIC";
- constexpr char kPrivate[] = "PRIVATE";
- bool ContainsReservedCharacters(const base::FilePath& path) {
- // We should disallow backslash '\\' as file path separator even on Windows,
- // because the backslash is not regarded as file path separator on Linux/Mac.
- // Extensions are cross-platform.
- // Since FilePath uses backslash '\\' as file path separator on Windows, so we
- // need to check manually.
- if (path.value().find('\\') != path.value().npos)
- return true;
- return !net::IsSafePortableRelativePath(path);
- }
- // Returns true if the given |manifest_version| is supported for the specified
- // |type| of extension. Optionally populates |warning| if an InstallWarning
- // should be added.
- bool IsManifestSupported(int manifest_version,
- Manifest::Type type,
- ManifestLocation location,
- int creation_flags,
- std::string* warning) {
- // Supported versions are always safe.
- if (manifest_version >= kMinimumSupportedManifestVersion &&
- manifest_version <= kMaximumSupportedManifestVersion) {
- // Emit a warning for unpacked extensions on Manifest V2 warning that
- // MV2 is deprecated.
- if (type == Manifest::TYPE_EXTENSION && manifest_version == 2 &&
- Manifest::IsUnpackedLocation(location) &&
- !g_silence_deprecated_manifest_version_warnings) {
- *warning = errors::kManifestV2IsDeprecatedWarning;
- }
- return true;
- }
- if (manifest_version > kMaximumSupportedManifestVersion) {
- // Silence future manifest error with flag.
- bool allow_future_manifest_version =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowFutureManifestVersion);
- if (!allow_future_manifest_version) {
- *warning = ErrorUtils::FormatErrorMessage(
- manifest_errors::kManifestVersionTooHighWarning,
- base::NumberToString(kMaximumSupportedManifestVersion),
- base::NumberToString(manifest_version));
- }
- return true;
- }
- // Allow an exception for extensions if a special commandline flag is present.
- // Note: This allows the extension to load, but it may effectively be treated
- // as a higher manifest version. For instance, all extension v1-specific
- // handling has been removed, which means they will effectively be treated as
- // v2s.
- bool allow_legacy_extensions =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowLegacyExtensionManifests);
- if (type == Manifest::TYPE_EXTENSION && allow_legacy_extensions)
- return true;
- if ((creation_flags & Extension::REQUIRE_MODERN_MANIFEST_VERSION) != 0)
- return false;
- static constexpr int kMinimumExtensionManifestVersion = 2;
- if (type == Manifest::TYPE_EXTENSION)
- return manifest_version >= kMinimumExtensionManifestVersion;
- static constexpr int kMinimumPlatformAppManifestVersion = 2;
- if (type == Manifest::TYPE_PLATFORM_APP)
- return manifest_version >= kMinimumPlatformAppManifestVersion;
- return true;
- }
- // Computes the |extension_id| from the given parameters. On success, returns
- // true. On failure, populates |error| and returns false.
- bool ComputeExtensionID(const base::DictionaryValue& manifest,
- const base::FilePath& path,
- int creation_flags,
- std::u16string* error,
- ExtensionId* extension_id) {
- if (const base::Value* public_key = manifest.FindKey(keys::kPublicKey)) {
- std::string public_key_bytes;
- if (!public_key->is_string() ||
- !Extension::ParsePEMKeyBytes(public_key->GetString(),
- &public_key_bytes)) {
- *error = errors::kInvalidKey;
- return false;
- }
- *extension_id = crx_file::id_util::GenerateId(public_key_bytes);
- return true;
- }
- if (creation_flags & Extension::REQUIRE_KEY) {
- *error = errors::kInvalidKey;
- return false;
- }
- // 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.
- *extension_id = crx_file::id_util::GenerateIdForPath(path);
- if (extension_id->empty()) {
- NOTREACHED() << "Could not create ID from path.";
- return false;
- }
- return true;
- }
- std::u16string InvalidManifestVersionError(const char* manifest_version_error,
- bool is_platform_app) {
- std::string valid_version;
- if (kMinimumSupportedManifestVersion == kMaximumSupportedManifestVersion) {
- valid_version = base::NumberToString(kMinimumSupportedManifestVersion);
- } else if (kMaximumSupportedManifestVersion -
- kMinimumSupportedManifestVersion ==
- 1) {
- valid_version = base::StrCat(
- {"either ", base::NumberToString(kMinimumSupportedManifestVersion),
- " or ", base::NumberToString(kMaximumSupportedManifestVersion)});
- } else {
- valid_version = base::StrCat(
- {"between ", base::NumberToString(kMinimumSupportedManifestVersion),
- " and ", base::NumberToString(kMaximumSupportedManifestVersion)});
- }
- return ErrorUtils::FormatErrorMessageUTF16(
- manifest_version_error, valid_version,
- is_platform_app ? "apps" : "extensions");
- }
- } // namespace
- const int Extension::kInitFromValueFlagBits = 15;
- const char Extension::kMimeType[] = "application/x-chrome-extension";
- const int Extension::kValidWebExtentSchemes =
- URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
- const int Extension::kValidHostPermissionSchemes =
- URLPattern::SCHEME_CHROMEUI | URLPattern::SCHEME_HTTP |
- URLPattern::SCHEME_HTTPS | URLPattern::SCHEME_FILE |
- URLPattern::SCHEME_FTP | URLPattern::SCHEME_WS | URLPattern::SCHEME_WSS |
- URLPattern::SCHEME_UUID_IN_PACKAGE;
- //
- // Extension
- //
- // static
- void Extension::set_silence_deprecated_manifest_version_warnings_for_testing(
- bool silence) {
- g_silence_deprecated_manifest_version_warnings = silence;
- }
- // static
- scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
- ManifestLocation location,
- const base::DictionaryValue& value,
- int flags,
- std::string* utf8_error) {
- return Extension::Create(path,
- location,
- value,
- flags,
- std::string(), // ID is ignored if empty.
- utf8_error);
- }
- // TODO(sungguk): Continue removing std::string errors and replacing
- // with std::u16string. See http://crbug.com/71980.
- scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
- ManifestLocation location,
- const base::DictionaryValue& value,
- int flags,
- const std::string& explicit_id,
- std::string* utf8_error) {
- base::ElapsedTimer timer;
- DCHECK(utf8_error);
- std::u16string error;
- ExtensionId extension_id;
- if (!explicit_id.empty()) {
- extension_id = explicit_id;
- } else if (!ComputeExtensionID(value, path, flags, &error, &extension_id)) {
- *utf8_error = base::UTF16ToUTF8(error);
- return nullptr;
- }
- if ((flags & FROM_BOOKMARK) != 0) {
- // Extension-based bookmark apps are no longer supported.
- // They have been replaced by web apps.
- return nullptr;
- }
- std::unique_ptr<extensions::Manifest> manifest;
- if (flags & FOR_LOGIN_SCREEN) {
- manifest = Manifest::CreateManifestForLoginScreen(
- location, value.CreateDeepCopy(), std::move(extension_id));
- } else {
- manifest = std::make_unique<Manifest>(location, value.CreateDeepCopy(),
- std::move(extension_id));
- }
- std::vector<InstallWarning> install_warnings;
- if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
- return nullptr;
- }
- scoped_refptr<Extension> extension = new Extension(path, std::move(manifest));
- extension->install_warnings_.swap(install_warnings);
- if (!extension->InitFromValue(flags, &error)) {
- *utf8_error = base::UTF16ToUTF8(error);
- return nullptr;
- }
- extension->guid_ = base::GUID::GenerateRandomV4();
- extension->dynamic_url_ = Extension::GetBaseURLFromExtensionId(
- extension->guid_.AsLowercaseString());
- return extension;
- }
- Manifest::Type Extension::GetType() const {
- return converted_from_user_script() ?
- Manifest::TYPE_USER_SCRIPT : manifest_->type();
- }
- // static
- GURL Extension::GetResourceURL(const GURL& extension_url,
- const std::string& relative_path) {
- DCHECK(extension_url.SchemeIs(kExtensionScheme));
- return extension_url.Resolve(relative_path);
- }
- bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
- const std::string& resource) const {
- return pattern_set.MatchesURL(extension_url_.Resolve(resource));
- }
- ExtensionResource Extension::GetResource(
- base::StringPiece relative_path) const {
- // We have some legacy data where resources have leading slashes.
- // See: http://crbug.com/121164
- if (!relative_path.empty() && relative_path[0] == '/')
- relative_path.remove_prefix(1);
- base::FilePath relative_file_path =
- base::FilePath::FromUTF8Unsafe(relative_path);
- if (ContainsReservedCharacters(relative_file_path))
- return ExtensionResource();
- ExtensionResource r(id(), path(), relative_file_path);
- if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
- r.set_follow_symlinks_anywhere();
- }
- return r;
- }
- ExtensionResource Extension::GetResource(
- const base::FilePath& relative_file_path) const {
- if (ContainsReservedCharacters(relative_file_path))
- return ExtensionResource();
- ExtensionResource r(id(), path(), relative_file_path);
- if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
- r.set_follow_symlinks_anywhere();
- }
- return r;
- }
- // 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 (input.length() == 0)
- return false;
- std::string working = input;
- if (base::StartsWith(working, kKeyBeginHeaderMarker,
- base::CompareCase::SENSITIVE)) {
- working = base::CollapseWhitespaceASCII(working, true);
- size_t header_pos = working.find(kKeyInfoEndMarker,
- sizeof(kKeyBeginHeaderMarker) - 1);
- if (header_pos == std::string::npos)
- return false;
- size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
- size_t end_pos = working.rfind(kKeyBeginFooterMarker);
- if (end_pos == std::string::npos)
- return false;
- if (start_pos >= end_pos)
- return false;
- working = working.substr(start_pos, end_pos - start_pos);
- if (working.length() == 0)
- return false;
- }
- return base::Base64Decode(working, output);
- }
- // static
- bool Extension::ProducePEM(const std::string& input, std::string* output) {
- DCHECK(output);
- if (input.empty())
- return false;
- base::Base64Encode(input, output);
- return true;
- }
- // 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");
- return true;
- }
- // static
- GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
- return GURL(base::StrCat({extensions::kExtensionScheme,
- url::kStandardSchemeSeparator, extension_id}));
- }
- // static
- url::Origin Extension::CreateOriginFromExtensionId(
- const ExtensionId& extension_id) {
- // TODO(lukasza): Avoid url::Origin::Create calls in general. Sadly the call
- // below cannot be replaced with CreateFromNormalizedTuple, because it DCHECKs
- // that the `extension_id` is not a properly canonicalized hostname.
- return url::Origin::Create(GetBaseURLFromExtensionId(extension_id));
- }
- 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);
- return web_extent().OverlapsWith(origin_only_pattern_list);
- }
- bool Extension::RequiresSortOrdinal() const {
- return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
- }
- bool Extension::ShouldDisplayInAppLauncher() const {
- // Only apps should be displayed in the launcher.
- return is_app() && display_in_launcher_;
- }
- bool Extension::ShouldDisplayInNewTabPage() const {
- // Only apps should be displayed on the NTP.
- return is_app() && display_in_new_tab_page_;
- }
- bool Extension::ShouldExposeViaManagementAPI() const {
- // Hide component extensions because they are only extensions as an
- // implementation detail of Chrome.
- return !extensions::Manifest::IsComponentLocation(location());
- }
- Extension::ManifestData* Extension::GetManifestData(const std::string& key)
- const {
- DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
- auto iter = manifest_data_.find(key);
- if (iter != manifest_data_.end())
- return iter->second.get();
- return nullptr;
- }
- void Extension::SetManifestData(const std::string& key,
- std::unique_ptr<Extension::ManifestData> data) {
- DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
- manifest_data_[key] = std::move(data);
- }
- void Extension::SetGUID(const ExtensionGuid& guid) {
- guid_ = base::GUID::ParseLowercase(guid);
- DCHECK(guid_.is_valid());
- dynamic_url_ =
- Extension::GetBaseURLFromExtensionId(guid_.AsLowercaseString());
- }
- const ExtensionGuid& Extension::guid() const {
- DCHECK(guid_.is_valid());
- return guid_.AsLowercaseString();
- }
- ManifestLocation Extension::location() const {
- return manifest_->location();
- }
- const std::string& Extension::id() const {
- return manifest_->extension_id();
- }
- const HashedExtensionId& Extension::hashed_id() const {
- return manifest_->hashed_id();
- }
- std::string Extension::VersionString() const {
- return version_.GetString();
- }
- std::string Extension::DifferentialFingerprint() const {
- // We currently support two sources of differential fingerprints:
- // server-provided and synthesized. Fingerprints are of the format V.FP, where
- // V indicates the fingerprint type (1 for SHA256 hash, 2 for app version) and
- // FP indicates the value. The hash-based FP from the server is more precise
- // (a hash of the extension CRX), so use that when available, otherwise
- // synthesize a 2.VERSION fingerprint for use. For more information, see
- // https://github.com/google/omaha/blob/master/doc/ServerProtocolV3.md#packages--fingerprints
- if (const std::string* fingerprint =
- manifest_->FindStringPath(keys::kDifferentialFingerprint))
- return *fingerprint;
- return "2." + VersionString();
- }
- std::string Extension::GetVersionForDisplay() const {
- if (version_name_.size() > 0)
- return version_name_;
- return VersionString();
- }
- void Extension::AddInstallWarning(InstallWarning new_warning) {
- install_warnings_.push_back(std::move(new_warning));
- }
- void Extension::AddInstallWarnings(std::vector<InstallWarning> new_warnings) {
- install_warnings_.insert(install_warnings_.end(),
- std::make_move_iterator(new_warnings.begin()),
- std::make_move_iterator(new_warnings.end()));
- }
- bool Extension::is_app() const {
- return manifest()->is_app();
- }
- 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_extension() const {
- return manifest()->is_extension();
- }
- bool Extension::is_shared_module() const {
- return manifest()->is_shared_module();
- }
- bool Extension::is_theme() const {
- return manifest()->is_theme();
- }
- bool Extension::is_login_screen_extension() const {
- return manifest()->is_login_screen_extension();
- }
- bool Extension::is_chromeos_system_extension() const {
- return manifest()->is_chromeos_system_extension();
- }
- void Extension::AddWebExtentPattern(const URLPattern& pattern) {
- extent_.AddPattern(pattern);
- }
- Extension::Extension(const base::FilePath& path,
- std::unique_ptr<extensions::Manifest> manifest)
- : manifest_version_(0),
- converted_from_user_script_(false),
- manifest_(manifest.release()),
- finished_parsing_manifest_(false),
- display_in_launcher_(true),
- display_in_new_tab_page_(true),
- wants_file_access_(false),
- creation_flags_(0) {
- DCHECK(path.empty() || path.IsAbsolute());
- path_ = crx_file::id_util::MaybeNormalizePath(path);
- }
- Extension::~Extension() {
- }
- bool Extension::InitFromValue(int flags, std::u16string* error) {
- DCHECK(error);
- creation_flags_ = flags;
- // Check for |converted_from_user_script| first, since it affects the type
- // returned by GetType(). This is needed to determine if the manifest version
- // is valid.
- converted_from_user_script_ =
- manifest_->FindBoolPath(keys::kConvertedFromUserScript).value_or(false);
- // Important to load manifest version first because many other features
- // depend on its value.
- if (!LoadManifestVersion(error))
- return false;
- if (!LoadRequiredFeatures(error))
- return false;
- if (const std::string* temp = manifest()->FindStringPath(keys::kPublicKey)) {
- // We don't need to validate because ComputeExtensionId() already did that.
- public_key_ = *temp;
- }
- extension_origin_ = Extension::CreateOriginFromExtensionId(id());
- extension_url_ = Extension::GetBaseURLFromExtensionId(id());
- // 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;
- permissions_parser_ = std::make_unique<PermissionsParser>();
- if (!permissions_parser_->Parse(this, error))
- return false;
- if (!LoadSharedFeatures(error))
- return false;
- permissions_parser_->Finalize(this);
- permissions_parser_.reset();
- finished_parsing_manifest_ = true;
- permissions_data_ = std::make_unique<PermissionsData>(
- id(), GetType(), location(),
- PermissionsParser::GetRequiredPermissions(this).Clone());
- return true;
- }
- bool Extension::LoadRequiredFeatures(std::u16string* error) {
- if (!LoadName(error) ||
- !LoadVersion(error))
- return false;
- return true;
- }
- bool Extension::LoadName(std::u16string* error) {
- const std::string* non_localized_name_ptr =
- manifest_->FindStringPath(keys::kName);
- if (non_localized_name_ptr == nullptr) {
- *error = errors::kInvalidName16;
- return false;
- }
- non_localized_name_ = *non_localized_name_ptr;
- std::u16string sanitized_name =
- base::CollapseWhitespace(base::UTF8ToUTF16(non_localized_name_), true);
- base::i18n::SanitizeUserSuppliedString(&sanitized_name);
- display_name_ = base::UTF16ToUTF8(sanitized_name);
- return true;
- }
- bool Extension::LoadVersion(std::u16string* error) {
- const std::string* version_str = manifest_->FindStringPath(keys::kVersion);
- if (version_str == nullptr) {
- *error = errors::kInvalidVersion;
- return false;
- }
- version_ = base::Version(*version_str);
- if (!version_.IsValid() || version_.components().size() > 4) {
- *error = errors::kInvalidVersion;
- return false;
- }
- if (const base::Value* temp = manifest_->FindKey(keys::kVersionName)) {
- if (!temp->is_string()) {
- *error = errors::kInvalidVersionName;
- return false;
- }
- version_name_ = temp->GetString();
- }
- return true;
- }
- bool Extension::LoadAppFeatures(std::u16string* error) {
- if (!LoadExtent(keys::kWebURLs, &extent_,
- errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
- return false;
- }
- if (const base::Value* temp = manifest_->FindKey(keys::kDisplayInLauncher)) {
- if (!temp->is_bool()) {
- *error = errors::kInvalidDisplayInLauncher;
- return false;
- }
- display_in_launcher_ = temp->GetBool();
- }
- if (const base::Value* temp =
- manifest_->FindKey(keys::kDisplayInNewTabPage)) {
- if (!temp->is_bool()) {
- *error = errors::kInvalidDisplayInNewTabPage;
- return false;
- }
- display_in_new_tab_page_ = temp->GetBool();
- } else {
- // Inherit default from display_in_launcher property.
- display_in_new_tab_page_ = display_in_launcher_;
- }
- return true;
- }
- bool Extension::LoadExtent(const char* key,
- URLPatternSet* extent,
- const char* list_error,
- const char* value_error,
- std::u16string* error) {
- const base::Value* temp_pattern_value = manifest_->FindPath(key);
- if (temp_pattern_value == nullptr)
- return true;
- if (!temp_pattern_value->is_list()) {
- *error = base::ASCIIToUTF16(list_error);
- return false;
- }
- const base::Value::List& pattern_list = temp_pattern_value->GetList();
- for (size_t i = 0; i < pattern_list.size(); ++i) {
- std::string pattern_string;
- if (pattern_list[i].is_string()) {
- pattern_string = pattern_list[i].GetString();
- } else {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error, base::NumberToString(i), errors::kExpectString);
- return false;
- }
- URLPattern pattern(kValidWebExtentSchemes);
- URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
- if (parse_result == URLPattern::ParseResult::kEmptyPath) {
- pattern_string += "/";
- parse_result = pattern.Parse(pattern_string);
- }
- if (parse_result != URLPattern::ParseResult::kSuccess) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error, base::NumberToString(i),
- URLPattern::GetParseResultString(parse_result));
- return false;
- }
- // Do not allow authors to claim "<all_urls>".
- if (pattern.match_all_urls()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error, base::NumberToString(i),
- errors::kCannotClaimAllURLsInExtent);
- return false;
- }
- // Do not allow authors to claim "*" for host.
- if (pattern.host().empty()) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- value_error, base::NumberToString(i),
- errors::kCannotClaimAllHostsInExtent);
- return false;
- }
- // 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::NumberToString(i), errors::kNoWildCardsInPaths);
- return false;
- }
- pattern.SetPath(pattern.path() + '*');
- extent->AddPattern(pattern);
- }
- return true;
- }
- bool Extension::LoadSharedFeatures(std::u16string* error) {
- if (!LoadDescription(error) ||
- !ManifestHandler::ParseExtension(this, error) ||
- !LoadShortName(error))
- return false;
- return true;
- }
- bool Extension::LoadDescription(std::u16string* error) {
- if (const base::Value* temp = manifest_->FindKey(keys::kDescription)) {
- if (!temp->is_string()) {
- *error = errors::kInvalidDescription;
- return false;
- }
- description_ = temp->GetString();
- }
- return true;
- }
- bool Extension::LoadManifestVersion(std::u16string* error) {
- // Get the original value out of the dictionary so that we can validate it
- // more strictly.
- bool key_exists = false;
- if (const base::Value* version_value =
- manifest_->available_values().FindKey(keys::kManifestVersion)) {
- if (!version_value->is_int()) {
- *error = InvalidManifestVersionError(
- errors::kInvalidManifestVersionUnsupported, is_platform_app());
- return false;
- }
- key_exists = true;
- }
- manifest_version_ = manifest_->manifest_version();
- std::string warning;
- if (!IsManifestSupported(manifest_version_, GetType(), location(),
- creation_flags_, &warning)) {
- std::string json;
- base::JSONWriter::Write(*manifest_->value(), &json);
- LOG(WARNING) << "Failed to load extension. Manifest JSON: " << json;
- *error = InvalidManifestVersionError(
- key_exists ? errors::kInvalidManifestVersionUnsupported
- : errors::kInvalidManifestVersionMissingKey,
- is_platform_app());
- return false;
- }
- if (!warning.empty())
- AddInstallWarning(InstallWarning(warning, keys::kManifestVersion));
- return true;
- }
- bool Extension::LoadShortName(std::u16string* error) {
- if (const base::Value* temp = manifest_->FindKey(keys::kShortName)) {
- const std::string* localized_short_name_utf8 = temp->GetIfString();
- if (!localized_short_name_utf8 || localized_short_name_utf8->empty()) {
- *error = errors::kInvalidShortName;
- return false;
- }
- std::u16string localized_short_name =
- base::UTF8ToUTF16(*localized_short_name_utf8);
- base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
- short_name_ = base::UTF16ToUTF8(localized_short_name);
- } else {
- short_name_ = display_name_;
- }
- return true;
- }
- ExtensionInfo::ExtensionInfo(const base::DictionaryValue* manifest,
- const std::string& id,
- const base::FilePath& path,
- ManifestLocation location)
- : extension_id(id), extension_path(path), extension_location(location) {
- if (manifest)
- extension_manifest = manifest->CreateDeepCopy();
- }
- ExtensionInfo::~ExtensionInfo() {}
- } // namespace extensions
|