15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/grit/generated_resources.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/extensions_client.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/permissions/permission_message.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/permissions/permission_message_util.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/common/permissions/permission_set.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/url_pattern.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/url_pattern_set.h" 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "grit/extensions_strings.h" 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "url/gurl.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace extensions { 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::set<PermissionMessage> PermissionMsgSet; 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template<typename T> 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)typename T::iterator FindMessageByID(T& messages, int id) { 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (typename T::iterator it = messages.begin(); 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) it != messages.end(); ++it) { 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (it->id() == id) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return it; 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return messages.end(); 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template<typename T> 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typename T::const_iterator FindMessageByID(const T& messages, int id) { 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (typename T::const_iterator it = messages.begin(); 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) it != messages.end(); ++it) { 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (it->id() == id) 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return it; 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return messages.end(); 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template<typename T> 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SuppressMessage(T& messages, 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int suppressing_message, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int suppressed_message) { 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) typename T::iterator suppressed = FindMessageByID(messages, 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) suppressed_message); 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (suppressed != messages.end() && 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FindMessageByID(messages, suppressing_message) != messages.end()) { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) messages.erase(suppressed); 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ContainsMessages(const PermissionMessages& messages, 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int first_message, 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int second_message) { 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return FindMessageByID(messages, first_message) != messages.end() && 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FindMessageByID(messages, second_message) != messages.end(); 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ContainsMessages(const PermissionMessages& messages, 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int first_message, 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int second_message, 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int third_message) { 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return ContainsMessages(messages, first_message, second_message) && 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FindMessageByID(messages, third_message) != messages.end(); 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ChromePermissionMessageProvider::ChromePermissionMessageProvider() { 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromePermissionMessageProvider::~ChromePermissionMessageProvider() { 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages( 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const PermissionSet* permissions, 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Manifest::Type extension_type) const { 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PermissionMessages messages; 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (permissions->HasEffectiveFullAccess()) { 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) messages.push_back(PermissionMessage( 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PermissionMessage::kFullAccess, 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS))); 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return messages; 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Some warnings are more generic and/or powerful and superseed other 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // warnings. In that case, the first message suppresses the second one. 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::multimap<PermissionMessage::ID, PermissionMessage::ID> kSuppressList; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert( 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) {PermissionMessage::kBluetooth, PermissionMessage::kBluetoothDevices}); 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert( 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {PermissionMessage::kBookmarks, PermissionMessage::kOverrideBookmarksUI}); 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // History already allows reading favicons. 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert( 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {PermissionMessage::kBrowsingHistory, PermissionMessage::kFavicon}); 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // History already allows tabs access. 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) kSuppressList.insert( 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) {PermissionMessage::kBrowsingHistory, PermissionMessage::kTabs}); 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // History already allows access the list of most frequently visited sites. 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) kSuppressList.insert( 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) {PermissionMessage::kBrowsingHistory, PermissionMessage::kTopSites}); 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // A special hack: If kFileSystemWriteDirectory would be displayed, hide 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // kFileSystemDirectory as the write directory message implies it. 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(sammc): Remove this. See http://crbug.com/284849. 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) kSuppressList.insert({PermissionMessage::kFileSystemWriteDirectory, 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PermissionMessage::kFileSystemDirectory}); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Full access already allows DeclarativeWebRequest. 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert({PermissionMessage::kHostsAll, 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PermissionMessage::kDeclarativeWebRequest}); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Full access implies reading the list of most frequently visited sites. 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert( 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {PermissionMessage::kHostsAll, PermissionMessage::kTopSites}); 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Full access already covers tabs access. 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kSuppressList.insert( 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {PermissionMessage::kHostsAll, PermissionMessage::kTabs}); 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Tabs already allows reading favicons. 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kSuppressList.insert({PermissionMessage::kTabs, PermissionMessage::kFavicon}); 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Tabs already allows reading the list of most frequently visited sites. 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kSuppressList.insert( 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {PermissionMessage::kTabs, PermissionMessage::kTopSites}); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PermissionMsgSet host_msgs = 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetHostPermissionMessages(permissions, extension_type); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PermissionMsgSet api_msgs = GetAPIPermissionMessages(permissions); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PermissionMsgSet manifest_permission_msgs = 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) GetManifestPermissionMessages(permissions); 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) messages.insert(messages.end(), host_msgs.begin(), host_msgs.end()); 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) messages.insert(messages.end(), api_msgs.begin(), api_msgs.end()); 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) messages.insert(messages.end(), manifest_permission_msgs.begin(), 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) manifest_permission_msgs.end()); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (std::multimap<PermissionMessage::ID, 139 PermissionMessage::ID>::const_iterator it = 140 kSuppressList.begin(); 141 it != kSuppressList.end(); 142 ++it) { 143 SuppressMessage(messages, it->first, it->second); 144 } 145 146 return messages; 147} 148 149std::vector<base::string16> ChromePermissionMessageProvider::GetWarningMessages( 150 const PermissionSet* permissions, 151 Manifest::Type extension_type) const { 152 std::vector<base::string16> message_strings; 153 PermissionMessages messages = 154 GetPermissionMessages(permissions, extension_type); 155 156 for (PermissionMessages::const_iterator i = messages.begin(); 157 i != messages.end(); ++i) { 158 int id = i->id(); 159 // Access to users' devices should provide a single warning message 160 // specifying the transport method used; USB, serial and/or Bluetooth. 161 if (id == PermissionMessage::kBluetooth || 162 id == PermissionMessage::kSerial || 163 id == PermissionMessage::kUsb) { 164 if (ContainsMessages(messages, 165 PermissionMessage::kBluetooth, 166 PermissionMessage::kSerial, 167 PermissionMessage::kUsb)) { 168 if (id == PermissionMessage::kBluetooth) { 169 message_strings.push_back(l10n_util::GetStringUTF16( 170 IDS_EXTENSION_PROMPT_WARNING_ALL_DEVICES)); 171 } 172 continue; 173 } 174 if (ContainsMessages(messages, 175 PermissionMessage::kBluetooth, 176 PermissionMessage::kUsb)) { 177 if (id == PermissionMessage::kBluetooth) { 178 message_strings.push_back(l10n_util::GetStringUTF16( 179 IDS_EXTENSION_PROMPT_WARNING_USB_BLUETOOTH)); 180 } 181 continue; 182 } 183 if (ContainsMessages(messages, 184 PermissionMessage::kSerial, 185 PermissionMessage::kUsb)) { 186 if (id == PermissionMessage::kSerial) { 187 message_strings.push_back(l10n_util::GetStringUTF16( 188 IDS_EXTENSION_PROMPT_WARNING_USB_SERIAL)); 189 } 190 continue; 191 } 192 if (ContainsMessages(messages, 193 PermissionMessage::kBluetooth, 194 PermissionMessage::kSerial)) { 195 if (id == PermissionMessage::kBluetooth) { 196 message_strings.push_back(l10n_util::GetStringUTF16( 197 IDS_EXTENSION_PROMPT_WARNING_BLUETOOTH_SERIAL)); 198 } 199 continue; 200 } 201 } 202 if (id == PermissionMessage::kAccessibilityFeaturesModify || 203 id == PermissionMessage::kAccessibilityFeaturesRead) { 204 if (ContainsMessages(messages, 205 PermissionMessage::kAccessibilityFeaturesModify, 206 PermissionMessage::kAccessibilityFeaturesRead)) { 207 if (id == PermissionMessage::kAccessibilityFeaturesModify) { 208 message_strings.push_back(l10n_util::GetStringUTF16( 209 IDS_EXTENSION_PROMPT_WARNING_ACCESSIBILITY_FEATURES_READ_MODIFY)); 210 } 211 continue; 212 } 213 } 214 if (id == PermissionMessage::kAudioCapture || 215 id == PermissionMessage::kVideoCapture) { 216 if (ContainsMessages(messages, 217 PermissionMessage::kAudioCapture, 218 PermissionMessage::kVideoCapture)) { 219 if (id == PermissionMessage::kAudioCapture) { 220 message_strings.push_back(l10n_util::GetStringUTF16( 221 IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE)); 222 } 223 continue; 224 } 225 } 226 if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo || 227 id == PermissionMessage::kMediaGalleriesAllGalleriesDelete || 228 id == PermissionMessage::kMediaGalleriesAllGalleriesRead) { 229 if (ContainsMessages( 230 messages, 231 PermissionMessage::kMediaGalleriesAllGalleriesCopyTo, 232 PermissionMessage::kMediaGalleriesAllGalleriesDelete, 233 PermissionMessage::kMediaGalleriesAllGalleriesRead)) { 234 if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo) { 235 message_strings.push_back(l10n_util::GetStringUTF16( 236 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE_DELETE)); 237 } 238 continue; 239 } 240 if (ContainsMessages( 241 messages, 242 PermissionMessage::kMediaGalleriesAllGalleriesCopyTo, 243 PermissionMessage::kMediaGalleriesAllGalleriesRead)) { 244 if (id == PermissionMessage::kMediaGalleriesAllGalleriesCopyTo) { 245 message_strings.push_back(l10n_util::GetStringUTF16( 246 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE)); 247 } 248 continue; 249 } 250 if (ContainsMessages( 251 messages, 252 PermissionMessage::kMediaGalleriesAllGalleriesDelete, 253 PermissionMessage::kMediaGalleriesAllGalleriesRead)) { 254 if (id == PermissionMessage::kMediaGalleriesAllGalleriesDelete) { 255 message_strings.push_back(l10n_util::GetStringUTF16( 256 IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_DELETE)); 257 } 258 continue; 259 } 260 } 261 if (permissions->HasAPIPermission(APIPermission::kSessions) && 262 id == PermissionMessage::kTabs) { 263 message_strings.push_back(l10n_util::GetStringUTF16( 264 IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ_AND_SESSIONS)); 265 continue; 266 } 267 if (permissions->HasAPIPermission(APIPermission::kSessions) && 268 id == PermissionMessage::kBrowsingHistory) { 269 message_strings.push_back(l10n_util::GetStringUTF16( 270 IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE_AND_SESSIONS)); 271 continue; 272 } 273 274 message_strings.push_back(i->message()); 275 } 276 277 return message_strings; 278} 279 280std::vector<base::string16> 281ChromePermissionMessageProvider::GetWarningMessagesDetails( 282 const PermissionSet* permissions, 283 Manifest::Type extension_type) const { 284 std::vector<base::string16> message_strings; 285 PermissionMessages messages = 286 GetPermissionMessages(permissions, extension_type); 287 288 for (PermissionMessages::const_iterator i = messages.begin(); 289 i != messages.end(); ++i) 290 message_strings.push_back(i->details()); 291 292 return message_strings; 293} 294 295bool ChromePermissionMessageProvider::IsPrivilegeIncrease( 296 const PermissionSet* old_permissions, 297 const PermissionSet* new_permissions, 298 Manifest::Type extension_type) const { 299 // Things can't get worse than native code access. 300 if (old_permissions->HasEffectiveFullAccess()) 301 return false; 302 303 // Otherwise, it's a privilege increase if the new one has full access. 304 if (new_permissions->HasEffectiveFullAccess()) 305 return true; 306 307 if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type)) 308 return true; 309 310 if (IsAPIPrivilegeIncrease(old_permissions, new_permissions)) 311 return true; 312 313 if (IsManifestPermissionPrivilegeIncrease(old_permissions, new_permissions)) 314 return true; 315 316 return false; 317} 318 319std::set<PermissionMessage> 320ChromePermissionMessageProvider::GetAPIPermissionMessages( 321 const PermissionSet* permissions) const { 322 PermissionMsgSet messages; 323 for (APIPermissionSet::const_iterator permission_it = 324 permissions->apis().begin(); 325 permission_it != permissions->apis().end(); ++permission_it) { 326 if (permission_it->HasMessages()) { 327 PermissionMessages new_messages = permission_it->GetMessages(); 328 messages.insert(new_messages.begin(), new_messages.end()); 329 } 330 } 331 332 // A special hack: The warning message for declarativeWebRequest 333 // permissions speaks about blocking parts of pages, which is a 334 // subset of what the "<all_urls>" access allows. Therefore we 335 // display only the "<all_urls>" warning message if both permissions 336 // are required. 337 if (permissions->ShouldWarnAllHosts()) { 338 messages.erase( 339 PermissionMessage( 340 PermissionMessage::kDeclarativeWebRequest, base::string16())); 341 } 342 return messages; 343} 344 345std::set<PermissionMessage> 346ChromePermissionMessageProvider::GetManifestPermissionMessages( 347 const PermissionSet* permissions) const { 348 PermissionMsgSet messages; 349 for (ManifestPermissionSet::const_iterator permission_it = 350 permissions->manifest_permissions().begin(); 351 permission_it != permissions->manifest_permissions().end(); 352 ++permission_it) { 353 if (permission_it->HasMessages()) { 354 PermissionMessages new_messages = permission_it->GetMessages(); 355 messages.insert(new_messages.begin(), new_messages.end()); 356 } 357 } 358 return messages; 359} 360 361std::set<PermissionMessage> 362ChromePermissionMessageProvider::GetHostPermissionMessages( 363 const PermissionSet* permissions, 364 Manifest::Type extension_type) const { 365 PermissionMsgSet messages; 366 // Since platform apps always use isolated storage, they can't (silently) 367 // access user data on other domains, so there's no need to prompt. 368 // Note: this must remain consistent with IsHostPrivilegeIncrease. 369 // See crbug.com/255229. 370 if (extension_type == Manifest::TYPE_PLATFORM_APP) 371 return messages; 372 373 if (permissions->ShouldWarnAllHosts()) { 374 messages.insert(PermissionMessage( 375 PermissionMessage::kHostsAll, 376 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS))); 377 } else { 378 URLPatternSet regular_hosts; 379 ExtensionsClient::Get()->FilterHostPermissions( 380 permissions->effective_hosts(), ®ular_hosts, &messages); 381 382 std::set<std::string> hosts = 383 permission_message_util::GetDistinctHosts(regular_hosts, true, true); 384 if (!hosts.empty()) 385 messages.insert(permission_message_util::CreateFromHostList(hosts)); 386 } 387 return messages; 388} 389 390bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease( 391 const PermissionSet* old_permissions, 392 const PermissionSet* new_permissions) const { 393 if (new_permissions == NULL) 394 return false; 395 396 PermissionMsgSet old_warnings = GetAPIPermissionMessages(old_permissions); 397 PermissionMsgSet new_warnings = GetAPIPermissionMessages(new_permissions); 398 PermissionMsgSet delta_warnings = 399 base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings); 400 401 // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory. 402 // TODO(sammc): Remove this. See http://crbug.com/284849. 403 if (old_warnings.find(PermissionMessage( 404 PermissionMessage::kFileSystemWriteDirectory, base::string16())) != 405 old_warnings.end()) { 406 delta_warnings.erase( 407 PermissionMessage(PermissionMessage::kFileSystemDirectory, 408 base::string16())); 409 } 410 411 // It is a privilege increase if there are additional warnings present. 412 return !delta_warnings.empty(); 413} 414 415bool ChromePermissionMessageProvider::IsManifestPermissionPrivilegeIncrease( 416 const PermissionSet* old_permissions, 417 const PermissionSet* new_permissions) const { 418 if (new_permissions == NULL) 419 return false; 420 421 PermissionMsgSet old_warnings = 422 GetManifestPermissionMessages(old_permissions); 423 PermissionMsgSet new_warnings = 424 GetManifestPermissionMessages(new_permissions); 425 PermissionMsgSet delta_warnings = 426 base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings); 427 428 // It is a privilege increase if there are additional warnings present. 429 return !delta_warnings.empty(); 430} 431 432bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease( 433 const PermissionSet* old_permissions, 434 const PermissionSet* new_permissions, 435 Manifest::Type extension_type) const { 436 // Platform apps host permission changes do not count as privilege increases. 437 // Note: this must remain consistent with GetHostPermissionMessages. 438 if (extension_type == Manifest::TYPE_PLATFORM_APP) 439 return false; 440 441 // If the old permission set can access any host, then it can't be elevated. 442 if (old_permissions->HasEffectiveAccessToAllHosts()) 443 return false; 444 445 // Likewise, if the new permission set has full host access, then it must be 446 // a privilege increase. 447 if (new_permissions->HasEffectiveAccessToAllHosts()) 448 return true; 449 450 const URLPatternSet& old_list = old_permissions->effective_hosts(); 451 const URLPatternSet& new_list = new_permissions->effective_hosts(); 452 453 // TODO(jstritar): This is overly conservative with respect to subdomains. 454 // For example, going from *.google.com to www.google.com will be 455 // considered an elevation, even though it is not (http://crbug.com/65337). 456 std::set<std::string> new_hosts_set( 457 permission_message_util::GetDistinctHosts(new_list, false, false)); 458 std::set<std::string> old_hosts_set( 459 permission_message_util::GetDistinctHosts(old_list, false, false)); 460 std::set<std::string> new_hosts_only = 461 base::STLSetDifference<std::set<std::string> >(new_hosts_set, 462 old_hosts_set); 463 464 return !new_hosts_only.empty(); 465} 466 467} // namespace extensions 468