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