| // Copyright 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. |
| |
| #ifndef EXTENSIONS_COMMON_MANIFEST_H_ |
| #define EXTENSIONS_COMMON_MANIFEST_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "extensions/common/extension_id.h" |
| #include "extensions/common/hashed_extension_id.h" |
| #include "extensions/common/mojom/manifest.mojom-shared.h" |
| |
| namespace base { |
| class DictionaryValue; |
| class Value; |
| } // namespace base |
| |
| namespace extensions { |
| struct InstallWarning; |
| |
| // Wraps the DictionaryValue form of extension's manifest. Enforces access to |
| // properties of the manifest using ManifestFeatureProvider. |
| class Manifest final { |
| public: |
| // Do not change the order of entries or remove entries in this list as this |
| // is used in ExtensionType enum in tools/metrics/histograms/enums.xml. |
| enum Type { |
| TYPE_UNKNOWN = 0, |
| TYPE_EXTENSION = 1, |
| TYPE_THEME = 2, |
| TYPE_USER_SCRIPT = 3, |
| TYPE_HOSTED_APP = 4, |
| // This is marked legacy because platform apps are preferred. For |
| // backwards compatibility, we can't remove support for packaged apps |
| TYPE_LEGACY_PACKAGED_APP = 5, |
| TYPE_PLATFORM_APP = 6, |
| TYPE_SHARED_MODULE = 7, |
| TYPE_LOGIN_SCREEN_EXTENSION = 8, |
| TYPE_CHROMEOS_SYSTEM_EXTENSION = 9, |
| |
| // New enum values must go above here. |
| NUM_LOAD_TYPES |
| }; |
| |
| // Given two install sources, return the one which should take priority |
| // over the other. If an extension is installed from two sources A and B, |
| // its install source should be set to GetHigherPriorityLocation(A, B). |
| static mojom::ManifestLocation GetHigherPriorityLocation( |
| mojom::ManifestLocation loc1, |
| mojom::ManifestLocation loc2); |
| |
| // Whether the |location| is external or not. |
| static inline bool IsExternalLocation(mojom::ManifestLocation location) { |
| return location == mojom::ManifestLocation::kExternalPref || |
| location == mojom::ManifestLocation::kExternalRegistry || |
| location == mojom::ManifestLocation::kExternalPrefDownload || |
| location == mojom::ManifestLocation::kExternalPolicy || |
| location == mojom::ManifestLocation::kExternalPolicyDownload || |
| location == mojom::ManifestLocation::kExternalComponent; |
| } |
| |
| // Whether the |location| is unpacked (no CRX) or not. |
| static inline bool IsUnpackedLocation(mojom::ManifestLocation location) { |
| return location == mojom::ManifestLocation::kUnpacked || |
| location == mojom::ManifestLocation::kCommandLine; |
| } |
| |
| // Whether extensions with |location| are auto-updatable or not. |
| static inline bool IsAutoUpdateableLocation( |
| mojom::ManifestLocation location) { |
| // Only internal and external extensions can be autoupdated. |
| return location == mojom::ManifestLocation::kInternal || |
| IsExternalLocation(location); |
| } |
| |
| // Whether the |location| is a source of extensions force-installed through |
| // policy. |
| static inline bool IsPolicyLocation(mojom::ManifestLocation location) { |
| return location == mojom::ManifestLocation::kExternalPolicy || |
| location == mojom::ManifestLocation::kExternalPolicyDownload; |
| } |
| |
| // Whether the |location| is an extension intended to be an internal part of |
| // Chrome. |
| static inline bool IsComponentLocation(mojom::ManifestLocation location) { |
| return location == mojom::ManifestLocation::kComponent || |
| location == mojom::ManifestLocation::kExternalComponent; |
| } |
| |
| static inline bool IsValidLocation(mojom::ManifestLocation location) { |
| return location > mojom::ManifestLocation::kInvalidLocation && |
| location <= mojom::ManifestLocation::kMaxValue; |
| } |
| |
| // Unpacked extensions start off with file access since they are a developer |
| // feature. |
| static inline bool ShouldAlwaysAllowFileAccess( |
| mojom::ManifestLocation location) { |
| return IsUnpackedLocation(location); |
| } |
| |
| // Returns the Manifest::Type for the given |value|. |
| static Type GetTypeFromManifestValue(const base::DictionaryValue& value, |
| bool for_login_screen = false); |
| |
| // Returns true if an item with the given |location| should always be loaded, |
| // even if extensions are otherwise disabled. |
| static bool ShouldAlwaysLoadExtension(mojom::ManifestLocation location, |
| bool is_theme); |
| |
| // Creates a Manifest for a login screen context. Note that this won't always |
| // result in a Manifest of TYPE_LOGIN_SCREEN_EXTENSION, since other items |
| // (like platform apps) may be installed in the same login screen profile. |
| static std::unique_ptr<Manifest> CreateManifestForLoginScreen( |
| mojom::ManifestLocation location, |
| std::unique_ptr<base::DictionaryValue> value, |
| ExtensionId extension_id); |
| |
| Manifest(mojom::ManifestLocation location, |
| std::unique_ptr<base::DictionaryValue> value, |
| ExtensionId extension_id); |
| |
| Manifest(const Manifest&) = delete; |
| Manifest& operator=(const Manifest&) = delete; |
| |
| ~Manifest(); |
| |
| const ExtensionId& extension_id() const { return extension_id_; } |
| const HashedExtensionId& hashed_id() const { return hashed_id_; } |
| |
| mojom::ManifestLocation location() const { return location_; } |
| |
| // Returns false and |error| will be non-empty if the manifest is malformed. |
| // |warnings| will be populated if there are keys in the manifest that cannot |
| // be specified by the extension type. |
| bool ValidateManifest(std::string* error, |
| std::vector<InstallWarning>* warnings) const; |
| |
| // The version of this extension's manifest. We increase the manifest |
| // version when making breaking changes to the extension system. If the |
| // manifest contains no explicit manifest version, this returns the current |
| // system default. |
| int manifest_version() const { return manifest_version_; } |
| |
| // Returns the manifest type. |
| Type type() const { return type_; } |
| |
| bool is_theme() const { return type_ == TYPE_THEME; } |
| bool is_app() const { |
| return is_legacy_packaged_app() || is_hosted_app() || is_platform_app(); |
| } |
| bool is_platform_app() const { return type_ == TYPE_PLATFORM_APP; } |
| bool is_hosted_app() const { return type_ == TYPE_HOSTED_APP; } |
| bool is_legacy_packaged_app() const { |
| return type_ == TYPE_LEGACY_PACKAGED_APP; |
| } |
| bool is_extension() const { return type_ == TYPE_EXTENSION; } |
| bool is_login_screen_extension() const { |
| return type_ == TYPE_LOGIN_SCREEN_EXTENSION; |
| } |
| bool is_shared_module() const { return type_ == TYPE_SHARED_MODULE; } |
| bool is_chromeos_system_extension() const { |
| return type_ == TYPE_CHROMEOS_SYSTEM_EXTENSION; |
| } |
| |
| // These access the wrapped manifest value, returning nullptr/nullopt when the |
| // property does not exist or if the manifest type can't access it. |
| const base::Value* FindKey(base::StringPiece path) const; |
| const base::Value* FindPath(base::StringPiece path) const; |
| absl::optional<bool> FindBoolPath(base::StringPiece path) const; |
| absl::optional<int> FindIntPath(base::StringPiece path) const; |
| const std::string* FindStringPath(base::StringPiece path) const; |
| // Deprecated: Use the GetDictionary() overload that accepts a base::Value |
| // output parameter instead. |
| bool GetDictionary(const std::string& path, |
| const base::DictionaryValue** out_value) const; |
| bool GetDictionary(const std::string& path, |
| const base::Value** out_value) const; |
| bool GetList(const std::string& path, const base::Value** out_value) const; |
| |
| // Returns true if this equals the |other| manifest. |
| bool EqualsForTesting(const Manifest& other) const; |
| |
| // Gets the underlying DictionaryValue representing the manifest. |
| // Note: only use this when you KNOW you don't need the validation. |
| const base::DictionaryValue* value() const { return value_.get(); } |
| |
| // Gets the underlying DictionaryValue representing the manifest with all |
| // unavailable manifest keys removed. |
| const base::DictionaryValue& available_values() const { |
| return *available_values_; |
| } |
| |
| private: |
| Manifest(mojom::ManifestLocation location, |
| std::unique_ptr<base::DictionaryValue> value, |
| ExtensionId extension_id, |
| bool for_login_screen); |
| |
| // A persistent, globally unique ID. An extension's ID is used in things |
| // like directory structures and URLs, and is expected to not change across |
| // versions. It is generated as a SHA-256 hash of the extension's public |
| // key, or as a hash of the path in the case of unpacked extensions. |
| const std::string extension_id_; |
| |
| // The hex-encoding of the SHA1 of the extension id; used to determine feature |
| // availability. |
| const HashedExtensionId hashed_id_; |
| |
| // The location the extension was loaded from. |
| const mojom::ManifestLocation location_; |
| |
| // The underlying dictionary representation of the manifest. |
| const std::unique_ptr<const base::DictionaryValue> value_; |
| |
| // Same as |value_| but comprises only of keys available to this manifest. |
| std::unique_ptr<const base::DictionaryValue> available_values_; |
| |
| const Type type_; |
| |
| const int manifest_version_; |
| }; |
| |
| } // namespace extensions |
| |
| #endif // EXTENSIONS_COMMON_MANIFEST_H_ |