1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef EXTENSIONS_COMMON_MANIFEST_H_ 6 #define EXTENSIONS_COMMON_MANIFEST_H_ 7 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "base/containers/span.h" 15 #include "base/macros.h" 16 #include "base/strings/string16.h" 17 #include "base/values.h" 18 #include "extensions/common/extension_id.h" 19 #include "extensions/common/hashed_extension_id.h" 20 21 namespace extensions { 22 struct InstallWarning; 23 24 // Wraps the DictionaryValue form of extension's manifest. Enforces access to 25 // properties of the manifest using ManifestFeatureProvider. 26 class Manifest { 27 public: 28 // Historically, where an extension was loaded from, and whether an 29 // extension's files were inside or outside of the profile's directory. In 30 // modern usage, a Location can be thought of as the installation source: 31 // whether an extension was explicitly installed by the user (through the 32 // UI), or implicitly installed by other means. For example, enterprise 33 // policy, being part of Chrome per se (but implemented as an extension), or 34 // installed as a side effect of installing third party software. 35 // 36 // NOTE: These values are stored as integers in the preferences and used 37 // in histograms so don't remove or reorder existing items. Just append 38 // to the end. 39 enum Location { 40 INVALID_LOCATION, 41 INTERNAL, // A crx file from the internal Extensions directory. This 42 // includes extensions explicitly installed by the user. It also 43 // includes installed-by-default extensions that are not part of 44 // Chrome itself (and thus not a COMPONENT), but are part of a 45 // larger system (such as Chrome OS). 46 EXTERNAL_PREF, // A crx file from an external directory (via prefs). 47 EXTERNAL_REGISTRY, // A crx file from an external directory (via eg the 48 // registry on Windows). 49 UNPACKED, // From loading an unpacked extension from the 50 // extensions settings page. 51 COMPONENT, // An integral component of Chrome itself, which 52 // happens to be implemented as an extension. We don't 53 // show these in the management UI. 54 EXTERNAL_PREF_DOWNLOAD, // A crx file from an external directory (via 55 // prefs), installed from an update URL. 56 EXTERNAL_POLICY_DOWNLOAD, // A crx file from an external directory (via 57 // admin policies), installed from an update URL. 58 COMMAND_LINE, // --load-extension. 59 EXTERNAL_POLICY, // A crx file from an external directory (via admin 60 // policies), cached locally and installed from the 61 // cache. 62 EXTERNAL_COMPONENT, // Similar to COMPONENT in that it's considered an 63 // internal implementation detail of chrome, but 64 // installed from an update URL like the *DOWNLOAD ones. 65 66 // New enum values must go above here. 67 NUM_LOCATIONS 68 }; 69 70 // Do not change the order of entries or remove entries in this list as this 71 // is used in ExtensionType enum in tools/metrics/histograms/enums.xml. 72 enum Type { 73 TYPE_UNKNOWN = 0, 74 TYPE_EXTENSION = 1, 75 TYPE_THEME = 2, 76 TYPE_USER_SCRIPT = 3, 77 TYPE_HOSTED_APP = 4, 78 // This is marked legacy because platform apps are preferred. For 79 // backwards compatibility, we can't remove support for packaged apps 80 TYPE_LEGACY_PACKAGED_APP = 5, 81 TYPE_PLATFORM_APP = 6, 82 TYPE_SHARED_MODULE = 7, 83 TYPE_LOGIN_SCREEN_EXTENSION = 8, 84 85 // New enum values must go above here. 86 NUM_LOAD_TYPES 87 }; 88 89 // Given two install sources, return the one which should take priority 90 // over the other. If an extension is installed from two sources A and B, 91 // its install source should be set to GetHigherPriorityLocation(A, B). 92 static Location GetHigherPriorityLocation(Location loc1, Location loc2); 93 94 // Whether the |location| is external or not. IsExternalLocation(Location location)95 static inline bool IsExternalLocation(Location location) { 96 return location == EXTERNAL_PREF || location == EXTERNAL_REGISTRY || 97 location == EXTERNAL_PREF_DOWNLOAD || location == EXTERNAL_POLICY || 98 location == EXTERNAL_POLICY_DOWNLOAD || 99 location == EXTERNAL_COMPONENT; 100 } 101 102 // Whether the |location| is unpacked (no CRX) or not. IsUnpackedLocation(Location location)103 static inline bool IsUnpackedLocation(Location location) { 104 return location == UNPACKED || location == COMMAND_LINE; 105 } 106 107 // Whether extensions with |location| are auto-updatable or not. IsAutoUpdateableLocation(Location location)108 static inline bool IsAutoUpdateableLocation(Location location) { 109 // Only internal and external extensions can be autoupdated. 110 return location == INTERNAL || IsExternalLocation(location); 111 } 112 113 // Whether the |location| is a source of extensions force-installed through 114 // policy. IsPolicyLocation(Location location)115 static inline bool IsPolicyLocation(Location location) { 116 return location == EXTERNAL_POLICY || location == EXTERNAL_POLICY_DOWNLOAD; 117 } 118 119 // Whether the |location| is an extension intended to be an internal part of 120 // Chrome. IsComponentLocation(Location location)121 static inline bool IsComponentLocation(Location location) { 122 return location == COMPONENT || location == EXTERNAL_COMPONENT; 123 } 124 IsValidLocation(Location location)125 static inline bool IsValidLocation(Location location) { 126 return location > INVALID_LOCATION && location < NUM_LOCATIONS; 127 } 128 129 // Unpacked extensions start off with file access since they are a developer 130 // feature. ShouldAlwaysAllowFileAccess(Location location)131 static inline bool ShouldAlwaysAllowFileAccess(Location location) { 132 return IsUnpackedLocation(location); 133 } 134 135 // Returns the Manifest::Type for the given |value|. 136 static Type GetTypeFromManifestValue(const base::DictionaryValue& value, 137 bool for_login_screen = false); 138 139 // Returns true if an item with the given |location| should always be loaded, 140 // even if extensions are otherwise disabled. 141 static bool ShouldAlwaysLoadExtension(Manifest::Location location, 142 bool is_theme); 143 144 // Creates a Manifest for a login screen context. Note that this won't always 145 // result in a Manifest of TYPE_LOGIN_SCREEN_EXTENSION, since other items 146 // (like platform apps) may be installed in the same login screen profile. 147 static std::unique_ptr<Manifest> CreateManifestForLoginScreen( 148 Location location, 149 std::unique_ptr<base::DictionaryValue> value); 150 151 Manifest(Location location, std::unique_ptr<base::DictionaryValue> value); 152 virtual ~Manifest(); 153 154 void SetExtensionId(const ExtensionId& id); 155 extension_id()156 const ExtensionId& extension_id() const { return extension_id_; } hashed_id()157 const HashedExtensionId& hashed_id() const { return hashed_id_; } 158 location()159 Location location() const { return location_; } 160 161 // Returns false and |error| will be non-empty if the manifest is malformed. 162 // |warnings| will be populated if there are keys in the manifest that cannot 163 // be specified by the extension type. 164 bool ValidateManifest(std::string* error, 165 std::vector<InstallWarning>* warnings) const; 166 167 // The version of this extension's manifest. We increase the manifest 168 // version when making breaking changes to the extension system. If the 169 // manifest contains no explicit manifest version, this returns the current 170 // system default. 171 int GetManifestVersion() const; 172 173 // Returns the manifest type. type()174 Type type() const { return type_; } 175 is_theme()176 bool is_theme() const { return type_ == TYPE_THEME; } is_app()177 bool is_app() const { 178 return is_legacy_packaged_app() || is_hosted_app() || is_platform_app(); 179 } is_platform_app()180 bool is_platform_app() const { return type_ == TYPE_PLATFORM_APP; } is_hosted_app()181 bool is_hosted_app() const { return type_ == TYPE_HOSTED_APP; } is_legacy_packaged_app()182 bool is_legacy_packaged_app() const { 183 return type_ == TYPE_LEGACY_PACKAGED_APP; 184 } is_extension()185 bool is_extension() const { return type_ == TYPE_EXTENSION; } is_login_screen_extension()186 bool is_login_screen_extension() const { 187 return type_ == TYPE_LOGIN_SCREEN_EXTENSION; 188 } is_shared_module()189 bool is_shared_module() const { return type_ == TYPE_SHARED_MODULE; } 190 191 // These access the wrapped manifest value, returning false when the property 192 // does not exist or if the manifest type can't access it. 193 // TODO(karandeepb): These methods should be changed to use base::StringPiece. 194 // Better, we should pass a list of path components instead of a unified 195 // |path| to do away with our usage of deprecated base::Value methods. 196 bool HasKey(const std::string& key) const; 197 bool HasPath(const std::string& path) const; 198 bool Get(const std::string& path, const base::Value** out_value) const; 199 bool GetBoolean(const std::string& path, bool* out_value) const; 200 bool GetInteger(const std::string& path, int* out_value) const; 201 bool GetString(const std::string& path, std::string* out_value) const; 202 bool GetString(const std::string& path, base::string16* out_value) const; 203 // Deprecated: Use the GetDictionary() overload that accepts a base::Value 204 // output parameter instead. 205 bool GetDictionary(const std::string& path, 206 const base::DictionaryValue** out_value) const; 207 bool GetDictionary(const std::string& path, 208 const base::Value** out_value) const; 209 // Deprecated: Use the GetList() overload that accepts a base::Value output 210 // parameter instead. 211 bool GetList(const std::string& path, 212 const base::ListValue** out_value) const; 213 bool GetList(const std::string& path, const base::Value** out_value) const; 214 215 bool GetPathOfType(const std::string& path, 216 base::Value::Type type, 217 const base::Value** out_value) const; 218 219 // Returns a new Manifest equal to this one. 220 std::unique_ptr<Manifest> CreateDeepCopy() const; 221 222 // Returns true if this equals the |other| manifest. 223 bool Equals(const Manifest* other) const; 224 225 // Gets the underlying DictionaryValue representing the manifest. 226 // Note: only use this when you KNOW you don't need the validation. value()227 const base::DictionaryValue* value() const { return value_.get(); } 228 229 private: 230 Manifest(Location location, 231 std::unique_ptr<base::DictionaryValue> value, 232 bool for_login_screen); 233 // Returns true if the extension can specify the given |path|. 234 bool CanAccessPath(const std::string& path) const; 235 bool CanAccessPath(const base::span<const base::StringPiece> path) const; 236 bool CanAccessKey(const std::string& key) const; 237 238 // A persistent, globally unique ID. An extension's ID is used in things 239 // like directory structures and URLs, and is expected to not change across 240 // versions. It is generated as a SHA-256 hash of the extension's public 241 // key, or as a hash of the path in the case of unpacked extensions. 242 std::string extension_id_; 243 244 // The hex-encoding of the SHA1 of the extension id; used to determine feature 245 // availability. 246 HashedExtensionId hashed_id_; 247 248 // The location the extension was loaded from. 249 Location location_; 250 251 // The underlying dictionary representation of the manifest. 252 std::unique_ptr<base::DictionaryValue> value_; 253 254 Type type_; 255 256 DISALLOW_COPY_AND_ASSIGN(Manifest); 257 }; 258 259 } // namespace extensions 260 261 #endif // EXTENSIONS_COMMON_MANIFEST_H_ 262