cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / common / extensions / permissions / chrome_permission_message_provider.cc
blob3261efd41119302691f37dfc04686e5c69b31600
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.
5 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
7 #include <vector>
9 #include "base/metrics/field_trial.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/common/extensions/permissions/chrome_permission_message_rules.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "extensions/common/extensions_client.h"
16 #include "extensions/common/permissions/permission_message_util.h"
17 #include "extensions/common/permissions/permission_set.h"
18 #include "extensions/common/url_pattern.h"
19 #include "extensions/common/url_pattern_set.h"
20 #include "grit/extensions_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "url/gurl.h"
24 namespace extensions {
26 namespace {
28 // Copyable wrapper to make PermissionMessages comparable.
29 class ComparablePermission {
30 public:
31 explicit ComparablePermission(const PermissionMessage& msg) : msg_(&msg) {}
33 bool operator<(const ComparablePermission& rhs) const {
34 if (msg_->message() < rhs.msg_->message())
35 return true;
36 if (msg_->message() > rhs.msg_->message())
37 return false;
38 return msg_->submessages() < rhs.msg_->submessages();
41 private:
42 const PermissionMessage* msg_;
44 using ComparablePermissions = std::vector<ComparablePermission>;
46 } // namespace
48 typedef std::set<PermissionMessage> PermissionMsgSet;
50 ChromePermissionMessageProvider::ChromePermissionMessageProvider() {
53 ChromePermissionMessageProvider::~ChromePermissionMessageProvider() {
56 PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
57 const PermissionIDSet& permissions) const {
58 std::vector<ChromePermissionMessageRule> rules =
59 ChromePermissionMessageRule::GetAllRules();
61 // Apply each of the rules, in order, to generate the messages for the given
62 // permissions. Once a permission is used in a rule, remove it from the set
63 // of available permissions so it cannot be applied to subsequent rules.
64 PermissionIDSet remaining_permissions = permissions;
65 PermissionMessages messages;
66 for (const auto& rule : rules) {
67 // Only apply the rule if we have all the required permission IDs.
68 if (remaining_permissions.ContainsAllIDs(rule.required_permissions())) {
69 // We can apply the rule. Add all the required permissions, and as many
70 // optional permissions as we can, to the new message.
71 PermissionIDSet used_permissions =
72 remaining_permissions.GetAllPermissionsWithIDs(
73 rule.all_permissions());
74 messages.push_back(rule.GetPermissionMessage(used_permissions));
76 remaining_permissions =
77 PermissionIDSet::Difference(remaining_permissions, used_permissions);
81 return messages;
84 bool ChromePermissionMessageProvider::IsPrivilegeIncrease(
85 const PermissionSet* old_permissions,
86 const PermissionSet* new_permissions,
87 Manifest::Type extension_type) const {
88 // Things can't get worse than native code access.
89 if (old_permissions->HasEffectiveFullAccess())
90 return false;
92 // Otherwise, it's a privilege increase if the new one has full access.
93 if (new_permissions->HasEffectiveFullAccess())
94 return true;
96 if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type))
97 return true;
99 if (IsAPIOrManifestPrivilegeIncrease(old_permissions, new_permissions))
100 return true;
102 return false;
105 PermissionIDSet ChromePermissionMessageProvider::GetAllPermissionIDs(
106 const PermissionSet* permissions,
107 Manifest::Type extension_type) const {
108 PermissionIDSet permission_ids;
109 AddAPIPermissions(permissions, &permission_ids);
110 AddManifestPermissions(permissions, &permission_ids);
111 AddHostPermissions(permissions, &permission_ids, extension_type);
112 return permission_ids;
115 void ChromePermissionMessageProvider::AddAPIPermissions(
116 const PermissionSet* permissions,
117 PermissionIDSet* permission_ids) const {
118 for (const APIPermission* permission : permissions->apis())
119 permission_ids->InsertAll(permission->GetPermissions());
121 // A special hack: The warning message for declarativeWebRequest
122 // permissions speaks about blocking parts of pages, which is a
123 // subset of what the "<all_urls>" access allows. Therefore we
124 // display only the "<all_urls>" warning message if both permissions
125 // are required.
126 // TODO(treib): The same should apply to other permissions that are implied by
127 // "<all_urls>" (aka APIPermission::kHostsAll), such as kTab. This would
128 // happen automatically if we didn't differentiate between API/Manifest/Host
129 // permissions here.
130 if (permissions->ShouldWarnAllHosts())
131 permission_ids->erase(APIPermission::kDeclarativeWebRequest);
134 void ChromePermissionMessageProvider::AddManifestPermissions(
135 const PermissionSet* permissions,
136 PermissionIDSet* permission_ids) const {
137 for (const ManifestPermission* p : permissions->manifest_permissions())
138 permission_ids->InsertAll(p->GetPermissions());
141 void ChromePermissionMessageProvider::AddHostPermissions(
142 const PermissionSet* permissions,
143 PermissionIDSet* permission_ids,
144 Manifest::Type extension_type) const {
145 // Since platform apps always use isolated storage, they can't (silently)
146 // access user data on other domains, so there's no need to prompt.
147 // Note: this must remain consistent with IsHostPrivilegeIncrease.
148 // See crbug.com/255229.
149 if (extension_type == Manifest::TYPE_PLATFORM_APP)
150 return;
152 if (permissions->ShouldWarnAllHosts()) {
153 permission_ids->insert(APIPermission::kHostsAll);
154 } else {
155 URLPatternSet regular_hosts;
156 ExtensionsClient::Get()->FilterHostPermissions(
157 permissions->effective_hosts(), &regular_hosts, permission_ids);
159 std::set<std::string> hosts =
160 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
161 if (!hosts.empty()) {
162 permission_message_util::AddHostPermissions(
163 permission_ids, hosts, permission_message_util::kReadWrite);
168 bool ChromePermissionMessageProvider::IsAPIOrManifestPrivilegeIncrease(
169 const PermissionSet* old_permissions,
170 const PermissionSet* new_permissions) const {
171 PermissionIDSet old_ids;
172 AddAPIPermissions(old_permissions, &old_ids);
173 AddManifestPermissions(old_permissions, &old_ids);
174 PermissionIDSet new_ids;
175 AddAPIPermissions(new_permissions, &new_ids);
176 AddManifestPermissions(new_permissions, &new_ids);
178 // If all the IDs were already there, it's not a privilege increase.
179 if (old_ids.Includes(new_ids))
180 return false;
182 // Otherwise, check the actual messages - not all IDs result in a message,
183 // and some messages can suppress others.
184 PermissionMessages old_messages = GetPermissionMessages(old_ids);
185 PermissionMessages new_messages = GetPermissionMessages(new_ids);
187 ComparablePermissions old_strings(old_messages.begin(), old_messages.end());
188 ComparablePermissions new_strings(new_messages.begin(), new_messages.end());
190 std::sort(old_strings.begin(), old_strings.end());
191 std::sort(new_strings.begin(), new_strings.end());
193 return !base::STLIncludes(old_strings, new_strings);
196 bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease(
197 const PermissionSet* old_permissions,
198 const PermissionSet* new_permissions,
199 Manifest::Type extension_type) const {
200 // Platform apps host permission changes do not count as privilege increases.
201 // Note: this must remain consistent with AddHostPermissions.
202 if (extension_type == Manifest::TYPE_PLATFORM_APP)
203 return false;
205 // If the old permission set can access any host, then it can't be elevated.
206 if (old_permissions->HasEffectiveAccessToAllHosts())
207 return false;
209 // Likewise, if the new permission set has full host access, then it must be
210 // a privilege increase.
211 if (new_permissions->HasEffectiveAccessToAllHosts())
212 return true;
214 const URLPatternSet& old_list = old_permissions->effective_hosts();
215 const URLPatternSet& new_list = new_permissions->effective_hosts();
217 // TODO(jstritar): This is overly conservative with respect to subdomains.
218 // For example, going from *.google.com to www.google.com will be
219 // considered an elevation, even though it is not (http://crbug.com/65337).
220 std::set<std::string> new_hosts_set(
221 permission_message_util::GetDistinctHosts(new_list, false, false));
222 std::set<std::string> old_hosts_set(
223 permission_message_util::GetDistinctHosts(old_list, false, false));
224 std::set<std::string> new_hosts_only =
225 base::STLSetDifference<std::set<std::string> >(new_hosts_set,
226 old_hosts_set);
228 return !new_hosts_only.empty();
231 } // namespace extensions