• 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 using extensions::URLPatternSet;
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 namespace extensions {
32 
33 //
34 // PermissionSet
35 //
36 
PermissionSet()37 PermissionSet::PermissionSet() {}
38 
PermissionSet(const APIPermissionSet & apis,const ManifestPermissionSet & manifest_permissions,const URLPatternSet & explicit_hosts,const URLPatternSet & scriptable_hosts)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
CreateDifference(const PermissionSet * set1,const PermissionSet * set2)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
CreateIntersection(const PermissionSet * set1,const PermissionSet * set2)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
CreateUnion(const PermissionSet * set1,const PermissionSet * set2)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 
operator ==(const PermissionSet & rhs) const142 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 
Contains(const PermissionSet & set) const150 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 
GetAPIsAsStrings() const157 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 
IsEmpty() const166 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 
HasAPIPermission(APIPermission::ID id) const175 bool PermissionSet::HasAPIPermission(
176     APIPermission::ID id) const {
177   return apis().find(id) != apis().end();
178 }
179 
HasAPIPermission(const std::string & permission_name) const180 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 
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   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 
HasEffectiveAccessToURL(const GURL & url) const232 bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
233   return effective_hosts().MatchesURL(url);
234 }
235 
HasEffectiveFullAccess() const236 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 
~PermissionSet()245 PermissionSet::~PermissionSet() {}
246 
InitImplicitPermissions()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 
InitEffectiveHosts()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