• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AddPatternsAndRemovePaths(const URLPatternSet & set,URLPatternSet * out)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 
PermissionSet()35 PermissionSet::PermissionSet() : should_warn_all_hosts_(UNINITIALIZED) {}
36 
PermissionSet(const APIPermissionSet & apis,const ManifestPermissionSet & manifest_permissions,const URLPatternSet & explicit_hosts,const URLPatternSet & scriptable_hosts)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
CreateDifference(const PermissionSet * set1,const PermissionSet * set2)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
CreateIntersection(const PermissionSet * set1,const PermissionSet * set2)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
CreateUnion(const PermissionSet * set1,const PermissionSet * set2)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 
operator ==(const PermissionSet & rhs) const141 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 
Contains(const PermissionSet & set) const149 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 
GetAPIsAsStrings() const156 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 
IsEmpty() const165 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 
HasAPIPermission(APIPermission::ID id) const174 bool PermissionSet::HasAPIPermission(
175     APIPermission::ID id) const {
176   return apis().find(id) != apis().end();
177 }
178 
HasAPIPermission(const std::string & permission_name) const179 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 
CheckAPIPermission(APIPermission::ID permission) const187 bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
188   return CheckAPIPermissionWithParam(permission, NULL);
189 }
190 
CheckAPIPermissionWithParam(APIPermission::ID permission,const APIPermission::CheckParam * param) const191 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 
HasExplicitAccessToOrigin(const GURL & origin) const200 bool PermissionSet::HasExplicitAccessToOrigin(
201     const GURL& origin) const {
202   return explicit_hosts().MatchesURL(origin);
203 }
204 
HasScriptableAccessToURL(const GURL & origin) const205 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 
HasEffectiveAccessToAllHosts() const213 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 
ShouldWarnAllHosts() const228 bool PermissionSet::ShouldWarnAllHosts() const {
229   if (should_warn_all_hosts_ == UNINITIALIZED)
230     InitShouldWarnAllHosts();
231   return should_warn_all_hosts_ == WARN_ALL_HOSTS;
232 }
233 
HasEffectiveAccessToURL(const GURL & url) const234 bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
235   return effective_hosts().MatchesURL(url);
236 }
237 
HasEffectiveFullAccess() const238 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 
~PermissionSet()247 PermissionSet::~PermissionSet() {}
248 
InitImplicitPermissions()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 
InitEffectiveHosts()259 void PermissionSet::InitEffectiveHosts() {
260   effective_hosts_.ClearPatterns();
261 
262   URLPatternSet::CreateUnion(
263       explicit_hosts(), scriptable_hosts(), &effective_hosts_);
264 }
265 
InitShouldWarnAllHosts() const266 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