Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: chrome/common/extensions/permissions/permission_set.cc

Issue 27446002: Move permission warning message handling from PermissionSet to PermissionMessageProvider. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: more better Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/permissions/permission_set.h" 5 #include "chrome/common/extensions/permissions/permission_set.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <string> 9 #include <string>
10 10
11 #include "base/stl_util.h"
12 #include "chrome/common/extensions/permissions/permission_message_util.h"
13 #include "content/public/common/url_constants.h"
14 #include "extensions/common/extensions_client.h"
15 #include "extensions/common/permissions/permissions_info.h" 11 #include "extensions/common/permissions/permissions_info.h"
16 #include "extensions/common/url_pattern.h" 12 #include "extensions/common/url_pattern.h"
17 #include "extensions/common/url_pattern_set.h" 13 #include "extensions/common/url_pattern_set.h"
18 #include "grit/generated_resources.h"
19 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "url/gurl.h" 14 #include "url/gurl.h"
22 15
23 using extensions::URLPatternSet; 16 using extensions::URLPatternSet;
24 17
25 namespace { 18 namespace {
26 19
27 // Helper for GetDistinctHosts(): com > net > org > everything else.
28 bool RcdBetterThan(const std::string& a, const std::string& b) {
29 if (a == b)
30 return false;
31 if (a == "com")
32 return true;
33 if (a == "net")
34 return b != "com";
35 if (a == "org")
36 return b != "com" && b != "net";
37 return false;
38 }
39
40 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) { 20 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
41 DCHECK(out); 21 DCHECK(out);
42 for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) { 22 for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
43 URLPattern p = *i; 23 URLPattern p = *i;
44 p.SetPath("/*"); 24 p.SetPath("/*");
45 out->AddPattern(p); 25 out->AddPattern(p);
46 } 26 }
47 } 27 }
48 28
49 } // namespace 29 } // namespace
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 134
155 std::set<std::string> PermissionSet::GetAPIsAsStrings() const { 135 std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
156 std::set<std::string> apis_str; 136 std::set<std::string> apis_str;
157 for (APIPermissionSet::const_iterator i = apis_.begin(); 137 for (APIPermissionSet::const_iterator i = apis_.begin();
158 i != apis_.end(); ++i) { 138 i != apis_.end(); ++i) {
159 apis_str.insert(i->name()); 139 apis_str.insert(i->name());
160 } 140 }
161 return apis_str; 141 return apis_str;
162 } 142 }
163 143
164 PermissionMessages PermissionSet::GetPermissionMessages(
165 Manifest::Type extension_type) const {
166 PermissionMessages messages;
167
168 if (HasEffectiveFullAccess()) {
169 messages.push_back(PermissionMessage(
170 PermissionMessage::kFullAccess,
171 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
172 return messages;
173 }
174
175 std::set<PermissionMessage> host_msgs =
176 GetHostPermissionMessages(extension_type);
177 std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages();
178 messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
179 messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
180
181 return messages;
182 }
183
184 std::vector<string16> PermissionSet::GetWarningMessages(
185 Manifest::Type extension_type) const {
186 std::vector<string16> messages;
187 PermissionMessages permissions = GetPermissionMessages(extension_type);
188
189 bool audio_capture = false;
190 bool video_capture = false;
191 bool media_galleries_read = false;
192 bool media_galleries_copy_to = false;
193 for (PermissionMessages::const_iterator i = permissions.begin();
194 i != permissions.end(); ++i) {
195 switch (i->id()) {
196 case PermissionMessage::kAudioCapture:
197 audio_capture = true;
198 break;
199 case PermissionMessage::kVideoCapture:
200 video_capture = true;
201 break;
202 case PermissionMessage::kMediaGalleriesAllGalleriesRead:
203 media_galleries_read = true;
204 break;
205 case PermissionMessage::kMediaGalleriesAllGalleriesCopyTo:
206 media_galleries_copy_to = true;
207 break;
208 default:
209 break;
210 }
211 }
212
213 for (PermissionMessages::const_iterator i = permissions.begin();
214 i != permissions.end(); ++i) {
215 int id = i->id();
216 if (audio_capture && video_capture) {
217 if (id == PermissionMessage::kAudioCapture) {
218 messages.push_back(l10n_util::GetStringUTF16(
219 IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE));
220 continue;
221 } else if (id == PermissionMessage::kVideoCapture) {
222 // The combined message will be pushed above.
223 continue;
224 }
225 }
226 if (media_galleries_read && media_galleries_copy_to) {
227 if (id == PermissionMessage::kMediaGalleriesAllGalleriesRead) {
228 messages.push_back(l10n_util::GetStringUTF16(
229 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE));
230 continue;
231 } else if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo) {
232 // The combined message will be pushed above.
233 continue;
234 }
235 }
236
237 messages.push_back(i->message());
238 }
239
240 return messages;
241 }
242
243 std::vector<string16> PermissionSet::GetWarningMessagesDetails(
244 Manifest::Type extension_type) const {
245 std::vector<string16> messages;
246 PermissionMessages permissions = GetPermissionMessages(extension_type);
247
248 for (PermissionMessages::const_iterator i = permissions.begin();
249 i != permissions.end(); ++i)
250 messages.push_back(i->details());
251
252 return messages;
253 }
254
255 bool PermissionSet::IsEmpty() const { 144 bool PermissionSet::IsEmpty() const {
256 // Not default if any host permissions are present. 145 // Not default if any host permissions are present.
257 if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty())) 146 if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
258 return false; 147 return false;
259 148
260 // Or if it has no api permissions. 149 // Or if it has no api permissions.
261 return apis().empty(); 150 return apis().empty();
262 } 151 }
263 152
264 bool PermissionSet::HasAPIPermission( 153 bool PermissionSet::HasAPIPermission(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 213
325 bool PermissionSet::HasEffectiveFullAccess() const { 214 bool PermissionSet::HasEffectiveFullAccess() const {
326 for (APIPermissionSet::const_iterator i = apis().begin(); 215 for (APIPermissionSet::const_iterator i = apis().begin();
327 i != apis().end(); ++i) { 216 i != apis().end(); ++i) {
328 if (i->info()->implies_full_access()) 217 if (i->info()->implies_full_access())
329 return true; 218 return true;
330 } 219 }
331 return false; 220 return false;
332 } 221 }
333 222
334 bool PermissionSet::HasLessPrivilegesThan(
335 const PermissionSet* permissions,
336 Manifest::Type extension_type) const {
337 // Things can't get worse than native code access.
338 if (HasEffectiveFullAccess())
339 return false;
340
341 // Otherwise, it's a privilege increase if the new one has full access.
342 if (permissions->HasEffectiveFullAccess())
343 return true;
344
345 if (HasLessHostPrivilegesThan(permissions, extension_type))
346 return true;
347
348 if (HasLessAPIPrivilegesThan(permissions))
349 return true;
350
351 return false;
352 }
353
354 PermissionSet::~PermissionSet() {} 223 PermissionSet::~PermissionSet() {}
355 224
356 // static
357 std::set<std::string> PermissionSet::GetDistinctHosts(
358 const URLPatternSet& host_patterns,
359 bool include_rcd,
360 bool exclude_file_scheme) {
361 // Use a vector to preserve order (also faster than a map on small sets).
362 // Each item is a host split into two parts: host without RCDs and
363 // current best RCD.
364 typedef std::vector<std::pair<std::string, std::string> > HostVector;
365 HostVector hosts_best_rcd;
366 for (URLPatternSet::const_iterator i = host_patterns.begin();
367 i != host_patterns.end(); ++i) {
368 if (exclude_file_scheme && i->scheme() == chrome::kFileScheme)
369 continue;
370
371 std::string host = i->host();
372
373 // Add the subdomain wildcard back to the host, if necessary.
374 if (i->match_subdomains())
375 host = "*." + host;
376
377 // If the host has an RCD, split it off so we can detect duplicates.
378 std::string rcd;
379 size_t reg_len = net::registry_controlled_domains::GetRegistryLength(
380 host,
381 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
382 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
383 if (reg_len && reg_len != std::string::npos) {
384 if (include_rcd) // else leave rcd empty
385 rcd = host.substr(host.size() - reg_len);
386 host = host.substr(0, host.size() - reg_len);
387 }
388
389 // Check if we've already seen this host.
390 HostVector::iterator it = hosts_best_rcd.begin();
391 for (; it != hosts_best_rcd.end(); ++it) {
392 if (it->first == host)
393 break;
394 }
395 // If this host was found, replace the RCD if this one is better.
396 if (it != hosts_best_rcd.end()) {
397 if (include_rcd && RcdBetterThan(rcd, it->second))
398 it->second = rcd;
399 } else { // Previously unseen host, append it.
400 hosts_best_rcd.push_back(std::make_pair(host, rcd));
401 }
402 }
403
404 // Build up the final vector by concatenating hosts and RCDs.
405 std::set<std::string> distinct_hosts;
406 for (HostVector::iterator it = hosts_best_rcd.begin();
407 it != hosts_best_rcd.end(); ++it)
408 distinct_hosts.insert(it->first + it->second);
409 return distinct_hosts;
410 }
411
412 void PermissionSet::InitImplicitPermissions() { 225 void PermissionSet::InitImplicitPermissions() {
413 // The downloads permission implies the internal version as well. 226 // The downloads permission implies the internal version as well.
414 if (apis_.find(APIPermission::kDownloads) != apis_.end()) 227 if (apis_.find(APIPermission::kDownloads) != apis_.end())
415 apis_.insert(APIPermission::kDownloadsInternal); 228 apis_.insert(APIPermission::kDownloadsInternal);
416 229
417 // TODO(fsamuel): Is there a better way to request access to the WebRequest 230 // TODO(fsamuel): Is there a better way to request access to the WebRequest
418 // API without exposing it to the Chrome App? 231 // API without exposing it to the Chrome App?
419 if (apis_.find(APIPermission::kWebView) != apis_.end()) 232 if (apis_.find(APIPermission::kWebView) != apis_.end())
420 apis_.insert(APIPermission::kWebRequestInternal); 233 apis_.insert(APIPermission::kWebRequestInternal);
421 234
422 // The webRequest permission implies the internal version as well. 235 // The webRequest permission implies the internal version as well.
423 if (apis_.find(APIPermission::kWebRequest) != apis_.end()) 236 if (apis_.find(APIPermission::kWebRequest) != apis_.end())
424 apis_.insert(APIPermission::kWebRequestInternal); 237 apis_.insert(APIPermission::kWebRequestInternal);
425 238
426 // The fileBrowserHandler permission implies the internal version as well. 239 // The fileBrowserHandler permission implies the internal version as well.
427 if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end()) 240 if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
428 apis_.insert(APIPermission::kFileBrowserHandlerInternal); 241 apis_.insert(APIPermission::kFileBrowserHandlerInternal);
429 } 242 }
430 243
431 void PermissionSet::InitEffectiveHosts() { 244 void PermissionSet::InitEffectiveHosts() {
432 effective_hosts_.ClearPatterns(); 245 effective_hosts_.ClearPatterns();
433 246
434 URLPatternSet::CreateUnion( 247 URLPatternSet::CreateUnion(
435 explicit_hosts(), scriptable_hosts(), &effective_hosts_); 248 explicit_hosts(), scriptable_hosts(), &effective_hosts_);
436 } 249 }
437 250
438 std::set<PermissionMessage> PermissionSet::GetAPIPermissionMessages() const {
439 std::set<PermissionMessage> messages;
440 for (APIPermissionSet::const_iterator permission_it = apis_.begin();
441 permission_it != apis_.end(); ++permission_it) {
442 if (permission_it->HasMessages()) {
443 PermissionMessages new_messages = permission_it->GetMessages();
444 messages.insert(new_messages.begin(), new_messages.end());
445 }
446 }
447
448 // A special hack: If kFileSystemWriteDirectory would be displayed, hide
449 // kFileSystemDirectory and and kFileSystemWrite as the write directory
450 // message implies the other two.
451 // TODO(sammc): Remove this. See http://crbug.com/284849.
452 std::set<PermissionMessage>::iterator write_directory_message =
453 messages.find(PermissionMessage(
454 PermissionMessage::kFileSystemWriteDirectory, string16()));
455 if (write_directory_message != messages.end()) {
456 messages.erase(
457 PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
458 messages.erase(
459 PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
460 }
461
462 // A special hack: The warning message for declarativeWebRequest
463 // permissions speaks about blocking parts of pages, which is a
464 // subset of what the "<all_urls>" access allows. Therefore we
465 // display only the "<all_urls>" warning message if both permissions
466 // are required.
467 if (HasEffectiveAccessToAllHosts()) {
468 messages.erase(
469 PermissionMessage(
470 PermissionMessage::kDeclarativeWebRequest, string16()));
471 }
472
473 return messages;
474 }
475
476 std::set<PermissionMessage> PermissionSet::GetHostPermissionMessages(
477 Manifest::Type extension_type) const {
478 // Since platform apps always use isolated storage, they can't (silently)
479 // access user data on other domains, so there's no need to prompt.
480 // Note: this must remain consistent with HasLessHostPrivilegesThan.
481 // See crbug.com/255229.
482 std::set<PermissionMessage> messages;
483 if (extension_type == Manifest::TYPE_PLATFORM_APP)
484 return messages;
485
486 if (HasEffectiveAccessToAllHosts()) {
487 messages.insert(PermissionMessage(
488 PermissionMessage::kHostsAll,
489 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
490 } else {
491 URLPatternSet regular_hosts;
492 ExtensionsClient::Get()->FilterHostPermissions(
493 effective_hosts_, &regular_hosts, &messages);
494
495 std::set<std::string> hosts = GetDistinctHosts(regular_hosts, true, true);
496 if (!hosts.empty())
497 messages.insert(permission_message_util::CreateFromHostList(hosts));
498 }
499 return messages;
500 }
501
502 bool PermissionSet::HasLessAPIPrivilegesThan(
503 const PermissionSet* permissions) const {
504 if (permissions == NULL)
505 return false;
506
507 typedef std::set<PermissionMessage> PermissionMsgSet;
508 PermissionMsgSet current_warnings = GetAPIPermissionMessages();
509 PermissionMsgSet new_warnings = permissions->GetAPIPermissionMessages();
510 PermissionMsgSet delta_warnings =
511 base::STLSetDifference<PermissionMsgSet>(new_warnings, current_warnings);
512
513 // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
514 // kFileSystemWrite.
515 // TODO(sammc): Remove this. See http://crbug.com/284849.
516 if (current_warnings.find(PermissionMessage(
517 PermissionMessage::kFileSystemWriteDirectory, string16())) !=
518 current_warnings.end()) {
519 delta_warnings.erase(
520 PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
521 delta_warnings.erase(
522 PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
523 }
524
525 // We have less privileges if there are additional warnings present.
526 return !delta_warnings.empty();
527 }
528
529 bool PermissionSet::HasLessHostPrivilegesThan(
530 const PermissionSet* permissions,
531 Manifest::Type extension_type) const {
532 // Platform apps host permission changes do not count as privilege increases.
533 // Note: this must remain consistent with GetHostPermissionMessages.
534 if (extension_type == Manifest::TYPE_PLATFORM_APP)
535 return false;
536
537 // If this permission set can access any host, then it can't be elevated.
538 if (HasEffectiveAccessToAllHosts())
539 return false;
540
541 // Likewise, if the other permission set has full host access, then it must be
542 // a privilege increase.
543 if (permissions->HasEffectiveAccessToAllHosts())
544 return true;
545
546 const URLPatternSet& old_list = effective_hosts();
547 const URLPatternSet& new_list = permissions->effective_hosts();
548
549 // TODO(jstritar): This is overly conservative with respect to subdomains.
550 // For example, going from *.google.com to www.google.com will be
551 // considered an elevation, even though it is not (http://crbug.com/65337).
552 std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false));
553 std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false));
554 std::set<std::string> new_hosts_only =
555 base::STLSetDifference<std::set<std::string> >(new_hosts_set,
556 old_hosts_set);
557
558 return !new_hosts_only.empty();
559 }
560
561 } // namespace extensions 251 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698