- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / permissions / chrome_permission_message_provider.cc
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 "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
6
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"
15
16 namespace extensions {
17
18 ChromePermissionMessageProvider::ChromePermissionMessageProvider() {
19 }
20
21 ChromePermissionMessageProvider::~ChromePermissionMessageProvider() {
22 }
23
24 // static
25 PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
26     const PermissionSet* permissions,
27     Manifest::Type extension_type) const {
28   PermissionMessages messages;
29
30   if (permissions->HasEffectiveFullAccess()) {
31     messages.push_back(PermissionMessage(
32         PermissionMessage::kFullAccess,
33         l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
34     return messages;
35   }
36
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());
42
43   return messages;
44 }
45
46 // static
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);
53
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) {
60     switch (i->id()) {
61       case PermissionMessage::kAudioCapture:
62         audio_capture = true;
63         break;
64       case PermissionMessage::kVideoCapture:
65         video_capture = true;
66         break;
67       case PermissionMessage::kMediaGalleriesAllGalleriesRead:
68         media_galleries_read = true;
69         break;
70       case PermissionMessage::kMediaGalleriesAllGalleriesCopyTo:
71         media_galleries_copy_to = true;
72         break;
73       default:
74         break;
75     }
76   }
77
78   for (PermissionMessages::const_iterator i = messages.begin();
79        i != messages.end(); ++i) {
80     int id = i->id();
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));
85         continue;
86       } else if (id == PermissionMessage::kVideoCapture) {
87         // The combined message will be pushed above.
88         continue;
89       }
90     }
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));
95         continue;
96       } else if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo) {
97         // The combined message will be pushed above.
98         continue;
99       }
100     }
101
102     message_strings.push_back(i->message());
103   }
104
105   return message_strings;
106 }
107
108 // static
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);
116
117   for (PermissionMessages::const_iterator i = messages.begin();
118        i != messages.end(); ++i)
119     message_strings.push_back(i->details());
120
121   return message_strings;
122 }
123
124 // static
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())
131     return false;
132
133   // Otherwise, it's a privilege increase if the new one has full access.
134   if (new_permissions->HasEffectiveFullAccess())
135     return true;
136
137   if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type))
138     return true;
139
140   if (IsAPIPrivilegeIncrease(old_permissions, new_permissions))
141     return true;
142
143   return false;
144 }
145
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());
156     }
157   }
158
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()) {
167     messages.erase(
168         PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
169     messages.erase(
170         PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
171   }
172
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
177   // are required.
178   if (permissions->HasEffectiveAccessToAllHosts()) {
179     messages.erase(
180         PermissionMessage(
181             PermissionMessage::kDeclarativeWebRequest, string16()));
182   }
183
184   return messages;
185 }
186
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)
197     return messages;
198
199   if (permissions->HasEffectiveAccessToAllHosts()) {
200     messages.insert(PermissionMessage(
201         PermissionMessage::kHostsAll,
202         l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
203   } else {
204     URLPatternSet regular_hosts;
205     ExtensionsClient::Get()->FilterHostPermissions(
206         permissions->effective_hosts(), &regular_hosts, &messages);
207
208     std::set<std::string> hosts =
209         permission_message_util::GetDistinctHosts(regular_hosts, true, true);
210     if (!hosts.empty())
211       messages.insert(permission_message_util::CreateFromHostList(hosts));
212   }
213   return messages;
214 }
215
216 bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease(
217     const PermissionSet* old_permissions,
218     const PermissionSet* new_permissions) const {
219   if (new_permissions == NULL)
220     return false;
221
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);
227
228   // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
229   // kFileSystemWrite.
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()));
238   }
239
240   // We have less privileges if there are additional warnings present.
241   return !delta_warnings.empty();
242 }
243
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)
251     return false;
252
253   // If the old permission set can access any host, then it can't be elevated.
254   if (old_permissions->HasEffectiveAccessToAllHosts())
255     return false;
256
257   // Likewise, if the new permission set has full host access, then it must be
258   // a privilege increase.
259   if (new_permissions->HasEffectiveAccessToAllHosts())
260     return true;
261
262   const URLPatternSet& old_list = old_permissions->effective_hosts();
263   const URLPatternSet& new_list = new_permissions->effective_hosts();
264
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,
274                                                      old_hosts_set);
275
276   return !new_hosts_only.empty();
277 }
278
279 }  // namespace extensions