• 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 "base/strings/stringprintf.h"
12 #include "extensions/common/permissions/permissions_info.h"
13 #include "extensions/common/url_pattern.h"
14 #include "extensions/common/url_pattern_set.h"
15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
16 #include "url/gurl.h"
17 
18 namespace extensions {
19 
20 namespace {
21 
AddPatternsAndRemovePaths(const URLPatternSet & set,URLPatternSet * out)22 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
23   DCHECK(out);
24   for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
25     URLPattern p = *i;
26     p.SetPath("/*");
27     out->AddPattern(p);
28   }
29 }
30 
31 }  // namespace
32 
33 //
34 // PermissionSet
35 //
36 
PermissionSet()37 PermissionSet::PermissionSet() : should_warn_all_hosts_(UNINITIALIZED) {}
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       should_warn_all_hosts_(UNINITIALIZED) {
48   AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
49   InitImplicitPermissions();
50   InitEffectiveHosts();
51 }
52 
53 // static
CreateDifference(const PermissionSet * set1,const PermissionSet * set2)54 PermissionSet* PermissionSet::CreateDifference(
55     const PermissionSet* set1,
56     const PermissionSet* set2) {
57   scoped_refptr<PermissionSet> empty = new PermissionSet();
58   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
59   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
60 
61   APIPermissionSet apis;
62   APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
63 
64   ManifestPermissionSet manifest_permissions;
65   ManifestPermissionSet::Difference(set1_safe->manifest_permissions(),
66                                     set2_safe->manifest_permissions(),
67                                     &manifest_permissions);
68 
69   URLPatternSet explicit_hosts;
70   URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
71                                   set2_safe->explicit_hosts(),
72                                   &explicit_hosts);
73 
74   URLPatternSet scriptable_hosts;
75   URLPatternSet::CreateDifference(set1_safe->scriptable_hosts(),
76                                   set2_safe->scriptable_hosts(),
77                                   &scriptable_hosts);
78 
79   return new PermissionSet(apis, manifest_permissions,
80                            explicit_hosts, scriptable_hosts);
81 }
82 
83 // static
CreateIntersection(const PermissionSet * set1,const PermissionSet * set2)84 PermissionSet* PermissionSet::CreateIntersection(
85     const PermissionSet* set1,
86     const PermissionSet* set2) {
87   scoped_refptr<PermissionSet> empty = new PermissionSet();
88   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
89   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
90 
91   APIPermissionSet apis;
92   APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
93 
94   ManifestPermissionSet manifest_permissions;
95   ManifestPermissionSet::Intersection(set1_safe->manifest_permissions(),
96                                       set2_safe->manifest_permissions(),
97                                       &manifest_permissions);
98 
99   URLPatternSet explicit_hosts;
100   URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
101                                     set2_safe->explicit_hosts(),
102                                     &explicit_hosts);
103 
104   URLPatternSet scriptable_hosts;
105   URLPatternSet::CreateIntersection(set1_safe->scriptable_hosts(),
106                                     set2_safe->scriptable_hosts(),
107                                     &scriptable_hosts);
108 
109   return new PermissionSet(apis, manifest_permissions,
110                            explicit_hosts, scriptable_hosts);
111 }
112 
113 // static
CreateUnion(const PermissionSet * set1,const PermissionSet * set2)114 PermissionSet* PermissionSet::CreateUnion(
115     const PermissionSet* set1,
116     const PermissionSet* set2) {
117   scoped_refptr<PermissionSet> empty = new PermissionSet();
118   const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
119   const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
120 
121   APIPermissionSet apis;
122   APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
123 
124   ManifestPermissionSet manifest_permissions;
125   ManifestPermissionSet::Union(set1_safe->manifest_permissions(),
126                                set2_safe->manifest_permissions(),
127                                &manifest_permissions);
128 
129   URLPatternSet explicit_hosts;
130   URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
131                              set2_safe->explicit_hosts(),
132                              &explicit_hosts);
133 
134   URLPatternSet scriptable_hosts;
135   URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
136                              set2_safe->scriptable_hosts(),
137                              &scriptable_hosts);
138 
139   return new PermissionSet(apis, manifest_permissions,
140                            explicit_hosts, scriptable_hosts);
141 }
142 
operator ==(const PermissionSet & rhs) const143 bool PermissionSet::operator==(
144     const PermissionSet& rhs) const {
145   return apis_ == rhs.apis_ &&
146       manifest_permissions_ == rhs.manifest_permissions_ &&
147       scriptable_hosts_ == rhs.scriptable_hosts_ &&
148       explicit_hosts_ == rhs.explicit_hosts_;
149 }
150 
Contains(const PermissionSet & set) const151 bool PermissionSet::Contains(const PermissionSet& set) const {
152   return apis_.Contains(set.apis()) &&
153          manifest_permissions_.Contains(set.manifest_permissions()) &&
154          explicit_hosts().Contains(set.explicit_hosts()) &&
155          scriptable_hosts().Contains(set.scriptable_hosts());
156 }
157 
GetAPIsAsStrings() const158 std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
159   std::set<std::string> apis_str;
160   for (APIPermissionSet::const_iterator i = apis_.begin();
161        i != apis_.end(); ++i) {
162     apis_str.insert(i->name());
163   }
164   return apis_str;
165 }
166 
IsEmpty() const167 bool PermissionSet::IsEmpty() const {
168   // Not default if any host permissions are present.
169   if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
170     return false;
171 
172   // Or if it has no api permissions.
173   return apis().empty() && manifest_permissions().empty();
174 }
175 
HasAPIPermission(APIPermission::ID id) const176 bool PermissionSet::HasAPIPermission(
177     APIPermission::ID id) const {
178   return apis().find(id) != apis().end();
179 }
180 
HasAPIPermission(const std::string & permission_name) const181 bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
182   const APIPermissionInfo* permission =
183       PermissionsInfo::GetInstance()->GetByName(permission_name);
184   // Ensure our PermissionsProvider is aware of this permission.
185   CHECK(permission) << permission_name;
186   return (permission && apis_.count(permission->id()));
187 }
188 
CheckAPIPermission(APIPermission::ID permission) const189 bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
190   return CheckAPIPermissionWithParam(permission, NULL);
191 }
192 
CheckAPIPermissionWithParam(APIPermission::ID permission,const APIPermission::CheckParam * param) const193 bool PermissionSet::CheckAPIPermissionWithParam(
194     APIPermission::ID permission,
195     const APIPermission::CheckParam* param) const {
196   APIPermissionSet::const_iterator iter = apis().find(permission);
197   if (iter == apis().end())
198     return false;
199   return iter->Check(param);
200 }
201 
HasExplicitAccessToOrigin(const GURL & origin) const202 bool PermissionSet::HasExplicitAccessToOrigin(
203     const GURL& origin) const {
204   return explicit_hosts().MatchesURL(origin);
205 }
206 
HasScriptableAccessToURL(const GURL & origin) const207 bool PermissionSet::HasScriptableAccessToURL(
208     const GURL& origin) const {
209   // We only need to check our host list to verify access. The host list should
210   // already reflect any special rules (such as chrome://favicon, all hosts
211   // access, etc.).
212   return scriptable_hosts().MatchesURL(origin);
213 }
214 
HasEffectiveAccessToAllHosts() const215 bool PermissionSet::HasEffectiveAccessToAllHosts() const {
216   // There are two ways this set can have effective access to all hosts:
217   //  1) it has an <all_urls> URL pattern.
218   //  2) it has a named permission with implied full URL access.
219   for (URLPatternSet::const_iterator host = effective_hosts().begin();
220        host != effective_hosts().end(); ++host) {
221     if (host->match_all_urls() ||
222         (host->match_subdomains() && host->host().empty()))
223       return true;
224   }
225 
226   for (APIPermissionSet::const_iterator i = apis().begin();
227        i != apis().end(); ++i) {
228     if (i->info()->implies_full_url_access())
229       return true;
230   }
231   return false;
232 }
233 
ShouldWarnAllHosts() const234 bool PermissionSet::ShouldWarnAllHosts() const {
235   if (should_warn_all_hosts_ == UNINITIALIZED)
236     InitShouldWarnAllHosts();
237   return should_warn_all_hosts_ == WARN_ALL_HOSTS;
238 }
239 
HasEffectiveAccessToURL(const GURL & url) const240 bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
241   return effective_hosts().MatchesURL(url);
242 }
243 
HasEffectiveFullAccess() const244 bool PermissionSet::HasEffectiveFullAccess() const {
245   for (APIPermissionSet::const_iterator i = apis().begin();
246        i != apis().end(); ++i) {
247     if (i->info()->implies_full_access())
248       return true;
249   }
250   return false;
251 }
252 
~PermissionSet()253 PermissionSet::~PermissionSet() {}
254 
InitImplicitPermissions()255 void PermissionSet::InitImplicitPermissions() {
256   // The downloads permission implies the internal version as well.
257   if (apis_.find(APIPermission::kDownloads) != apis_.end())
258     apis_.insert(APIPermission::kDownloadsInternal);
259 
260   // The fileBrowserHandler permission implies the internal version as well.
261   if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
262     apis_.insert(APIPermission::kFileBrowserHandlerInternal);
263 }
264 
InitEffectiveHosts()265 void PermissionSet::InitEffectiveHosts() {
266   effective_hosts_.ClearPatterns();
267 
268   URLPatternSet::CreateUnion(
269       explicit_hosts(), scriptable_hosts(), &effective_hosts_);
270 }
271 
InitShouldWarnAllHosts() const272 void PermissionSet::InitShouldWarnAllHosts() const {
273   if (HasEffectiveAccessToAllHosts()) {
274     should_warn_all_hosts_ = WARN_ALL_HOSTS;
275     return;
276   }
277 
278   for (URLPatternSet::const_iterator iter = effective_hosts_.begin();
279        iter != effective_hosts_.end();
280        ++iter) {
281     // If this doesn't even match subdomains, it can't possibly imply all hosts.
282     if (!iter->match_subdomains())
283       continue;
284 
285     // If iter->host() is a recognized TLD, this will be 0. We don't include
286     // private TLDs, so that, e.g., *.appspot.com does not imply all hosts.
287     size_t registry_length =
288         net::registry_controlled_domains::GetRegistryLength(
289             iter->host(),
290             net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
291             net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
292     // If there was more than just a TLD in the host (e.g., *.foobar.com), it
293     // doesn't imply all hosts.
294     if (registry_length > 0)
295       continue;
296 
297     // At this point the host could either be just a TLD ("com") or some unknown
298     // TLD-like string ("notatld"). To disambiguate between them construct a
299     // fake URL, and check the registry. This returns 0 if the TLD is
300     // unrecognized, or the length of the recognized TLD.
301     registry_length = net::registry_controlled_domains::GetRegistryLength(
302         base::StringPrintf("foo.%s", iter->host().c_str()),
303         net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
304         net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
305     // If we recognized this TLD, then this is a pattern like *.com, and it
306     // should imply all hosts.
307     if (registry_length > 0) {
308       should_warn_all_hosts_ = WARN_ALL_HOSTS;
309       return;
310     }
311   }
312 
313   should_warn_all_hosts_ = DONT_WARN_ALL_HOSTS;
314 }
315 
316 }  // namespace extensions
317