Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / extensions / common / permissions / permissions_data.cc
1 // Copyright (c) 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 #include "extensions/common/permissions/permissions_data.h"
6
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string16.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "content/public/common/url_constants.h"
15 #include "extensions/common/constants.h"
16 #include "extensions/common/error_utils.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/extensions_client.h"
19 #include "extensions/common/features/feature.h"
20 #include "extensions/common/features/feature_provider.h"
21 #include "extensions/common/manifest.h"
22 #include "extensions/common/manifest_constants.h"
23 #include "extensions/common/manifest_handler.h"
24 #include "extensions/common/permissions/api_permission_set.h"
25 #include "extensions/common/permissions/permission_message_provider.h"
26 #include "extensions/common/permissions/permission_set.h"
27 #include "extensions/common/permissions/permissions_info.h"
28 #include "extensions/common/switches.h"
29 #include "extensions/common/url_pattern_set.h"
30 #include "extensions/common/user_script.h"
31 #include "url/gurl.h"
32
33 namespace extensions {
34
35 namespace keys = manifest_keys;
36 namespace errors = manifest_errors;
37
38 namespace {
39
40 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
41
42 // Custom checks for the experimental permission that can't be expressed in
43 // _permission_features.json.
44 bool CanSpecifyExperimentalPermission(const Extension* extension) {
45   if (extension->location() == Manifest::COMPONENT)
46     return true;
47
48   if (CommandLine::ForCurrentProcess()->HasSwitch(
49           switches::kEnableExperimentalExtensionApis)) {
50     return true;
51   }
52
53   // We rely on the webstore to check access to experimental. This way we can
54   // whitelist extensions to have access to experimental in just the store, and
55   // not have to push a new version of the client.
56   if (extension->from_webstore())
57     return true;
58
59   return false;
60 }
61
62 // Checks whether the host |pattern| is allowed for the given |extension|,
63 // given API permissions |permissions|.
64 bool CanSpecifyHostPermission(const Extension* extension,
65                               const URLPattern& pattern,
66                               const APIPermissionSet& permissions) {
67   if (!pattern.match_all_urls() &&
68       pattern.MatchesScheme(content::kChromeUIScheme)) {
69     URLPatternSet chrome_scheme_hosts = ExtensionsClient::Get()->
70         GetPermittedChromeSchemeHosts(extension, permissions);
71     if (chrome_scheme_hosts.ContainsPattern(pattern))
72       return true;
73
74     // Component extensions can have access to all of chrome://*.
75     if (PermissionsData::CanExecuteScriptEverywhere(extension))
76       return true;
77
78     if (CommandLine::ForCurrentProcess()->HasSwitch(
79           switches::kExtensionsOnChromeURLs)) {
80       return true;
81     }
82
83     // TODO(aboxhall): return from_webstore() when webstore handles blocking
84     // extensions which request chrome:// urls
85     return false;
86   }
87
88   // Otherwise, the valid schemes were handled by URLPattern.
89   return true;
90 }
91
92 // Parses the host and api permissions from the specified permission |key|
93 // from |extension|'s manifest.
94 bool ParseHelper(Extension* extension,
95                  const char* key,
96                  APIPermissionSet* api_permissions,
97                  URLPatternSet* host_permissions,
98                  base::string16* error) {
99   if (!extension->manifest()->HasKey(key))
100     return true;
101
102   const base::ListValue* permissions = NULL;
103   if (!extension->manifest()->GetList(key, &permissions)) {
104     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
105                                                  std::string());
106     return false;
107   }
108
109   // NOTE: We need to get the APIPermission before we check if features
110   // associated with them are available because the feature system does not
111   // know about aliases.
112
113   std::vector<std::string> host_data;
114   if (!APIPermissionSet::ParseFromJSON(
115           permissions, APIPermissionSet::kDisallowInternalPermissions,
116           api_permissions, error, &host_data)) {
117     return false;
118   }
119
120   // Verify feature availability of permissions.
121   std::vector<APIPermission::ID> to_remove;
122   FeatureProvider* permission_features =
123       FeatureProvider::GetPermissionFeatures();
124   for (APIPermissionSet::const_iterator iter = api_permissions->begin();
125        iter != api_permissions->end(); ++iter) {
126     Feature* feature = permission_features->GetFeature(iter->name());
127
128     // The feature should exist since we just got an APIPermission for it. The
129     // two systems should be updated together whenever a permission is added.
130     DCHECK(feature) << "Could not find feature for " << iter->name();
131     // http://crbug.com/176381
132     if (!feature) {
133       to_remove.push_back(iter->id());
134       continue;
135     }
136
137     Feature::Availability availability =
138         feature->IsAvailableToExtension(extension);
139
140     if (!availability.is_available()) {
141       // Don't fail, but warn the developer that the manifest contains
142       // unrecognized permissions. This may happen legitimately if the
143       // extensions requests platform- or channel-specific permissions.
144       extension->AddInstallWarning(InstallWarning(availability.message(),
145                                                   feature->name()));
146       to_remove.push_back(iter->id());
147       continue;
148     }
149
150     if (iter->id() == APIPermission::kExperimental) {
151       if (!CanSpecifyExperimentalPermission(extension)) {
152         *error = base::ASCIIToUTF16(errors::kExperimentalFlagRequired);
153         return false;
154       }
155     }
156   }
157
158   api_permissions->AddImpliedPermissions();
159
160   // Remove permissions that are not available to this extension.
161   for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
162        iter != to_remove.end(); ++iter) {
163       api_permissions->erase(*iter);
164   }
165
166   // Parse host pattern permissions.
167   const int kAllowedSchemes =
168       PermissionsData::CanExecuteScriptEverywhere(extension) ?
169       URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes;
170
171   for (std::vector<std::string>::const_iterator iter = host_data.begin();
172        iter != host_data.end(); ++iter) {
173     const std::string& permission_str = *iter;
174
175     // Check if it's a host pattern permission.
176     URLPattern pattern = URLPattern(kAllowedSchemes);
177     URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
178     if (parse_result == URLPattern::PARSE_SUCCESS) {
179       // The path component is not used for host permissions, so we force it
180       // to match all paths.
181       pattern.SetPath("/*");
182       int valid_schemes = pattern.valid_schemes();
183       if (pattern.MatchesScheme(content::kFileScheme) &&
184           !PermissionsData::CanExecuteScriptEverywhere(extension)) {
185         extension->set_wants_file_access(true);
186         if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
187           valid_schemes &= ~URLPattern::SCHEME_FILE;
188       }
189
190       if (pattern.scheme() != content::kChromeUIScheme &&
191           !PermissionsData::CanExecuteScriptEverywhere(extension)) {
192         // Keep chrome:// in allowed schemes only if it's explicitly requested
193         // or CanExecuteScriptEverywhere is true. If the
194         // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
195         // will fail, so don't check the flag here.
196         valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
197       }
198       pattern.SetValidSchemes(valid_schemes);
199
200       if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
201         // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
202         // below).
203         extension->AddInstallWarning(InstallWarning(
204             ErrorUtils::FormatErrorMessage(
205                 errors::kInvalidPermissionScheme, permission_str),
206             key,
207             permission_str));
208         continue;
209       }
210
211       host_permissions->AddPattern(pattern);
212       // We need to make sure all_urls matches chrome://favicon and (maybe)
213       // chrome://thumbnail, so add them back in to host_permissions separately.
214       if (pattern.match_all_urls()) {
215         host_permissions->AddPatterns(
216             ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
217                 extension, *api_permissions));
218       }
219       continue;
220     }
221
222     // It's probably an unknown API permission. Do not throw an error so
223     // extensions can retain backwards compatability (http://crbug.com/42742).
224     extension->AddInstallWarning(InstallWarning(
225         ErrorUtils::FormatErrorMessage(
226             manifest_errors::kPermissionUnknownOrMalformed,
227             permission_str),
228         key,
229         permission_str));
230   }
231
232   return true;
233 }
234
235 // Returns true if this extension id is from a trusted provider.
236 bool IsTrustedId(const std::string& extension_id) {
237   // See http://b/4946060 for more details.
238   return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
239 }
240
241 }  // namespace
242
243 struct PermissionsData::InitialPermissions {
244   APIPermissionSet api_permissions;
245   ManifestPermissionSet manifest_permissions;
246   URLPatternSet host_permissions;
247   URLPatternSet scriptable_hosts;
248 };
249
250 PermissionsData::PermissionsData() {
251 }
252
253 PermissionsData::~PermissionsData() {
254 }
255
256 // static
257 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
258   g_policy_delegate = delegate;
259 }
260
261 // static
262 const PermissionSet* PermissionsData::GetOptionalPermissions(
263     const Extension* extension) {
264   return extension->permissions_data()->optional_permission_set_.get();
265 }
266
267 // static
268 const PermissionSet* PermissionsData::GetRequiredPermissions(
269     const Extension* extension) {
270   return extension->permissions_data()->required_permission_set_.get();
271 }
272
273 // static
274 const APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
275     const Extension* extension) {
276   return &extension->permissions_data()->
277       initial_required_permissions_->api_permissions;
278 }
279
280 // static
281 APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
282     Extension* extension) {
283   return &extension->permissions_data()->
284       initial_required_permissions_->api_permissions;
285 }
286
287 // static
288 void PermissionsData::SetInitialScriptableHosts(
289     Extension* extension, const URLPatternSet& scriptable_hosts) {
290   extension->permissions_data()->
291       initial_required_permissions_->scriptable_hosts = scriptable_hosts;
292 }
293
294 // static
295 void PermissionsData::SetActivePermissions(const Extension* extension,
296                                            const PermissionSet* permissions) {
297   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
298   extension->permissions_data()->active_permissions_ = permissions;
299 }
300
301 // static
302 scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions(
303     const Extension* extension) {
304   return extension->permissions_data()->active_permissions_;
305 }
306
307 // static
308 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
309     const Extension* extension,
310     int tab_id) {
311   CHECK_GE(tab_id, 0);
312   TabPermissionsMap::const_iterator iter =
313       extension->permissions_data()->tab_specific_permissions_.find(tab_id);
314   return
315       (iter != extension->permissions_data()->tab_specific_permissions_.end())
316           ? iter->second
317           : NULL;
318 }
319
320 // static
321 void PermissionsData::UpdateTabSpecificPermissions(
322     const Extension* extension,
323     int tab_id,
324     scoped_refptr<const PermissionSet> permissions) {
325   CHECK_GE(tab_id, 0);
326   TabPermissionsMap* tab_permissions =
327       &extension->permissions_data()->tab_specific_permissions_;
328   if (tab_permissions->count(tab_id)) {
329     (*tab_permissions)[tab_id] = PermissionSet::CreateUnion(
330         (*tab_permissions)[tab_id].get(), permissions.get());
331   } else {
332     (*tab_permissions)[tab_id] = permissions;
333   }
334 }
335
336 // static
337 void PermissionsData::ClearTabSpecificPermissions(
338     const Extension* extension,
339     int tab_id) {
340   CHECK_GE(tab_id, 0);
341   extension->permissions_data()->tab_specific_permissions_.erase(tab_id);
342 }
343
344 // static
345 bool PermissionsData::HasAPIPermission(const Extension* extension,
346                                        APIPermission::ID permission) {
347   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
348   return GetActivePermissions(extension)->HasAPIPermission(permission);
349 }
350
351 // static
352 bool PermissionsData::HasAPIPermission(
353     const Extension* extension,
354     const std::string& permission_name) {
355   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
356   return GetActivePermissions(extension)->HasAPIPermission(permission_name);
357 }
358
359 // static
360 bool PermissionsData::HasAPIPermissionForTab(
361     const Extension* extension,
362     int tab_id,
363     APIPermission::ID permission) {
364   if (HasAPIPermission(extension, permission))
365     return true;
366
367   // Place autolock below the HasAPIPermission() check, since HasAPIPermission
368   // also acquires the lock.
369   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
370   scoped_refptr<const PermissionSet> tab_permissions =
371       GetTabSpecificPermissions(extension, tab_id);
372   return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
373 }
374
375 // static
376 bool PermissionsData::CheckAPIPermissionWithParam(
377     const Extension* extension,
378     APIPermission::ID permission,
379     const APIPermission::CheckParam* param) {
380   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
381   return GetActivePermissions(extension)->CheckAPIPermissionWithParam(
382       permission, param);
383 }
384
385 // static
386 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
387     const Extension* extension) {
388   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
389   return GetActivePermissions(extension)->effective_hosts();
390 }
391
392 // static
393 bool PermissionsData::CanSilentlyIncreasePermissions(
394     const Extension* extension) {
395   return extension->location() != Manifest::INTERNAL;
396 }
397
398 // static
399 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) {
400   return IsTrustedId(extension->id());
401 }
402
403 // static
404 bool PermissionsData::HasHostPermission(const Extension* extension,
405                                         const GURL& url) {
406   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
407   return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url);
408 }
409
410 // static
411 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) {
412   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
413   return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts();
414 }
415
416 // static
417 PermissionMessages PermissionsData::GetPermissionMessages(
418     const Extension* extension) {
419   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
420   if (ShouldSkipPermissionWarnings(extension)) {
421     return PermissionMessages();
422   } else {
423     return PermissionMessageProvider::Get()->GetPermissionMessages(
424         GetActivePermissions(extension), extension->GetType());
425   }
426 }
427
428 // static
429 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings(
430     const Extension* extension) {
431   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
432   if (ShouldSkipPermissionWarnings(extension)) {
433     return std::vector<base::string16>();
434   } else {
435     return PermissionMessageProvider::Get()->GetWarningMessages(
436         GetActivePermissions(extension), extension->GetType());
437   }
438 }
439
440 // static
441 std::vector<base::string16> PermissionsData::GetPermissionMessageDetailsStrings(
442     const Extension* extension) {
443   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
444   if (ShouldSkipPermissionWarnings(extension)) {
445     return std::vector<base::string16>();
446   } else {
447     return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
448         GetActivePermissions(extension), extension->GetType());
449   }
450 }
451
452 // static
453 bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension,
454                                              const GURL& document_url,
455                                              const GURL& top_frame_url,
456                                              int tab_id,
457                                              const UserScript* script,
458                                              int process_id,
459                                              std::string* error) {
460   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
461   const CommandLine* command_line = CommandLine::ForCurrentProcess();
462   bool can_execute_everywhere = CanExecuteScriptEverywhere(extension);
463
464   if (g_policy_delegate &&
465       !g_policy_delegate->CanExecuteScriptOnPage(
466            extension, document_url, top_frame_url, tab_id,
467            script, process_id, error))
468     return false;
469
470   if (!can_execute_everywhere &&
471       !ExtensionsClient::Get()->IsScriptableURL(document_url, error)) {
472     return false;
473   }
474
475   if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) {
476     if (document_url.SchemeIs(content::kChromeUIScheme) &&
477         !can_execute_everywhere) {
478       if (error)
479         *error = errors::kCannotAccessChromeUrl;
480       return false;
481     }
482   }
483
484   if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
485       top_frame_url.GetOrigin() !=
486           Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() &&
487       !can_execute_everywhere) {
488     if (error)
489       *error = errors::kCannotAccessExtensionUrl;
490     return false;
491   }
492
493   // If a tab ID is specified, try the tab-specific permissions.
494   if (tab_id >= 0) {
495     scoped_refptr<const PermissionSet> tab_permissions =
496         GetTabSpecificPermissions(extension, tab_id);
497     if (tab_permissions.get() &&
498         tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
499       return true;
500     }
501   }
502
503   bool can_access = false;
504
505   if (script) {
506     // If a script is specified, use its matches.
507     can_access = script->MatchesURL(document_url);
508   } else {
509     // Otherwise, see if this extension has permission to execute script
510     // programmatically on pages.
511     can_access = GetActivePermissions(extension)->
512         HasExplicitAccessToOrigin(document_url);
513   }
514
515   if (!can_access && error) {
516     *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
517                                             document_url.spec());
518   }
519
520   return can_access;
521 }
522
523 // static
524 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
525   if (extension->location() == Manifest::COMPONENT)
526     return true;
527
528   const ExtensionsClient::ScriptingWhitelist& whitelist =
529       ExtensionsClient::Get()->GetScriptingWhitelist();
530
531   return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
532       whitelist.end();
533 }
534
535 // static
536 bool PermissionsData::CanCaptureVisiblePage(const Extension* extension,
537                                             int tab_id,
538                                             std::string* error) {
539   scoped_refptr<const PermissionSet> active_permissions =
540       GetActivePermissions(extension);
541   const URLPattern all_urls(URLPattern::SCHEME_ALL,
542                             URLPattern::kAllUrlsPattern);
543   if (active_permissions->explicit_hosts().ContainsPattern(all_urls))
544     return true;
545
546   if (tab_id >= 0) {
547     scoped_refptr<const PermissionSet> tab_permissions =
548         GetTabSpecificPermissions(extension, tab_id);
549     if (tab_permissions &&
550         tab_permissions->HasAPIPermission(APIPermission::kTab)) {
551       return true;
552     }
553     if (error)
554       *error = errors::kActiveTabPermissionNotGranted;
555     return false;
556   }
557
558   if (error)
559     *error = errors::kAllURLOrActiveTabNeeded;
560   return false;
561 }
562
563 bool PermissionsData::ParsePermissions(Extension* extension,
564                                        base::string16* error) {
565   initial_required_permissions_.reset(new InitialPermissions);
566   if (!ParseHelper(extension,
567                    keys::kPermissions,
568                    &initial_required_permissions_->api_permissions,
569                    &initial_required_permissions_->host_permissions,
570                    error)) {
571     return false;
572   }
573
574   initial_optional_permissions_.reset(new InitialPermissions);
575   if (!ParseHelper(extension,
576                    keys::kOptionalPermissions,
577                    &initial_optional_permissions_->api_permissions,
578                    &initial_optional_permissions_->host_permissions,
579                    error)) {
580     return false;
581   }
582
583   return true;
584 }
585
586 void PermissionsData::InitializeManifestPermissions(Extension* extension) {
587   ManifestHandler::AddExtensionInitialRequiredPermissions(
588     extension, &initial_required_permissions_->manifest_permissions);
589 }
590
591 void PermissionsData::FinalizePermissions(Extension* extension) {
592   active_permissions_ = new PermissionSet(
593       initial_required_permissions_->api_permissions,
594       initial_required_permissions_->manifest_permissions,
595       initial_required_permissions_->host_permissions,
596       initial_required_permissions_->scriptable_hosts);
597
598   required_permission_set_ = new PermissionSet(
599       initial_required_permissions_->api_permissions,
600       initial_required_permissions_->manifest_permissions,
601       initial_required_permissions_->host_permissions,
602       initial_required_permissions_->scriptable_hosts);
603
604   optional_permission_set_ = new PermissionSet(
605       initial_optional_permissions_->api_permissions,
606       initial_optional_permissions_->manifest_permissions,
607       initial_optional_permissions_->host_permissions,
608       URLPatternSet());
609
610   initial_required_permissions_.reset();
611   initial_optional_permissions_.reset();
612 }
613
614 }  // namespace extensions