Home | History | Annotate | Download | only in permissions
      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 #include "extensions/common/permissions/permission_set.h"
      6 
      7 #include <algorithm>
      8 #include <iterator>
      9 #include <string>
     10 
     11 #include "extensions/common/permissions/permissions_info.h"
     12 #include "extensions/common/url_pattern.h"
     13 #include "extensions/common/url_pattern_set.h"
     14 #include "url/gurl.h"
     15 
     16 using extensions::URLPatternSet;
     17 
     18 namespace {
     19 
     20 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
     21   DCHECK(out);
     22   for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
     23     URLPattern p = *i;
     24     p.SetPath("/*");
     25     out->AddPattern(p);
     26   }
     27 }
     28 
     29 }  // namespace
     30 
     31 namespace extensions {
     32 
     33 //
     34 // PermissionSet
     35 //
     36 
     37 PermissionSet::PermissionSet() {}
     38 
     39 PermissionSet::PermissionSet(
     40     const APIPermissionSet& apis,
     41     const ManifestPermissionSet& manifest_permissions,
     42     const URLPatternSet& explicit_hosts,
     43     const URLPatternSet& scriptable_hosts)
     44     : apis_(apis),
     45       manifest_permissions_(manifest_permissions),
     46       scriptable_hosts_(scriptable_hosts) {
     47   AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
     48   InitImplicitPermissions();
     49   InitEffectiveHosts();
     50 }
     51 
     52 // static
     53 PermissionSet* PermissionSet::CreateDifference(
     54     const PermissionSet* set1,
     55     const PermissionSet* set2) {
     56   scoped_refptr<PermissionSet> empty = new PermissionSet();
     57   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
     58   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
     59 
     60   APIPermissionSet apis;
     61   APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
     62 
     63   ManifestPermissionSet manifest_permissions;
     64   ManifestPermissionSet::Difference(set1_safe->manifest_permissions(),
     65                                     set2_safe->manifest_permissions(),
     66                                     &manifest_permissions);
     67 
     68   URLPatternSet explicit_hosts;
     69   URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
     70                                   set2_safe->explicit_hosts(),
     71                                   &explicit_hosts);
     72 
     73   URLPatternSet scriptable_hosts;
     74   URLPatternSet::CreateDifference(set1_safe->scriptable_hosts(),
     75                                   set2_safe->scriptable_hosts(),
     76                                   &scriptable_hosts);
     77 
     78   return new PermissionSet(apis, manifest_permissions,
     79                            explicit_hosts, scriptable_hosts);
     80 }
     81 
     82 // static
     83 PermissionSet* PermissionSet::CreateIntersection(
     84     const PermissionSet* set1,
     85     const PermissionSet* set2) {
     86   scoped_refptr<PermissionSet> empty = new PermissionSet();
     87   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
     88   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
     89 
     90   APIPermissionSet apis;
     91   APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
     92 
     93   ManifestPermissionSet manifest_permissions;
     94   ManifestPermissionSet::Intersection(set1_safe->manifest_permissions(),
     95                                       set2_safe->manifest_permissions(),
     96                                       &manifest_permissions);
     97 
     98   URLPatternSet explicit_hosts;
     99   URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
    100                                     set2_safe->explicit_hosts(),
    101                                     &explicit_hosts);
    102 
    103   URLPatternSet scriptable_hosts;
    104   URLPatternSet::CreateIntersection(set1_safe->scriptable_hosts(),
    105                                     set2_safe->scriptable_hosts(),
    106                                     &scriptable_hosts);
    107 
    108   return new PermissionSet(apis, manifest_permissions,
    109                            explicit_hosts, scriptable_hosts);
    110 }
    111 
    112 // static
    113 PermissionSet* PermissionSet::CreateUnion(
    114     const PermissionSet* set1,
    115     const PermissionSet* set2) {
    116   scoped_refptr<PermissionSet> empty = new PermissionSet();
    117   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
    118   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
    119 
    120   APIPermissionSet apis;
    121   APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
    122 
    123   ManifestPermissionSet manifest_permissions;
    124   ManifestPermissionSet::Union(set1_safe->manifest_permissions(),
    125                                set2_safe->manifest_permissions(),
    126                                &manifest_permissions);
    127 
    128   URLPatternSet explicit_hosts;
    129   URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
    130                              set2_safe->explicit_hosts(),
    131                              &explicit_hosts);
    132 
    133   URLPatternSet scriptable_hosts;
    134   URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
    135                              set2_safe->scriptable_hosts(),
    136                              &scriptable_hosts);
    137 
    138   return new PermissionSet(apis, manifest_permissions,
    139                            explicit_hosts, scriptable_hosts);
    140 }
    141 
    142 bool PermissionSet::operator==(
    143     const PermissionSet& rhs) const {
    144   return apis_ == rhs.apis_ &&
    145       manifest_permissions_ == rhs.manifest_permissions_ &&
    146       scriptable_hosts_ == rhs.scriptable_hosts_ &&
    147       explicit_hosts_ == rhs.explicit_hosts_;
    148 }
    149 
    150 bool PermissionSet::Contains(const PermissionSet& set) const {
    151   return apis_.Contains(set.apis()) &&
    152          manifest_permissions_.Contains(set.manifest_permissions()) &&
    153          explicit_hosts().Contains(set.explicit_hosts()) &&
    154          scriptable_hosts().Contains(set.scriptable_hosts());
    155 }
    156 
    157 std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
    158   std::set<std::string> apis_str;
    159   for (APIPermissionSet::const_iterator i = apis_.begin();
    160        i != apis_.end(); ++i) {
    161     apis_str.insert(i->name());
    162   }
    163   return apis_str;
    164 }
    165 
    166 bool PermissionSet::IsEmpty() const {
    167   // Not default if any host permissions are present.
    168   if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
    169     return false;
    170 
    171   // Or if it has no api permissions.
    172   return apis().empty() && manifest_permissions().empty();
    173 }
    174 
    175 bool PermissionSet::HasAPIPermission(
    176     APIPermission::ID id) const {
    177   return apis().find(id) != apis().end();
    178 }
    179 
    180 bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
    181   const APIPermissionInfo* permission =
    182       PermissionsInfo::GetInstance()->GetByName(permission_name);
    183   CHECK(permission) << permission_name;
    184   return (permission && apis_.count(permission->id()));
    185 }
    186 
    187 bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
    188   return CheckAPIPermissionWithParam(permission, NULL);
    189 }
    190 
    191 bool PermissionSet::CheckAPIPermissionWithParam(
    192     APIPermission::ID permission,
    193     const APIPermission::CheckParam* param) const {
    194   APIPermissionSet::const_iterator iter = apis().find(permission);
    195   if (iter == apis().end())
    196     return false;
    197   return iter->Check(param);
    198 }
    199 
    200 bool PermissionSet::HasExplicitAccessToOrigin(
    201     const GURL& origin) const {
    202   return explicit_hosts().MatchesURL(origin);
    203 }
    204 
    205 bool PermissionSet::HasScriptableAccessToURL(
    206     const GURL& origin) const {
    207   // We only need to check our host list to verify access. The host list should
    208   // already reflect any special rules (such as chrome://favicon, all hosts
    209   // access, etc.).
    210   return scriptable_hosts().MatchesURL(origin);
    211 }
    212 
    213 bool PermissionSet::HasEffectiveAccessToAllHosts() const {
    214   // There are two ways this set can have effective access to all hosts:
    215   //  1) it has an <all_urls> URL pattern.
    216   //  2) it has a named permission with implied full URL access.
    217   for (URLPatternSet::const_iterator host = effective_hosts().begin();
    218        host != effective_hosts().end(); ++host) {
    219     if (host->match_all_urls() ||
    220         (host->match_subdomains() && host->host().empty()))
    221       return true;
    222   }
    223 
    224   for (APIPermissionSet::const_iterator i = apis().begin();
    225        i != apis().end(); ++i) {
    226     if (i->info()->implies_full_url_access())
    227       return true;
    228   }
    229   return false;
    230 }
    231 
    232 bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
    233   return effective_hosts().MatchesURL(url);
    234 }
    235 
    236 bool PermissionSet::HasEffectiveFullAccess() const {
    237   for (APIPermissionSet::const_iterator i = apis().begin();
    238        i != apis().end(); ++i) {
    239     if (i->info()->implies_full_access())
    240       return true;
    241   }
    242   return false;
    243 }
    244 
    245 PermissionSet::~PermissionSet() {}
    246 
    247 void PermissionSet::InitImplicitPermissions() {
    248   // The downloads permission implies the internal version as well.
    249   if (apis_.find(APIPermission::kDownloads) != apis_.end())
    250     apis_.insert(APIPermission::kDownloadsInternal);
    251 
    252   // TODO(fsamuel): Is there a better way to request access to the WebRequest
    253   // API without exposing it to the Chrome App?
    254   if (apis_.find(APIPermission::kWebView) != apis_.end())
    255     apis_.insert(APIPermission::kWebRequestInternal);
    256 
    257   // The webRequest permission implies the internal version as well.
    258   if (apis_.find(APIPermission::kWebRequest) != apis_.end())
    259     apis_.insert(APIPermission::kWebRequestInternal);
    260 
    261   // The fileBrowserHandler permission implies the internal version as well.
    262   if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
    263     apis_.insert(APIPermission::kFileBrowserHandlerInternal);
    264 }
    265 
    266 void PermissionSet::InitEffectiveHosts() {
    267   effective_hosts_.ClearPatterns();
    268 
    269   URLPatternSet::CreateUnion(
    270       explicit_hosts(), scriptable_hosts(), &effective_hosts_);
    271 }
    272 
    273 }  // namespace extensions
    274