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 "base/stl_util.h"
8 #include "chrome/common/extensions/permissions/permission_message_util.h"
9 #include "extensions/common/extensions_client.h"
10 #include "extensions/common/permissions/permission_message.h"
11 #include "extensions/common/permissions/permission_set.h"
12 #include "extensions/common/url_pattern_set.h"
13 #include "grit/generated_resources.h"
14 #include "ui/base/l10n/l10n_util.h"
16 namespace extensions {
18 ChromePermissionMessageProvider::ChromePermissionMessageProvider() {
21 ChromePermissionMessageProvider::~ChromePermissionMessageProvider() {
25 PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
26 const PermissionSet* permissions,
27 Manifest::Type extension_type) const {
28 PermissionMessages messages;
30 if (permissions->HasEffectiveFullAccess()) {
31 messages.push_back(PermissionMessage(
32 PermissionMessage::kFullAccess,
33 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
37 std::set<PermissionMessage> host_msgs =
38 GetHostPermissionMessages(permissions, extension_type);
39 std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(permissions);
40 messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
41 messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
47 std::vector<string16> ChromePermissionMessageProvider::GetWarningMessages(
48 const PermissionSet* permissions,
49 Manifest::Type extension_type) const {
50 std::vector<string16> message_strings;
51 PermissionMessages messages =
52 GetPermissionMessages(permissions, extension_type);
54 bool audio_capture = false;
55 bool video_capture = false;
56 bool media_galleries_read = false;
57 bool media_galleries_copy_to = false;
58 for (PermissionMessages::const_iterator i = messages.begin();
59 i != messages.end(); ++i) {
61 case PermissionMessage::kAudioCapture:
64 case PermissionMessage::kVideoCapture:
67 case PermissionMessage::kMediaGalleriesAllGalleriesRead:
68 media_galleries_read = true;
70 case PermissionMessage::kMediaGalleriesAllGalleriesCopyTo:
71 media_galleries_copy_to = true;
78 for (PermissionMessages::const_iterator i = messages.begin();
79 i != messages.end(); ++i) {
81 if (audio_capture && video_capture) {
82 if (id == PermissionMessage::kAudioCapture) {
83 message_strings.push_back(l10n_util::GetStringUTF16(
84 IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE));
86 } else if (id == PermissionMessage::kVideoCapture) {
87 // The combined message will be pushed above.
91 if (media_galleries_read && media_galleries_copy_to) {
92 if (id == PermissionMessage::kMediaGalleriesAllGalleriesRead) {
93 message_strings.push_back(l10n_util::GetStringUTF16(
94 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE));
96 } else if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo) {
97 // The combined message will be pushed above.
102 message_strings.push_back(i->message());
105 return message_strings;
109 std::vector<string16>
110 ChromePermissionMessageProvider::GetWarningMessagesDetails(
111 const PermissionSet* permissions,
112 Manifest::Type extension_type) const {
113 std::vector<string16> message_strings;
114 PermissionMessages messages =
115 GetPermissionMessages(permissions, extension_type);
117 for (PermissionMessages::const_iterator i = messages.begin();
118 i != messages.end(); ++i)
119 message_strings.push_back(i->details());
121 return message_strings;
125 bool ChromePermissionMessageProvider::IsPrivilegeIncrease(
126 const PermissionSet* old_permissions,
127 const PermissionSet* new_permissions,
128 Manifest::Type extension_type) const {
129 // Things can't get worse than native code access.
130 if (old_permissions->HasEffectiveFullAccess())
133 // Otherwise, it's a privilege increase if the new one has full access.
134 if (new_permissions->HasEffectiveFullAccess())
137 if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type))
140 if (IsAPIPrivilegeIncrease(old_permissions, new_permissions))
146 std::set<PermissionMessage>
147 ChromePermissionMessageProvider::GetAPIPermissionMessages(
148 const PermissionSet* permissions) const {
149 std::set<PermissionMessage> messages;
150 for (APIPermissionSet::const_iterator permission_it =
151 permissions->apis().begin();
152 permission_it != permissions->apis().end(); ++permission_it) {
153 if (permission_it->HasMessages()) {
154 PermissionMessages new_messages = permission_it->GetMessages();
155 messages.insert(new_messages.begin(), new_messages.end());
159 // A special hack: If kFileSystemWriteDirectory would be displayed, hide
160 // kFileSystemDirectory and and kFileSystemWrite as the write directory
161 // message implies the other two.
162 // TODO(sammc): Remove this. See http://crbug.com/284849.
163 std::set<PermissionMessage>::iterator write_directory_message =
164 messages.find(PermissionMessage(
165 PermissionMessage::kFileSystemWriteDirectory, string16()));
166 if (write_directory_message != messages.end()) {
168 PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
170 PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
173 // A special hack: The warning message for declarativeWebRequest
174 // permissions speaks about blocking parts of pages, which is a
175 // subset of what the "<all_urls>" access allows. Therefore we
176 // display only the "<all_urls>" warning message if both permissions
178 if (permissions->HasEffectiveAccessToAllHosts()) {
181 PermissionMessage::kDeclarativeWebRequest, string16()));
187 std::set<PermissionMessage>
188 ChromePermissionMessageProvider::GetHostPermissionMessages(
189 const PermissionSet* permissions,
190 Manifest::Type extension_type) const {
191 std::set<PermissionMessage> messages;
192 // Since platform apps always use isolated storage, they can't (silently)
193 // access user data on other domains, so there's no need to prompt.
194 // Note: this must remain consistent with IsHostPrivilegeIncrease.
195 // See crbug.com/255229.
196 if (extension_type == Manifest::TYPE_PLATFORM_APP)
199 if (permissions->HasEffectiveAccessToAllHosts()) {
200 messages.insert(PermissionMessage(
201 PermissionMessage::kHostsAll,
202 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
204 URLPatternSet regular_hosts;
205 ExtensionsClient::Get()->FilterHostPermissions(
206 permissions->effective_hosts(), ®ular_hosts, &messages);
208 std::set<std::string> hosts =
209 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
211 messages.insert(permission_message_util::CreateFromHostList(hosts));
216 bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease(
217 const PermissionSet* old_permissions,
218 const PermissionSet* new_permissions) const {
219 if (new_permissions == NULL)
222 typedef std::set<PermissionMessage> PermissionMsgSet;
223 PermissionMsgSet old_warnings = GetAPIPermissionMessages(old_permissions);
224 PermissionMsgSet new_warnings = GetAPIPermissionMessages(new_permissions);
225 PermissionMsgSet delta_warnings =
226 base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings);
228 // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
230 // TODO(sammc): Remove this. See http://crbug.com/284849.
231 if (old_warnings.find(PermissionMessage(
232 PermissionMessage::kFileSystemWriteDirectory, string16())) !=
233 old_warnings.end()) {
234 delta_warnings.erase(
235 PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
236 delta_warnings.erase(
237 PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
240 // We have less privileges if there are additional warnings present.
241 return !delta_warnings.empty();
244 bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease(
245 const PermissionSet* old_permissions,
246 const PermissionSet* new_permissions,
247 Manifest::Type extension_type) const {
248 // Platform apps host permission changes do not count as privilege increases.
249 // Note: this must remain consistent with GetHostPermissionMessages.
250 if (extension_type == Manifest::TYPE_PLATFORM_APP)
253 // If the old permission set can access any host, then it can't be elevated.
254 if (old_permissions->HasEffectiveAccessToAllHosts())
257 // Likewise, if the new permission set has full host access, then it must be
258 // a privilege increase.
259 if (new_permissions->HasEffectiveAccessToAllHosts())
262 const URLPatternSet& old_list = old_permissions->effective_hosts();
263 const URLPatternSet& new_list = new_permissions->effective_hosts();
265 // TODO(jstritar): This is overly conservative with respect to subdomains.
266 // For example, going from *.google.com to www.google.com will be
267 // considered an elevation, even though it is not (http://crbug.com/65337).
268 std::set<std::string> new_hosts_set(
269 permission_message_util::GetDistinctHosts(new_list, false, false));
270 std::set<std::string> old_hosts_set(
271 permission_message_util::GetDistinctHosts(old_list, false, false));
272 std::set<std::string> new_hosts_only =
273 base::STLSetDifference<std::set<std::string> >(new_hosts_set,
276 return !new_hosts_only.empty();
279 } // namespace extensions