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 namespace extensions {
     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 //
     32 // PermissionSet
     33 //
     34 
     35 PermissionSet::PermissionSet() : should_warn_all_hosts_(UNINITIALIZED) {}
     36 
     37 PermissionSet::PermissionSet(
     38     const APIPermissionSet& apis,
     39     const ManifestPermissionSet& manifest_permissions,
     40     const URLPatternSet& explicit_hosts,
     41     const URLPatternSet& scriptable_hosts)
     42     : apis_(apis),
     43       manifest_permissions_(manifest_permissions),
     44       scriptable_hosts_(scriptable_hosts),
     45       should_warn_all_hosts_(UNINITIALIZED) {
     46   AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
     47   InitImplicitPermissions();
     48   InitEffectiveHosts();
     49 }
     50 
     51 // static
     52 PermissionSet* PermissionSet::CreateDifference(
     53     const PermissionSet* set1,
     54     const PermissionSet* set2) {
     55   scoped_refptr<PermissionSet> empty = new PermissionSet();
     56   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
     57   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
     58 
     59   APIPermissionSet apis;
     60   APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
     61 
     62   ManifestPermissionSet manifest_permissions;
     63   ManifestPermissionSet::Difference(set1_safe->manifest_permissions(),
     64                                     set2_safe->manifest_permissions(),
     65                                     &manifest_permissions);
     66 
     67   URLPatternSet explicit_hosts;
     68   URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
     69                                   set2_safe->explicit_hosts(),
     70                                   &explicit_hosts);
     71 
     72   URLPatternSet scriptable_hosts;
     73   URLPatternSet::CreateDifference(set1_safe->scriptable_hosts(),
     74                                   set2_safe->scriptable_hosts(),
     75                                   &scriptable_hosts);
     76 
     77   return new PermissionSet(apis, manifest_permissions,
     78                            explicit_hosts, scriptable_hosts);
     79 }
     80 
     81 // static
     82 PermissionSet* PermissionSet::CreateIntersection(
     83     const PermissionSet* set1,
     84     const PermissionSet* set2) {
     85   scoped_refptr<PermissionSet> empty = new PermissionSet();
     86   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
     87   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
     88 
     89   APIPermissionSet apis;
     90   APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
     91 
     92   ManifestPermissionSet manifest_permissions;
     93   ManifestPermissionSet::Intersection(set1_safe->manifest_permissions(),
     94                                       set2_safe->manifest_permissions(),
     95                                       &manifest_permissions);
     96 
     97   URLPatternSet explicit_hosts;
     98   URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
     99                                     set2_safe->explicit_hosts(),
    100                                     &explicit_hosts);
    101 
    102   URLPatternSet scriptable_hosts;
    103   URLPatternSet::CreateIntersection(set1_safe->scriptable_hosts(),
    104                                     set2_safe->scriptable_hosts(),
    105                                     &scriptable_hosts);
    106 
    107   return new PermissionSet(apis, manifest_permissions,
    108                            explicit_hosts, scriptable_hosts);
    109 }
    110 
    111 // static
    112 PermissionSet* PermissionSet::CreateUnion(
    113     const PermissionSet* set1,
    114     const PermissionSet* set2) {
    115   scoped_refptr<PermissionSet> empty = new PermissionSet();
    116   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
    117   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
    118 
    119   APIPermissionSet apis;
    120   APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
    121 
    122   ManifestPermissionSet manifest_permissions;
    123   ManifestPermissionSet::Union(set1_safe->manifest_permissions(),
    124                                set2_safe->manifest_permissions(),
    125                                &manifest_permissions);
    126 
    127   URLPatternSet explicit_hosts;
    128   URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
    129                              set2_safe->explicit_hosts(),
    130                              &explicit_hosts);
    131 
    132   URLPatternSet scriptable_hosts;
    133   URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
    134                              set2_safe->scriptable_hosts(),
    135                              &scriptable_hosts);
    136 
    137   return new PermissionSet(apis, manifest_permissions,
    138                            explicit_hosts, scriptable_hosts);
    139 }
    140 
    141 bool PermissionSet::operator==(
    142     const PermissionSet& rhs) const {
    143   return apis_ == rhs.apis_ &&
    144       manifest_permissions_ == rhs.manifest_permissions_ &&
    145       scriptable_hosts_ == rhs.scriptable_hosts_ &&
    146       explicit_hosts_ == rhs.explicit_hosts_;
    147 }
    148 
    149 bool PermissionSet::Contains(const PermissionSet& set) const {
    150   return apis_.Contains(set.apis()) &&
    151          manifest_permissions_.Contains(set.manifest_permissions()) &&
    152          explicit_hosts().Contains(set.explicit_hosts()) &&
    153          scriptable_hosts().Contains(set.scriptable_hosts());
    154 }
    155 
    156 std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
    157   std::set<std::string> apis_str;
    158   for (APIPermissionSet::const_iterator i = apis_.begin();
    159        i != apis_.end(); ++i) {
    160     apis_str.insert(i->name());
    161   }
    162   return apis_str;
    163 }
    164 
    165 bool PermissionSet::IsEmpty() const {
    166   // Not default if any host permissions are present.
    167   if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
    168     return false;
    169 
    170   // Or if it has no api permissions.
    171   return apis().empty() && manifest_permissions().empty();
    172 }
    173 
    174 bool PermissionSet::HasAPIPermission(
    175     APIPermission::ID id) const {
    176   return apis().find(id) != apis().end();
    177 }
    178 
    179 bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
    180   const APIPermissionInfo* permission =
    181       PermissionsInfo::GetInstance()->GetByName(permission_name);
    182   // Ensure our PermissionsProvider is aware of this permission.
    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   if (effective_hosts().MatchesAllURLs())
    218     return true;
    219 
    220   for (APIPermissionSet::const_iterator i = apis().begin();
    221        i != apis().end(); ++i) {
    222     if (i->info()->implies_full_url_access())
    223       return true;
    224   }
    225   return false;
    226 }
    227 
    228 bool PermissionSet::ShouldWarnAllHosts() const {
    229   if (should_warn_all_hosts_ == UNINITIALIZED)
    230     InitShouldWarnAllHosts();
    231   return should_warn_all_hosts_ == WARN_ALL_HOSTS;
    232 }
    233 
    234 bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
    235   return effective_hosts().MatchesURL(url);
    236 }
    237 
    238 bool PermissionSet::HasEffectiveFullAccess() const {
    239   for (APIPermissionSet::const_iterator i = apis().begin();
    240        i != apis().end(); ++i) {
    241     if (i->info()->implies_full_access())
    242       return true;
    243   }
    244   return false;
    245 }
    246 
    247 PermissionSet::~PermissionSet() {}
    248 
    249 void PermissionSet::InitImplicitPermissions() {
    250   // The downloads permission implies the internal version as well.
    251   if (apis_.find(APIPermission::kDownloads) != apis_.end())
    252     apis_.insert(APIPermission::kDownloadsInternal);
    253 
    254   // The fileBrowserHandler permission implies the internal version as well.
    255   if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
    256     apis_.insert(APIPermission::kFileBrowserHandlerInternal);
    257 }
    258 
    259 void PermissionSet::InitEffectiveHosts() {
    260   effective_hosts_.ClearPatterns();
    261 
    262   URLPatternSet::CreateUnion(
    263       explicit_hosts(), scriptable_hosts(), &effective_hosts_);
    264 }
    265 
    266 void PermissionSet::InitShouldWarnAllHosts() const {
    267   if (HasEffectiveAccessToAllHosts()) {
    268     should_warn_all_hosts_ = WARN_ALL_HOSTS;
    269     return;
    270   }
    271 
    272   for (URLPatternSet::const_iterator iter = effective_hosts_.begin();
    273        iter != effective_hosts_.end();
    274        ++iter) {
    275     if (iter->ImpliesAllHosts()) {
    276       should_warn_all_hosts_ = WARN_ALL_HOSTS;
    277       return;
    278     }
    279   }
    280 
    281   should_warn_all_hosts_ = DONT_WARN_ALL_HOSTS;
    282 }
    283 
    284 }  // namespace extensions
    285