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