Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / permissions / chrome_permission_message_provider.cc
blob94cb2c4eeb9a8477ff03f0d55291c74c151e6029
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 namespace {
20 PermissionMessages::iterator FindMessageByID(PermissionMessages& messages,
21 int id) {
22 for (PermissionMessages::iterator it = messages.begin();
23 it != messages.end(); ++it) {
24 if (it->id() == id)
25 return it;
28 return messages.end();
31 } // namespace
33 ChromePermissionMessageProvider::ChromePermissionMessageProvider() {
36 ChromePermissionMessageProvider::~ChromePermissionMessageProvider() {
39 // static
40 PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
41 const PermissionSet* permissions,
42 Manifest::Type extension_type) const {
43 PermissionMessages messages;
45 if (permissions->HasEffectiveFullAccess()) {
46 messages.push_back(PermissionMessage(
47 PermissionMessage::kFullAccess,
48 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
49 return messages;
52 std::set<PermissionMessage> host_msgs =
53 GetHostPermissionMessages(permissions, extension_type);
54 std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(permissions);
55 std::set<PermissionMessage> manifest_permission_msgs =
56 GetManifestPermissionMessages(permissions);
57 messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
58 messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
59 messages.insert(messages.end(), manifest_permission_msgs.begin(),
60 manifest_permission_msgs.end());
62 // Special hack: bookmarks permission message supersedes override bookmarks UI
63 // permission message if both permissions are specified.
64 PermissionMessages::iterator override_bookmarks_ui =
65 FindMessageByID(messages, PermissionMessage::kOverrideBookmarksUI);
66 if (override_bookmarks_ui != messages.end() &&
67 FindMessageByID(messages, PermissionMessage::kBookmarks) !=
68 messages.end()) {
69 messages.erase(override_bookmarks_ui);
72 return messages;
75 // static
76 std::vector<base::string16> ChromePermissionMessageProvider::GetWarningMessages(
77 const PermissionSet* permissions,
78 Manifest::Type extension_type) const {
79 std::vector<base::string16> message_strings;
80 PermissionMessages messages =
81 GetPermissionMessages(permissions, extension_type);
83 bool audio_capture = false;
84 bool video_capture = false;
85 bool media_galleries_read = false;
86 bool media_galleries_copy_to = false;
87 bool media_galleries_delete = false;
88 for (PermissionMessages::const_iterator i = messages.begin();
89 i != messages.end(); ++i) {
90 switch (i->id()) {
91 case PermissionMessage::kAudioCapture:
92 audio_capture = true;
93 break;
94 case PermissionMessage::kVideoCapture:
95 video_capture = true;
96 break;
97 case PermissionMessage::kMediaGalleriesAllGalleriesRead:
98 media_galleries_read = true;
99 break;
100 case PermissionMessage::kMediaGalleriesAllGalleriesCopyTo:
101 media_galleries_copy_to = true;
102 break;
103 case PermissionMessage::kMediaGalleriesAllGalleriesDelete:
104 media_galleries_delete = true;
105 break;
106 default:
107 break;
111 for (PermissionMessages::const_iterator i = messages.begin();
112 i != messages.end(); ++i) {
113 int id = i->id();
114 if (audio_capture && video_capture) {
115 if (id == PermissionMessage::kAudioCapture) {
116 message_strings.push_back(l10n_util::GetStringUTF16(
117 IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE));
118 continue;
119 } else if (id == PermissionMessage::kVideoCapture) {
120 // The combined message will be pushed above.
121 continue;
124 if (media_galleries_read &&
125 (media_galleries_copy_to || media_galleries_delete)) {
126 if (id == PermissionMessage::kMediaGalleriesAllGalleriesRead) {
127 int m_id = media_galleries_copy_to ?
128 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE :
129 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_DELETE;
130 message_strings.push_back(l10n_util::GetStringUTF16(m_id));
131 continue;
132 } else if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo ||
133 id == PermissionMessage::kMediaGalleriesAllGalleriesDelete) {
134 // The combined message will be pushed above.
135 continue;
139 message_strings.push_back(i->message());
142 return message_strings;
145 // static
146 std::vector<base::string16>
147 ChromePermissionMessageProvider::GetWarningMessagesDetails(
148 const PermissionSet* permissions,
149 Manifest::Type extension_type) const {
150 std::vector<base::string16> message_strings;
151 PermissionMessages messages =
152 GetPermissionMessages(permissions, extension_type);
154 for (PermissionMessages::const_iterator i = messages.begin();
155 i != messages.end(); ++i)
156 message_strings.push_back(i->details());
158 return message_strings;
161 // static
162 bool ChromePermissionMessageProvider::IsPrivilegeIncrease(
163 const PermissionSet* old_permissions,
164 const PermissionSet* new_permissions,
165 Manifest::Type extension_type) const {
166 // Things can't get worse than native code access.
167 if (old_permissions->HasEffectiveFullAccess())
168 return false;
170 // Otherwise, it's a privilege increase if the new one has full access.
171 if (new_permissions->HasEffectiveFullAccess())
172 return true;
174 if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type))
175 return true;
177 if (IsAPIPrivilegeIncrease(old_permissions, new_permissions))
178 return true;
180 if (IsManifestPermissionPrivilegeIncrease(old_permissions, new_permissions))
181 return true;
183 return false;
186 std::set<PermissionMessage>
187 ChromePermissionMessageProvider::GetAPIPermissionMessages(
188 const PermissionSet* permissions) const {
189 std::set<PermissionMessage> messages;
190 for (APIPermissionSet::const_iterator permission_it =
191 permissions->apis().begin();
192 permission_it != permissions->apis().end(); ++permission_it) {
193 if (permission_it->HasMessages()) {
194 PermissionMessages new_messages = permission_it->GetMessages();
195 messages.insert(new_messages.begin(), new_messages.end());
199 // A special hack: If kFileSystemWriteDirectory would be displayed, hide
200 // kFileSystemDirectory and and kFileSystemWrite as the write directory
201 // message implies the other two.
202 // TODO(sammc): Remove this. See http://crbug.com/284849.
203 std::set<PermissionMessage>::iterator write_directory_message =
204 messages.find(PermissionMessage(
205 PermissionMessage::kFileSystemWriteDirectory, base::string16()));
206 if (write_directory_message != messages.end()) {
207 messages.erase(
208 PermissionMessage(PermissionMessage::kFileSystemWrite,
209 base::string16()));
210 messages.erase(
211 PermissionMessage(PermissionMessage::kFileSystemDirectory,
212 base::string16()));
215 // A special hack: The warning message for declarativeWebRequest
216 // permissions speaks about blocking parts of pages, which is a
217 // subset of what the "<all_urls>" access allows. Therefore we
218 // display only the "<all_urls>" warning message if both permissions
219 // are required.
220 if (permissions->HasEffectiveAccessToAllHosts()) {
221 messages.erase(
222 PermissionMessage(
223 PermissionMessage::kDeclarativeWebRequest, base::string16()));
226 return messages;
229 std::set<PermissionMessage>
230 ChromePermissionMessageProvider::GetManifestPermissionMessages(
231 const PermissionSet* permissions) const {
232 std::set<PermissionMessage> messages;
233 for (ManifestPermissionSet::const_iterator permission_it =
234 permissions->manifest_permissions().begin();
235 permission_it != permissions->manifest_permissions().end();
236 ++permission_it) {
237 if (permission_it->HasMessages()) {
238 PermissionMessages new_messages = permission_it->GetMessages();
239 messages.insert(new_messages.begin(), new_messages.end());
242 return messages;
245 std::set<PermissionMessage>
246 ChromePermissionMessageProvider::GetHostPermissionMessages(
247 const PermissionSet* permissions,
248 Manifest::Type extension_type) const {
249 std::set<PermissionMessage> messages;
250 // Since platform apps always use isolated storage, they can't (silently)
251 // access user data on other domains, so there's no need to prompt.
252 // Note: this must remain consistent with IsHostPrivilegeIncrease.
253 // See crbug.com/255229.
254 if (extension_type == Manifest::TYPE_PLATFORM_APP)
255 return messages;
257 if (permissions->HasEffectiveAccessToAllHosts()) {
258 messages.insert(PermissionMessage(
259 PermissionMessage::kHostsAll,
260 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
261 } else {
262 URLPatternSet regular_hosts;
263 ExtensionsClient::Get()->FilterHostPermissions(
264 permissions->effective_hosts(), &regular_hosts, &messages);
266 std::set<std::string> hosts =
267 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
268 if (!hosts.empty())
269 messages.insert(permission_message_util::CreateFromHostList(hosts));
271 return messages;
274 bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease(
275 const PermissionSet* old_permissions,
276 const PermissionSet* new_permissions) const {
277 if (new_permissions == NULL)
278 return false;
280 typedef std::set<PermissionMessage> PermissionMsgSet;
281 PermissionMsgSet old_warnings = GetAPIPermissionMessages(old_permissions);
282 PermissionMsgSet new_warnings = GetAPIPermissionMessages(new_permissions);
283 PermissionMsgSet delta_warnings =
284 base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings);
286 // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
287 // kFileSystemWrite.
288 // TODO(sammc): Remove this. See http://crbug.com/284849.
289 if (old_warnings.find(PermissionMessage(
290 PermissionMessage::kFileSystemWriteDirectory, base::string16())) !=
291 old_warnings.end()) {
292 delta_warnings.erase(
293 PermissionMessage(PermissionMessage::kFileSystemDirectory,
294 base::string16()));
295 delta_warnings.erase(
296 PermissionMessage(PermissionMessage::kFileSystemWrite,
297 base::string16()));
300 // It is a privilege increase if there are additional warnings present.
301 return !delta_warnings.empty();
304 bool ChromePermissionMessageProvider::IsManifestPermissionPrivilegeIncrease(
305 const PermissionSet* old_permissions,
306 const PermissionSet* new_permissions) const {
307 if (new_permissions == NULL)
308 return false;
310 typedef std::set<PermissionMessage> PermissionMsgSet;
311 PermissionMsgSet old_warnings =
312 GetManifestPermissionMessages(old_permissions);
313 PermissionMsgSet new_warnings =
314 GetManifestPermissionMessages(new_permissions);
315 PermissionMsgSet delta_warnings =
316 base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings);
318 // It is a privilege increase if there are additional warnings present.
319 return !delta_warnings.empty();
322 bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease(
323 const PermissionSet* old_permissions,
324 const PermissionSet* new_permissions,
325 Manifest::Type extension_type) const {
326 // Platform apps host permission changes do not count as privilege increases.
327 // Note: this must remain consistent with GetHostPermissionMessages.
328 if (extension_type == Manifest::TYPE_PLATFORM_APP)
329 return false;
331 // If the old permission set can access any host, then it can't be elevated.
332 if (old_permissions->HasEffectiveAccessToAllHosts())
333 return false;
335 // Likewise, if the new permission set has full host access, then it must be
336 // a privilege increase.
337 if (new_permissions->HasEffectiveAccessToAllHosts())
338 return true;
340 const URLPatternSet& old_list = old_permissions->effective_hosts();
341 const URLPatternSet& new_list = new_permissions->effective_hosts();
343 // TODO(jstritar): This is overly conservative with respect to subdomains.
344 // For example, going from *.google.com to www.google.com will be
345 // considered an elevation, even though it is not (http://crbug.com/65337).
346 std::set<std::string> new_hosts_set(
347 permission_message_util::GetDistinctHosts(new_list, false, false));
348 std::set<std::string> old_hosts_set(
349 permission_message_util::GetDistinctHosts(old_list, false, false));
350 std::set<std::string> new_hosts_only =
351 base::STLSetDifference<std::set<std::string> >(new_hosts_set,
352 old_hosts_set);
354 return !new_hosts_only.empty();
357 } // namespace extensions