Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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/extension_permission_set.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/memory/singleton.h" | |
| 10 #include "base/values.h" | |
| 11 #include "base/string_number_conversions.h" | |
| 12 #include "base/utf_string_conversions.h" | |
| 13 #include "chrome/browser/extensions/extension_prefs.h" | |
| 14 #include "chrome/common/extensions/extension.h" | |
| 15 #include "chrome/common/extensions/extension_constants.h" | |
| 16 #include "chrome/common/extensions/extension_l10n_util.h" | |
| 17 #include "chrome/common/extensions/url_pattern.h" | |
| 18 #include "chrome/common/extensions/url_pattern_set.h" | |
| 19 #include "grit/generated_resources.h" | |
| 20 #include "net/base/registry_controlled_domain.h" | |
| 21 #include "ui/base/l10n/l10n_util.h" | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Helper for GetDistinctHosts(): com > net > org > everything else. | |
| 26 bool RcdBetterThan(std::string a, std::string b) { | |
| 27 if (a == b) | |
| 28 return false; | |
| 29 if (a == "com") | |
| 30 return true; | |
| 31 if (a == "net") | |
| 32 return b != "com"; | |
| 33 if (a == "org") | |
| 34 return b != "com" && b != "net"; | |
| 35 return false; | |
| 36 } | |
| 37 | |
| 38 // Names of API modules that do not require a permission. | |
| 39 const char kBrowserActionModuleName[] = "browserAction"; | |
| 40 const char kBrowserActionsModuleName[] = "browserActions"; | |
| 41 const char kDevToolsModuleName[] = "devtools"; | |
| 42 const char kExtensionModuleName[] = "extension"; | |
| 43 const char kI18NModuleName[] = "i18n"; | |
| 44 const char kOmniboxModuleName[] = "omnibox"; | |
| 45 const char kPageActionModuleName[] = "pageAction"; | |
| 46 const char kPageActionsModuleName[] = "pageActions"; | |
| 47 const char kTestModuleName[] = "test"; | |
| 48 | |
| 49 // Names of modules that can be used without listing it in the permissions | |
| 50 // section of the manifest. | |
| 51 const char* kNonPermissionModuleNames[] = { | |
| 52 kBrowserActionModuleName, | |
| 53 kBrowserActionsModuleName, | |
| 54 kDevToolsModuleName, | |
| 55 kExtensionModuleName, | |
| 56 kI18NModuleName, | |
| 57 kOmniboxModuleName, | |
| 58 kPageActionModuleName, | |
| 59 kPageActionsModuleName, | |
| 60 kTestModuleName | |
| 61 }; | |
| 62 const size_t kNumNonPermissionModuleNames = | |
| 63 arraysize(kNonPermissionModuleNames); | |
| 64 | |
| 65 | |
| 66 // Names of functions (within modules requiring permissions) that can be used | |
| 67 // without asking for the module permission. In other words, functions you can | |
| 68 // use with no permissions specified. | |
| 69 const char* kNonPermissionFunctionNames[] = { | |
| 70 "tabs.create", | |
| 71 "tabs.onRemoved", | |
| 72 "tabs.remove", | |
| 73 "tabs.update", | |
| 74 }; | |
| 75 const size_t kNumNonPermissionFunctionNames = | |
| 76 arraysize(kNonPermissionFunctionNames); | |
| 77 | |
| 78 // Aliased to kTabPermission for purposes of API checks, but not allowed | |
| 79 // in the permissions field of the manifest. | |
| 80 static const char kWindowPermission[] = "windows"; | |
| 81 | |
| 82 const char kOldUnlimitedStoragePermission[] = "unlimited_storage"; | |
| 83 const char kWindowsPermission[] = "windows"; | |
| 84 | |
| 85 } // namespace | |
| 86 | |
| 87 // | |
| 88 // PermissionMessage | |
| 89 // | |
| 90 | |
| 91 ExtensionPermissionMessage::ExtensionPermissionMessage( | |
| 92 ExtensionPermissionMessage::MessageId message_id, string16 message) | |
| 93 : message_id_(message_id), | |
| 94 message_(message) { | |
| 95 } | |
| 96 | |
| 97 // static | |
| 98 ExtensionPermissionMessage ExtensionPermissionMessage::CreateFromHostList( | |
| 99 std::vector<std::string> hosts) { | |
| 100 CHECK(hosts.size() > 0); | |
| 101 MessageId message_id; | |
| 102 string16 message; | |
| 103 switch (hosts.size()) { | |
| 104 case 1: | |
| 105 message_id = ID_HOSTS_1; | |
| 106 message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_1_HOST, | |
| 107 UTF8ToUTF16(hosts[0])); | |
| 108 break; | |
| 109 case 2: | |
| 110 message_id = ID_HOSTS_2; | |
| 111 message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, | |
| 112 UTF8ToUTF16(hosts[0]), | |
| 113 UTF8ToUTF16(hosts[1])); | |
| 114 break; | |
| 115 case 3: | |
| 116 message_id = ID_HOSTS_3; | |
| 117 message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, | |
| 118 UTF8ToUTF16(hosts[0]), | |
| 119 UTF8ToUTF16(hosts[1]), | |
| 120 UTF8ToUTF16(hosts[2])); | |
| 121 break; | |
| 122 default: | |
| 123 message_id = ID_HOSTS_4_OR_MORE; | |
| 124 message = l10n_util::GetStringFUTF16( | |
| 125 IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS, | |
| 126 UTF8ToUTF16(hosts[0]), | |
| 127 UTF8ToUTF16(hosts[1]), | |
| 128 base::IntToString16(hosts.size() - 2)); | |
| 129 break; | |
| 130 } | |
| 131 | |
| 132 return ExtensionPermissionMessage(message_id, message); | |
| 133 } | |
| 134 | |
| 135 // | |
| 136 // ExtensionPermissionsInfo | |
| 137 // | |
| 138 | |
| 139 // static | |
| 140 ExtensionPermissionsInfo* ExtensionPermissionsInfo::GetInstance() { | |
| 141 return Singleton<ExtensionPermissionsInfo>::get(); | |
| 142 } | |
| 143 | |
| 144 // TODO(jstritar): Figure out how to clean up this initialization. We may want | |
| 145 // initialize these dynamically based on data in extension_api.json. | |
| 146 ExtensionPermissionsInfo::ExtensionPermissionsInfo() | |
|
jstritar
2011/06/09 21:12:57
Any advice on how to make these initializations cl
| |
| 147 : background_(this, "background", true, false, 0, | |
|
Matt Perry
2011/06/09 22:28:42
If you take my suggestion and switch to using an e
| |
| 148 ExtensionPermissionMessage::ID_NONE), | |
| 149 bookmark_(this, "bookmarks", false, false, | |
| 150 IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS, | |
| 151 ExtensionPermissionMessage::ID_BOOKMARKS), | |
| 152 clipboard_read_(this, "clipboardRead", true, false, | |
| 153 IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD, | |
| 154 ExtensionPermissionMessage::ID_CLIPBOARD), | |
| 155 clipboard_write_(this, "clipboardWrite", true, false, 0, | |
| 156 ExtensionPermissionMessage::ID_NONE), | |
| 157 content_settings_(this, "contentSettings", false, false, 0, | |
| 158 ExtensionPermissionMessage::ID_NONE), | |
| 159 context_menus_(this, "contentSettings", false, false, 0, | |
| 160 ExtensionPermissionMessage::ID_NONE), | |
| 161 cookie_(this, "cookies", false, false, 0, | |
| 162 ExtensionPermissionMessage::ID_NONE), | |
| 163 chrome_private_(this, "chromePrivate", true, false, 0, | |
| 164 ExtensionPermissionMessage::ID_NONE), | |
| 165 chromeos_info_private_(this, "chromeosInfoPrivate", false, true, 0, | |
| 166 ExtensionPermissionMessage::ID_NONE), | |
| 167 debugger_(this, "debugger", false, false, | |
| 168 IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, | |
| 169 ExtensionPermissionMessage::ID_DEBUGGER), | |
| 170 experimental_(this, "experimental", true, false, 0, | |
| 171 ExtensionPermissionMessage::ID_NONE), | |
| 172 file_browser_handler_(this, "fileBrowserHandler", false, false, 0, | |
| 173 ExtensionPermissionMessage::ID_NONE), | |
| 174 file_browser_private_(this, "fileBrowserPrivate", false, true, 0, | |
| 175 ExtensionPermissionMessage::ID_NONE), | |
| 176 geolocation_(this, "geolocation", true, false, | |
| 177 IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION, | |
| 178 ExtensionPermissionMessage::ID_GEOLOCATION), | |
| 179 history_(this, "history", false, false, | |
| 180 IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY, | |
| 181 ExtensionPermissionMessage::ID_BROWSING_HISTORY), | |
| 182 idle_(this, "idle", false, false, 0, ExtensionPermissionMessage::ID_NONE), | |
| 183 management_(this, "management", false, false, | |
| 184 IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT, | |
| 185 ExtensionPermissionMessage::ID_MANAGEMENT), | |
| 186 media_player_private_(this, "mediaPlayerPrivate", false, true, 0, | |
| 187 ExtensionPermissionMessage::ID_NONE), | |
| 188 notification_(this, "notifications", true, false, 0, | |
| 189 ExtensionPermissionMessage::ID_NONE), | |
| 190 proxy_(this, "proxy", false, false, 0, | |
| 191 ExtensionPermissionMessage::ID_NONE), | |
| 192 tab_(this, "tabs", false, false, IDS_EXTENSION_PROMPT_WARNING_TABS, | |
| 193 ExtensionPermissionMessage::ID_TABS), | |
| 194 unlimited_storage_(this, "unlimitedStorage", true, false, 0, | |
| 195 ExtensionPermissionMessage::ID_NONE), | |
| 196 web_socket_proxy_private_(this, "webSocketProxyPrivate", false, false, 0, | |
| 197 ExtensionPermissionMessage::ID_NONE), | |
| 198 webstore_private_(this, "webstorePrivate", true, true, 0, | |
| 199 ExtensionPermissionMessage::ID_NONE) { | |
| 200 | |
| 201 // Map aliases for old permissions. | |
| 202 permissions_[kOldUnlimitedStoragePermission] = &unlimited_storage_; | |
| 203 permissions_[kWindowsPermission] = &tab_; | |
| 204 } | |
| 205 | |
| 206 ExtensionPermissionsInfo::~ExtensionPermissionsInfo() { | |
| 207 } | |
| 208 | |
| 209 // | |
| 210 // ExtensionPermission | |
| 211 // | |
| 212 | |
| 213 | |
| 214 // static | |
| 215 const ExtensionAPIPermission& ExtensionAPIPermission::Background() { | |
| 216 return ExtensionPermissionsInfo::GetInstance()->background_; | |
| 217 } | |
| 218 | |
| 219 // static | |
| 220 const ExtensionAPIPermission& ExtensionAPIPermission::Bookmark() { | |
| 221 return ExtensionPermissionsInfo::GetInstance()->bookmark_; | |
| 222 } | |
| 223 | |
| 224 // static | |
| 225 const ExtensionAPIPermission& ExtensionAPIPermission::ClipboardRead() { | |
| 226 return ExtensionPermissionsInfo::GetInstance()->clipboard_read_; | |
| 227 } | |
| 228 | |
| 229 // static | |
| 230 const ExtensionAPIPermission& ExtensionAPIPermission::ClipboardWrite() { | |
| 231 return ExtensionPermissionsInfo::GetInstance()->clipboard_write_; | |
| 232 } | |
| 233 | |
| 234 // static | |
| 235 const ExtensionAPIPermission& ExtensionAPIPermission::ContentSettings() { | |
| 236 return ExtensionPermissionsInfo::GetInstance()->content_settings_; | |
| 237 } | |
| 238 | |
| 239 // static | |
| 240 const ExtensionAPIPermission& ExtensionAPIPermission::ContextMenus() { | |
| 241 return ExtensionPermissionsInfo::GetInstance()->context_menus_; | |
| 242 } | |
| 243 | |
| 244 // static | |
| 245 const ExtensionAPIPermission& ExtensionAPIPermission::Cookie() { | |
| 246 return ExtensionPermissionsInfo::GetInstance()->cookie_; | |
| 247 } | |
| 248 | |
| 249 // static | |
| 250 const ExtensionAPIPermission& ExtensionAPIPermission::ChromePrivate() { | |
| 251 return ExtensionPermissionsInfo::GetInstance()->chrome_private_; | |
| 252 } | |
| 253 | |
| 254 // static | |
| 255 const ExtensionAPIPermission& ExtensionAPIPermission::ChromeosInfoPrivate() { | |
| 256 return ExtensionPermissionsInfo::GetInstance()->chromeos_info_private_; | |
| 257 } | |
| 258 | |
| 259 // static | |
| 260 const ExtensionAPIPermission& ExtensionAPIPermission::Debugger() { | |
| 261 return ExtensionPermissionsInfo::GetInstance()->debugger_; | |
| 262 } | |
| 263 | |
| 264 // static | |
| 265 const ExtensionAPIPermission& ExtensionAPIPermission::Experimental() { | |
| 266 return ExtensionPermissionsInfo::GetInstance()->experimental_; | |
| 267 } | |
| 268 | |
| 269 // static | |
| 270 const ExtensionAPIPermission& ExtensionAPIPermission::FileBrowserHandler() { | |
| 271 return ExtensionPermissionsInfo::GetInstance()->file_browser_handler_; | |
| 272 } | |
| 273 | |
| 274 // static | |
| 275 const ExtensionAPIPermission& ExtensionAPIPermission::FileBrowserPrivate() { | |
| 276 return ExtensionPermissionsInfo::GetInstance()->file_browser_private_; | |
| 277 } | |
| 278 | |
| 279 // static | |
| 280 const ExtensionAPIPermission& ExtensionAPIPermission::Geolocation() { | |
| 281 return ExtensionPermissionsInfo::GetInstance()->geolocation_; | |
| 282 } | |
| 283 | |
| 284 // static | |
| 285 const ExtensionAPIPermission& ExtensionAPIPermission::History() { | |
| 286 return ExtensionPermissionsInfo::GetInstance()->history_; | |
| 287 } | |
| 288 | |
| 289 // static | |
| 290 const ExtensionAPIPermission& ExtensionAPIPermission::Idle() { | |
| 291 return ExtensionPermissionsInfo::GetInstance()->idle_; | |
| 292 } | |
| 293 | |
| 294 // static | |
| 295 const ExtensionAPIPermission& ExtensionAPIPermission::Management() { | |
| 296 return ExtensionPermissionsInfo::GetInstance()->management_; | |
| 297 } | |
| 298 | |
| 299 // static | |
| 300 const ExtensionAPIPermission& ExtensionAPIPermission::MediaPlayerPrivate() { | |
| 301 return ExtensionPermissionsInfo::GetInstance()->media_player_private_; | |
| 302 } | |
| 303 | |
| 304 // static | |
| 305 const ExtensionAPIPermission& ExtensionAPIPermission::Notification() { | |
| 306 return ExtensionPermissionsInfo::GetInstance()->notification_; | |
| 307 } | |
| 308 | |
| 309 // static | |
| 310 const ExtensionAPIPermission& ExtensionAPIPermission::Proxy() { | |
| 311 return ExtensionPermissionsInfo::GetInstance()->proxy_; | |
| 312 } | |
| 313 | |
| 314 // static | |
| 315 const ExtensionAPIPermission& ExtensionAPIPermission::Tab() { | |
| 316 return ExtensionPermissionsInfo::GetInstance()->tab_; | |
| 317 } | |
| 318 | |
| 319 // static | |
| 320 const ExtensionAPIPermission& ExtensionAPIPermission::UnlimitedStorage() { | |
| 321 return ExtensionPermissionsInfo::GetInstance()->unlimited_storage_; | |
| 322 } | |
| 323 | |
| 324 // static | |
| 325 const ExtensionAPIPermission& ExtensionAPIPermission::WebstorePrivate() { | |
| 326 return ExtensionPermissionsInfo::GetInstance()->webstore_private_; | |
| 327 } | |
| 328 | |
| 329 // static | |
| 330 const ExtensionAPIPermission& ExtensionAPIPermission::WebSocketProxyPrivate() { | |
| 331 return ExtensionPermissionsInfo::GetInstance()->web_socket_proxy_private_; | |
| 332 } | |
| 333 | |
| 334 // static | |
| 335 std::set<ExtensionAPIPermission> ExtensionAPIPermission::GetAll() { | |
| 336 std::set<ExtensionAPIPermission> permissions; | |
| 337 ExtensionPermissionsInfo::PermissionMap permission_map = | |
| 338 ExtensionPermissionsInfo::GetInstance()->permissions_; | |
| 339 ExtensionPermissionsInfo::PermissionMap::const_iterator i = | |
| 340 permission_map.begin(); | |
| 341 for (; i != permission_map.end(); ++i) { | |
| 342 permissions.insert(*(i->second)); | |
| 343 } | |
| 344 return permissions; | |
| 345 } | |
| 346 | |
| 347 // static | |
| 348 ExtensionAPIPermission* ExtensionAPIPermission::GetByName(std::string name) { | |
| 349 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance(); | |
| 350 if (info->permissions_.count(name)) | |
| 351 return info->permissions_.find(name)->second; | |
| 352 return NULL; | |
| 353 } | |
| 354 | |
| 355 // static | |
| 356 std::set<ExtensionAPIPermission> ExtensionAPIPermission::GetAllByName( | |
| 357 const std::set<std::string>& permissions_str) { | |
| 358 std::set<ExtensionAPIPermission> permissions; | |
| 359 for (std::set<std::string>::iterator i = permissions_str.begin(); | |
| 360 i != permissions_str.end(); ++i) { | |
| 361 ExtensionAPIPermission* permission = | |
| 362 ExtensionAPIPermission::GetByName(*i); | |
| 363 if (permission) | |
| 364 permissions.insert(*permission); | |
| 365 } | |
| 366 return permissions; | |
| 367 } | |
| 368 | |
| 369 // static | |
| 370 size_t ExtensionAPIPermission::permission_count_ = 0; | |
| 371 | |
| 372 // static | |
| 373 size_t ExtensionAPIPermission::hosted_app_permission_count_ = 0; | |
| 374 | |
| 375 ExtensionPermissionMessage ExtensionAPIPermission::GetMessage() const { | |
| 376 return ExtensionPermissionMessage( | |
| 377 message_id_, l10n_util::GetStringUTF16(l10n_message_id_)); | |
| 378 } | |
| 379 | |
| 380 ExtensionAPIPermission::ExtensionAPIPermission( | |
| 381 ExtensionPermissionsInfo* info, | |
| 382 const char* name, | |
| 383 bool is_hosted_app, | |
| 384 bool is_component_only, | |
| 385 int l10n_message_id, | |
| 386 ExtensionPermissionMessage::MessageId message_id) | |
| 387 : name_(name), | |
| 388 is_hosted_app_(is_hosted_app), | |
| 389 is_component_only_(is_component_only), | |
| 390 l10n_message_id_(l10n_message_id), | |
| 391 message_id_(message_id) { | |
| 392 // Update the permission counts when we create a new one. | |
| 393 permission_count_++; | |
| 394 | |
| 395 if (is_hosted_app) | |
| 396 hosted_app_permission_count_++; | |
| 397 | |
| 398 info->permissions_[name] = this; | |
| 399 } | |
| 400 | |
| 401 ExtensionAPIPermission::~ExtensionAPIPermission() { | |
| 402 } | |
| 403 | |
| 404 bool ExtensionAPIPermission::operator==( | |
| 405 const ExtensionAPIPermission& permission) const { | |
| 406 return name_ == permission.name_; | |
| 407 } | |
| 408 | |
| 409 bool ExtensionAPIPermission::operator<( | |
| 410 const ExtensionAPIPermission& permission) const { | |
| 411 return name_ < permission.name_; | |
| 412 } | |
| 413 | |
| 414 // | |
| 415 // ExtensionPermissionSet | |
| 416 // | |
| 417 | |
| 418 | |
| 419 ExtensionPermissionSet::ExtensionPermissionSet() | |
| 420 : native_code_(false) { | |
| 421 } | |
| 422 | |
| 423 ExtensionPermissionSet::ExtensionPermissionSet( | |
| 424 Extension* extension, | |
| 425 std::set<ExtensionAPIPermission> apis, | |
| 426 URLPatternList hosts) : apis_(apis), | |
| 427 native_code_(false) { | |
| 428 InitFromExtension(extension, hosts); | |
| 429 } | |
| 430 | |
| 431 ExtensionPermissionSet::ExtensionPermissionSet( | |
| 432 bool native_code, | |
| 433 std::set<ExtensionAPIPermission> apis, | |
| 434 URLPatternSet effective_hosts) : apis_(apis), | |
| 435 effective_hosts_(effective_hosts), | |
| 436 native_code_(native_code) { | |
| 437 } | |
| 438 | |
| 439 ExtensionPermissionSet::~ExtensionPermissionSet() { | |
| 440 } | |
| 441 | |
| 442 // static | |
| 443 ExtensionPermissionSet* ExtensionPermissionSet::CreateUnion( | |
| 444 const ExtensionPermissionSet& set1, | |
| 445 const ExtensionPermissionSet& set2) { | |
| 446 bool full_access = set1.native_code() || set2.native_code(); | |
| 447 | |
| 448 std::set<ExtensionAPIPermission> apis; | |
| 449 std::set_union(set1.apis_.begin(), set1.apis_.end(), | |
| 450 set2.apis_.begin(), set2.apis_.end(), | |
| 451 std::insert_iterator<std::set<ExtensionAPIPermission> >( | |
| 452 apis, apis.begin())); | |
| 453 | |
| 454 URLPatternSet new_hosts = set1.effective_hosts_; | |
| 455 URLPatternList hosts2 = set2.effective_hosts_.patterns(); | |
| 456 URLPatternList new_host_list = new_hosts.patterns(); | |
| 457 | |
| 458 for (URLPatternList::const_iterator i = hosts2.begin(); | |
| 459 i != hosts2.end(); ++i) { | |
| 460 bool duplicate = false; | |
| 461 for (URLPatternList::const_iterator j = new_host_list.begin(); | |
| 462 j != new_host_list.end(); ++j) { | |
| 463 if (j->GetAsString() == i->GetAsString()) { | |
| 464 duplicate = true; | |
| 465 break; | |
| 466 } | |
| 467 } | |
| 468 if (!duplicate) | |
| 469 new_hosts.AddPattern(*i); | |
| 470 } | |
| 471 | |
| 472 return new ExtensionPermissionSet(full_access, apis, new_hosts); | |
| 473 } | |
| 474 | |
| 475 // static | |
| 476 ExtensionPermissionSet* ExtensionPermissionSet::CreateDifference( | |
| 477 const ExtensionPermissionSet& set1, | |
| 478 const ExtensionPermissionSet& set2) { | |
| 479 NOTREACHED(); | |
| 480 return NULL; | |
| 481 } | |
| 482 | |
| 483 // static | |
| 484 ExtensionPermissionSet* ExtensionPermissionSet::CreateIntersection( | |
| 485 const ExtensionPermissionSet& set1, | |
| 486 const ExtensionPermissionSet& set2) { | |
| 487 NOTREACHED(); | |
| 488 return NULL; | |
| 489 } | |
| 490 | |
| 491 bool ExtensionPermissionSet::Contains( | |
| 492 const ExtensionPermissionSet& set) const { | |
| 493 NOTREACHED(); | |
| 494 return false; | |
| 495 } | |
| 496 | |
| 497 ExtensionPermissionMessages | |
| 498 ExtensionPermissionSet::GetPermissionMessages() const { | |
| 499 ExtensionPermissionMessages messages; | |
| 500 | |
| 501 if (native_code_) { | |
| 502 messages.push_back(ExtensionPermissionMessage( | |
| 503 ExtensionPermissionMessage::ID_FULL_ACCESS, | |
| 504 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS))); | |
| 505 return messages; | |
| 506 } | |
| 507 | |
| 508 if (HasEffectiveAccessToAllHosts()) { | |
| 509 messages.push_back(ExtensionPermissionMessage( | |
| 510 ExtensionPermissionMessage::ID_HOSTS_ALL, | |
| 511 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS))); | |
| 512 } else { | |
| 513 std::vector<std::string> hosts = GetDistinctHostsForDisplay(); | |
| 514 if (!hosts.empty()) | |
| 515 messages.push_back(ExtensionPermissionMessage::CreateFromHostList(hosts)); | |
| 516 } | |
| 517 | |
| 518 std::set<ExtensionPermissionMessage> simple_msgs = | |
| 519 GetSimplePermissionMessages(); | |
| 520 messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end()); | |
| 521 | |
| 522 return messages; | |
| 523 } | |
| 524 | |
| 525 std::vector<string16> ExtensionPermissionSet::GetWarningMessages() const { | |
| 526 std::vector<string16> messages; | |
| 527 ExtensionPermissionMessages permissions = GetPermissionMessages(); | |
| 528 for (ExtensionPermissionMessages::const_iterator i = permissions.begin(); | |
| 529 i != permissions.end(); ++i) | |
| 530 messages.push_back(i->message()); | |
| 531 return messages; | |
| 532 } | |
| 533 | |
| 534 bool ExtensionPermissionSet::IsEmpty() const { | |
| 535 return !native_code_ && apis_.empty() && effective_hosts_.is_empty(); | |
| 536 } | |
| 537 | |
| 538 bool ExtensionPermissionSet::HasAPIPermission( | |
| 539 const ExtensionAPIPermission& permission) const { | |
| 540 return apis_.count(permission) > 0; | |
| 541 } | |
| 542 | |
| 543 bool ExtensionPermissionSet::HasAccessToFunction( | |
| 544 const std::string& function_name) const { | |
| 545 // TODO(jstritar): Embed this information in each permission and add a method | |
| 546 // like GrantsAccess(function_name) to ExtensionAPIPermission. A "default" | |
| 547 // permission can then handle the modules and functions that everyone can | |
| 548 // access. | |
| 549 | |
| 550 std::string permission_name = function_name; | |
| 551 | |
| 552 for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) { | |
| 553 if (permission_name == kNonPermissionFunctionNames[i]) | |
| 554 return true; | |
| 555 } | |
| 556 | |
| 557 // See if this is a function or event name first and strip out the package. | |
| 558 // Functions will be of the form package.function | |
| 559 // Events will be of the form package/id or package.optional.stuff | |
| 560 size_t separator = function_name.find_first_of("./"); | |
| 561 if (separator != std::string::npos) | |
| 562 permission_name = function_name.substr(0, separator); | |
| 563 | |
| 564 ExtensionAPIPermission* permission = | |
| 565 ExtensionAPIPermission::GetByName(permission_name); | |
| 566 if (permission && apis_.count(*permission)) | |
| 567 return true; | |
| 568 | |
| 569 for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) { | |
| 570 if (permission_name == kNonPermissionModuleNames[i]) { | |
| 571 return true; | |
| 572 } | |
| 573 } | |
| 574 | |
| 575 return false; | |
| 576 } | |
| 577 | |
| 578 bool ExtensionPermissionSet::HasAccessToHost(const GURL& origin) const { | |
| 579 const URLPatternList patterns = effective_hosts_.patterns(); | |
| 580 for (URLPatternList::const_iterator host = patterns.begin(); | |
| 581 host != patterns.end(); ++host) { | |
| 582 if (host->MatchesURL(origin)) | |
| 583 return true; | |
| 584 } | |
| 585 | |
| 586 return false; | |
| 587 } | |
| 588 | |
| 589 bool ExtensionPermissionSet::HasEffectiveAccessToAllHosts() const { | |
| 590 const URLPatternList patterns = effective_hosts_.patterns(); | |
| 591 for (URLPatternList::const_iterator host = patterns.begin(); | |
| 592 host != patterns.end(); ++host) { | |
| 593 if (host->match_all_urls() || | |
| 594 (host->match_subdomains() && host->host().empty())) | |
| 595 return true; | |
| 596 } | |
| 597 | |
| 598 return false; | |
| 599 } | |
| 600 | |
| 601 | |
| 602 bool ExtensionPermissionSet::HasPrivatePermissions() const { | |
| 603 for (std::set<ExtensionAPIPermission>::const_iterator i = apis_.begin(); | |
| 604 i != apis_.end(); ++i) { | |
| 605 if (i->is_component_only()) | |
| 606 return true; | |
| 607 } | |
| 608 return false; | |
| 609 } | |
| 610 | |
| 611 // static | |
| 612 std::vector<std::string> ExtensionPermissionSet::GetDistinctHosts( | |
| 613 const URLPatternList& host_patterns, bool include_rcd) { | |
| 614 // Use a vector to preserve order (also faster than a map on small sets). | |
| 615 // Each item is a host split into two parts: host without RCDs and | |
| 616 // current best RCD. | |
| 617 typedef std::vector<std::pair<std::string, std::string> > HostVector; | |
| 618 HostVector hosts_best_rcd; | |
| 619 for (size_t i = 0; i < host_patterns.size(); ++i) { | |
| 620 std::string host = host_patterns[i].host(); | |
| 621 | |
| 622 // Add the subdomain wildcard back to the host, if necessary. | |
| 623 if (host_patterns[i].match_subdomains()) | |
| 624 host = "*." + host; | |
| 625 | |
| 626 // If the host has an RCD, split it off so we can detect duplicates. | |
| 627 std::string rcd; | |
| 628 size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength( | |
| 629 host, false); | |
| 630 if (reg_len && reg_len != std::string::npos) { | |
| 631 if (include_rcd) // else leave rcd empty | |
| 632 rcd = host.substr(host.size() - reg_len); | |
| 633 host = host.substr(0, host.size() - reg_len); | |
| 634 } | |
| 635 | |
| 636 // Check if we've already seen this host. | |
| 637 HostVector::iterator it = hosts_best_rcd.begin(); | |
| 638 for (; it != hosts_best_rcd.end(); ++it) { | |
| 639 if (it->first == host) | |
| 640 break; | |
| 641 } | |
| 642 // If this host was found, replace the RCD if this one is better. | |
| 643 if (it != hosts_best_rcd.end()) { | |
| 644 if (include_rcd && RcdBetterThan(rcd, it->second)) | |
| 645 it->second = rcd; | |
| 646 } else { // Previously unseen host, append it. | |
| 647 hosts_best_rcd.push_back(std::make_pair(host, rcd)); | |
| 648 } | |
| 649 } | |
| 650 | |
| 651 // Build up the final vector by concatenating hosts and RCDs. | |
| 652 std::vector<std::string> distinct_hosts; | |
| 653 for (HostVector::iterator it = hosts_best_rcd.begin(); | |
| 654 it != hosts_best_rcd.end(); ++it) | |
| 655 distinct_hosts.push_back(it->first + it->second); | |
| 656 return distinct_hosts; | |
| 657 } | |
| 658 | |
| 659 void ExtensionPermissionSet::InitFromExtension( | |
| 660 Extension* extension, | |
| 661 const URLPatternList& hosts_) { | |
| 662 native_code_ = !extension->plugins().empty(); | |
| 663 | |
| 664 // Initialize the effective host permissions. | |
| 665 for (URLPatternList::const_iterator host = hosts_.begin(); | |
| 666 host != hosts_.end(); ++host) | |
| 667 effective_hosts_.AddPattern(*host); | |
| 668 | |
| 669 for (UserScriptList::const_iterator content_script = | |
| 670 extension->content_scripts().begin(); | |
| 671 content_script != extension->content_scripts().end(); ++content_script) { | |
| 672 URLPatternList::const_iterator pattern = | |
| 673 content_script->url_patterns().begin(); | |
| 674 for (; pattern != content_script->url_patterns().end(); ++pattern) | |
| 675 effective_hosts_.AddPattern(*pattern); | |
| 676 } | |
| 677 | |
| 678 if (HasAPIPermission(ExtensionAPIPermission::Proxy()) || | |
| 679 !extension->devtools_url().is_empty()) { | |
| 680 URLPattern all_urls(URLPattern::SCHEME_ALL); | |
| 681 all_urls.set_match_all_urls(true); | |
| 682 effective_hosts_.AddPattern(all_urls); | |
| 683 } | |
| 684 | |
| 685 } | |
| 686 | |
| 687 std::set<std::string> ExtensionPermissionSet::GetAPIsAsStrings() const { | |
| 688 std::set<std::string> apis_str; | |
| 689 for (std::set<ExtensionAPIPermission>::iterator i = apis_.begin(); | |
| 690 i != apis_.end(); ++i) | |
| 691 apis_str.insert(i->name()); | |
| 692 return apis_str; | |
| 693 } | |
| 694 | |
| 695 std::vector<std::string> | |
| 696 ExtensionPermissionSet::GetDistinctHostsForDisplay() const { | |
| 697 return GetDistinctHosts(effective_hosts_.patterns(), true); | |
| 698 } | |
| 699 | |
| 700 string16 ExtensionPermissionSet::GetHostPermissionMessage() const { | |
| 701 if (HasEffectiveAccessToAllHosts()) | |
| 702 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS); | |
| 703 | |
| 704 std::vector<std::string> hosts = GetDistinctHostsForDisplay(); | |
| 705 | |
| 706 if (hosts.size() == 1) { | |
| 707 return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_1_HOST, | |
| 708 UTF8ToUTF16(hosts[0])); | |
| 709 } else if (hosts.size() == 2) { | |
| 710 return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, | |
| 711 UTF8ToUTF16(hosts[0]), | |
| 712 UTF8ToUTF16(hosts[1])); | |
| 713 } else if (hosts.size() == 3) { | |
| 714 return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, | |
| 715 UTF8ToUTF16(hosts[0]), | |
| 716 UTF8ToUTF16(hosts[1]), | |
| 717 UTF8ToUTF16(hosts[2])); | |
| 718 } else if (hosts.size() >= 4) { | |
| 719 return l10n_util::GetStringFUTF16( | |
| 720 IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS, | |
| 721 UTF8ToUTF16(hosts[0]), | |
| 722 UTF8ToUTF16(hosts[1]), | |
| 723 base::IntToString16(hosts.size() - 2)); | |
| 724 } | |
| 725 | |
| 726 return string16(); | |
| 727 } | |
| 728 | |
| 729 std::set<ExtensionPermissionMessage> | |
| 730 ExtensionPermissionSet::GetSimplePermissionMessages() const { | |
| 731 std::set<ExtensionPermissionMessage> messages; | |
| 732 std::set<ExtensionAPIPermission>::const_iterator i; | |
| 733 for (i = apis_.begin(); i != apis_.end(); ++i) { | |
| 734 DCHECK_GT(ExtensionPermissionMessage::ID_NONE, | |
| 735 ExtensionPermissionMessage::ID_UNKNOWN); | |
| 736 if (i->message_id() > ExtensionPermissionMessage::ID_NONE) | |
| 737 messages.insert(i->GetMessage()); | |
| 738 } | |
| 739 return messages; | |
| 740 } | |
| 741 | |
| 742 bool ExtensionPermissionSet::HasLessAPIPrivilegesThan( | |
| 743 const ExtensionPermissionSet& permissions) { | |
| 744 std::set<ExtensionAPIPermission> new_apis = permissions.apis_; | |
| 745 std::set<ExtensionAPIPermission> new_apis_only; | |
| 746 std::set_difference(new_apis.begin(), new_apis.end(), | |
| 747 apis_.begin(), apis_.end(), | |
| 748 std::inserter(new_apis_only, new_apis_only.begin())); | |
| 749 | |
| 750 // Ignore API permissions that don't require user approval when deciding if | |
| 751 // an extension has increased its privileges. | |
| 752 size_t new_api_count = 0; | |
| 753 for (std::set<ExtensionAPIPermission>::iterator i = new_apis_only.begin(); | |
| 754 i != new_apis_only.end(); ++i) { | |
| 755 if (i->message_id() > ExtensionPermissionMessage::ID_NONE) | |
| 756 new_api_count++; | |
| 757 } | |
| 758 | |
| 759 return new_api_count > 0; | |
| 760 } | |
| 761 | |
| 762 bool ExtensionPermissionSet::HasLessHostPrivilegesThan( | |
| 763 const ExtensionPermissionSet& permissions) { | |
| 764 // If this permission set can access any host, then it can't be elevated. | |
| 765 if (HasEffectiveAccessToAllHosts()) | |
| 766 return false; | |
| 767 | |
| 768 // Likewise, if the other permission set has full host access, then it must be | |
| 769 // a privilege increase. | |
| 770 if (permissions.HasEffectiveAccessToAllHosts()) | |
| 771 return true; | |
| 772 | |
| 773 const URLPatternList old_list = effective_hosts_.patterns(); | |
| 774 const URLPatternList new_list = | |
| 775 permissions.effective_hosts_.patterns(); | |
| 776 | |
| 777 // TODO(jstritar): This is overly conservative with respect to subdomains. | |
| 778 // For example, going from *.google.com to www.google.com will be | |
| 779 // considered an elevation, even though it is not (http://crbug.com/65337). | |
| 780 std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false); | |
| 781 std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false); | |
| 782 | |
| 783 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end()); | |
| 784 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end()); | |
| 785 std::set<std::string> new_hosts_only; | |
| 786 | |
| 787 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), | |
| 788 old_hosts_set.begin(), old_hosts_set.end(), | |
| 789 std::inserter(new_hosts_only, new_hosts_only.begin())); | |
| 790 | |
| 791 return !new_hosts_only.empty(); | |
| 792 } | |
| 793 | |
| 794 bool ExtensionPermissionSet::HasLessPrivilegesThan( | |
| 795 const ExtensionPermissionSet& permissions) { | |
| 796 // Things can't get worse native code access. | |
| 797 if (native_code_) | |
| 798 return false; | |
| 799 | |
| 800 // Otherwise, it's a privilege increase if the new one has full access. | |
| 801 if (permissions.native_code_) | |
| 802 return true; | |
| 803 | |
| 804 if (HasLessHostPrivilegesThan(permissions)) | |
| 805 return true; | |
| 806 | |
| 807 if (HasLessAPIPrivilegesThan(permissions)) | |
| 808 return true; | |
| 809 | |
| 810 return false; | |
| 811 | |
| 812 } | |
| OLD | NEW |