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