Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / extensions / common / manifest_handlers / permissions_parser.cc
blob0b08ef9345673bb9d1ee0eed71b666592536214a
1 // Copyright 2014 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.
5 #include "extensions/common/manifest_handlers/permissions_parser.h"
7 #include "base/command_line.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "content/public/common/url_constants.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/extensions_client.h"
15 #include "extensions/common/features/feature.h"
16 #include "extensions/common/features/feature_provider.h"
17 #include "extensions/common/manifest.h"
18 #include "extensions/common/manifest_constants.h"
19 #include "extensions/common/manifest_handler.h"
20 #include "extensions/common/permissions/api_permission_set.h"
21 #include "extensions/common/permissions/permission_set.h"
22 #include "extensions/common/permissions/permissions_data.h"
23 #include "extensions/common/switches.h"
24 #include "extensions/common/url_pattern_set.h"
25 #include "url/url_constants.h"
27 namespace extensions {
29 namespace {
31 namespace keys = manifest_keys;
32 namespace errors = manifest_errors;
34 struct ManifestPermissions : public Extension::ManifestData {
35 ManifestPermissions(scoped_refptr<const PermissionSet> permissions);
36 ~ManifestPermissions() override;
38 scoped_refptr<const PermissionSet> permissions;
41 ManifestPermissions::ManifestPermissions(
42 scoped_refptr<const PermissionSet> permissions)
43 : permissions(permissions) {
46 ManifestPermissions::~ManifestPermissions() {
49 // Custom checks for the experimental permission that can't be expressed in
50 // _permission_features.json.
51 bool CanSpecifyExperimentalPermission(const Extension* extension) {
52 if (extension->location() == Manifest::COMPONENT)
53 return true;
55 if (CommandLine::ForCurrentProcess()->HasSwitch(
56 switches::kEnableExperimentalExtensionApis)) {
57 return true;
60 // We rely on the webstore to check access to experimental. This way we can
61 // whitelist extensions to have access to experimental in just the store, and
62 // not have to push a new version of the client.
63 if (extension->from_webstore())
64 return true;
66 return false;
69 // Checks whether the host |pattern| is allowed for the given |extension|,
70 // given API permissions |permissions|.
71 bool CanSpecifyHostPermission(const Extension* extension,
72 const URLPattern& pattern,
73 const APIPermissionSet& permissions) {
74 if (!pattern.match_all_urls() &&
75 pattern.MatchesScheme(content::kChromeUIScheme)) {
76 URLPatternSet chrome_scheme_hosts =
77 ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(extension,
78 permissions);
79 if (chrome_scheme_hosts.ContainsPattern(pattern))
80 return true;
82 // Component extensions can have access to all of chrome://*.
83 if (PermissionsData::CanExecuteScriptEverywhere(extension))
84 return true;
86 if (CommandLine::ForCurrentProcess()->HasSwitch(
87 switches::kExtensionsOnChromeURLs)) {
88 return true;
91 // TODO(aboxhall): return from_webstore() when webstore handles blocking
92 // extensions which request chrome:// urls
93 return false;
96 // Otherwise, the valid schemes were handled by URLPattern.
97 return true;
100 // Parses the host and api permissions from the specified permission |key|
101 // from |extension|'s manifest.
102 bool ParseHelper(Extension* extension,
103 const char* key,
104 APIPermissionSet* api_permissions,
105 URLPatternSet* host_permissions,
106 base::string16* error) {
107 if (!extension->manifest()->HasKey(key))
108 return true;
110 const base::ListValue* permissions = NULL;
111 if (!extension->manifest()->GetList(key, &permissions)) {
112 *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
113 std::string());
114 return false;
117 // NOTE: We need to get the APIPermission before we check if features
118 // associated with them are available because the feature system does not
119 // know about aliases.
121 std::vector<std::string> host_data;
122 if (!APIPermissionSet::ParseFromJSON(
123 permissions,
124 APIPermissionSet::kDisallowInternalPermissions,
125 api_permissions,
126 error,
127 &host_data)) {
128 return false;
131 // Verify feature availability of permissions.
132 std::vector<APIPermission::ID> to_remove;
133 const FeatureProvider* permission_features =
134 FeatureProvider::GetPermissionFeatures();
135 for (APIPermissionSet::const_iterator iter = api_permissions->begin();
136 iter != api_permissions->end();
137 ++iter) {
138 Feature* feature = permission_features->GetFeature(iter->name());
140 // The feature should exist since we just got an APIPermission for it. The
141 // two systems should be updated together whenever a permission is added.
142 DCHECK(feature) << "Could not find feature for " << iter->name();
143 // http://crbug.com/176381
144 if (!feature) {
145 to_remove.push_back(iter->id());
146 continue;
149 Feature::Availability availability =
150 feature->IsAvailableToExtension(extension);
151 if (!availability.is_available()) {
152 // Don't fail, but warn the developer that the manifest contains
153 // unrecognized permissions. This may happen legitimately if the
154 // extensions requests platform- or channel-specific permissions.
155 extension->AddInstallWarning(
156 InstallWarning(availability.message(), feature->name()));
157 to_remove.push_back(iter->id());
158 continue;
161 if (iter->id() == APIPermission::kExperimental) {
162 if (!CanSpecifyExperimentalPermission(extension)) {
163 *error = base::ASCIIToUTF16(errors::kExperimentalFlagRequired);
164 return false;
169 api_permissions->AddImpliedPermissions();
171 // Remove permissions that are not available to this extension.
172 for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
173 iter != to_remove.end();
174 ++iter) {
175 api_permissions->erase(*iter);
178 // Parse host pattern permissions.
179 const int kAllowedSchemes =
180 PermissionsData::CanExecuteScriptEverywhere(extension)
181 ? URLPattern::SCHEME_ALL
182 : Extension::kValidHostPermissionSchemes;
184 for (std::vector<std::string>::const_iterator iter = host_data.begin();
185 iter != host_data.end();
186 ++iter) {
187 const std::string& permission_str = *iter;
189 // Check if it's a host pattern permission.
190 URLPattern pattern = URLPattern(kAllowedSchemes);
191 URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
192 if (parse_result == URLPattern::PARSE_SUCCESS) {
193 // The path component is not used for host permissions, so we force it
194 // to match all paths.
195 pattern.SetPath("/*");
196 int valid_schemes = pattern.valid_schemes();
197 if (pattern.MatchesScheme(url::kFileScheme) &&
198 !PermissionsData::CanExecuteScriptEverywhere(extension)) {
199 extension->set_wants_file_access(true);
200 if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
201 valid_schemes &= ~URLPattern::SCHEME_FILE;
204 if (pattern.scheme() != content::kChromeUIScheme &&
205 !PermissionsData::CanExecuteScriptEverywhere(extension)) {
206 // Keep chrome:// in allowed schemes only if it's explicitly requested
207 // or CanExecuteScriptEverywhere is true. If the
208 // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
209 // will fail, so don't check the flag here.
210 valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
212 pattern.SetValidSchemes(valid_schemes);
214 if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
215 // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
216 // below).
217 extension->AddInstallWarning(InstallWarning(
218 ErrorUtils::FormatErrorMessage(errors::kInvalidPermissionScheme,
219 permission_str),
220 key,
221 permission_str));
222 continue;
225 host_permissions->AddPattern(pattern);
226 // We need to make sure all_urls matches chrome://favicon and (maybe)
227 // chrome://thumbnail, so add them back in to host_permissions separately.
228 if (pattern.match_all_urls()) {
229 host_permissions->AddPatterns(
230 ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
231 extension, *api_permissions));
233 continue;
236 // It's probably an unknown API permission. Do not throw an error so
237 // extensions can retain backwards compatability (http://crbug.com/42742).
238 extension->AddInstallWarning(InstallWarning(
239 ErrorUtils::FormatErrorMessage(
240 manifest_errors::kPermissionUnknownOrMalformed, permission_str),
241 key,
242 permission_str));
245 return true;
248 } // namespace
250 struct PermissionsParser::InitialPermissions {
251 APIPermissionSet api_permissions;
252 ManifestPermissionSet manifest_permissions;
253 URLPatternSet host_permissions;
254 URLPatternSet scriptable_hosts;
257 PermissionsParser::PermissionsParser() {
260 PermissionsParser::~PermissionsParser() {
263 bool PermissionsParser::Parse(Extension* extension, base::string16* error) {
264 initial_required_permissions_.reset(new InitialPermissions);
265 if (!ParseHelper(extension,
266 keys::kPermissions,
267 &initial_required_permissions_->api_permissions,
268 &initial_required_permissions_->host_permissions,
269 error)) {
270 return false;
273 initial_optional_permissions_.reset(new InitialPermissions);
274 if (!ParseHelper(extension,
275 keys::kOptionalPermissions,
276 &initial_optional_permissions_->api_permissions,
277 &initial_optional_permissions_->host_permissions,
278 error)) {
279 return false;
282 return true;
285 void PermissionsParser::Finalize(Extension* extension) {
286 ManifestHandler::AddExtensionInitialRequiredPermissions(
287 extension, &initial_required_permissions_->manifest_permissions);
289 scoped_refptr<const PermissionSet> required_permissions(
290 new PermissionSet(initial_required_permissions_->api_permissions,
291 initial_required_permissions_->manifest_permissions,
292 initial_required_permissions_->host_permissions,
293 initial_required_permissions_->scriptable_hosts));
294 extension->SetManifestData(keys::kPermissions,
295 new ManifestPermissions(required_permissions));
297 scoped_refptr<const PermissionSet> optional_permissions(
298 new PermissionSet(initial_optional_permissions_->api_permissions,
299 initial_optional_permissions_->manifest_permissions,
300 initial_optional_permissions_->host_permissions,
301 URLPatternSet()));
302 extension->SetManifestData(keys::kOptionalPermissions,
303 new ManifestPermissions(optional_permissions));
306 // static
307 void PermissionsParser::AddAPIPermission(Extension* extension,
308 APIPermission::ID permission) {
309 DCHECK(extension->permissions_parser());
310 extension->permissions_parser()
311 ->initial_required_permissions_->api_permissions.insert(permission);
314 // static
315 void PermissionsParser::AddAPIPermission(Extension* extension,
316 APIPermission* permission) {
317 DCHECK(extension->permissions_parser());
318 extension->permissions_parser()
319 ->initial_required_permissions_->api_permissions.insert(permission);
322 // static
323 bool PermissionsParser::HasAPIPermission(const Extension* extension,
324 APIPermission::ID permission) {
325 DCHECK(extension->permissions_parser());
326 return extension->permissions_parser()
327 ->initial_required_permissions_->api_permissions.count(
328 permission) > 0;
331 // static
332 void PermissionsParser::SetScriptableHosts(
333 Extension* extension,
334 const URLPatternSet& scriptable_hosts) {
335 DCHECK(extension->permissions_parser());
336 extension->permissions_parser()
337 ->initial_required_permissions_->scriptable_hosts = scriptable_hosts;
340 // static
341 scoped_refptr<const PermissionSet> PermissionsParser::GetRequiredPermissions(
342 const Extension* extension) {
343 DCHECK(extension->GetManifestData(keys::kPermissions));
344 return static_cast<const ManifestPermissions*>(
345 extension->GetManifestData(keys::kPermissions))->permissions;
348 // static
349 scoped_refptr<const PermissionSet> PermissionsParser::GetOptionalPermissions(
350 const Extension* extension) {
351 DCHECK(extension->GetManifestData(keys::kOptionalPermissions));
352 return static_cast<const ManifestPermissions*>(
353 extension->GetManifestData(keys::kOptionalPermissions))
354 ->permissions;
357 } // namespace extensions