| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/extensions/extension.h" | 5 #include "chrome/common/extensions/extension.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 | 91 |
| 92 bool IsBaseCrxKey(const std::string& key) { | 92 bool IsBaseCrxKey(const std::string& key) { |
| 93 for (size_t i = 0; i < arraysize(kBaseCrxKeys); ++i) { | 93 for (size_t i = 0; i < arraysize(kBaseCrxKeys); ++i) { |
| 94 if (key == kBaseCrxKeys[i]) | 94 if (key == kBaseCrxKeys[i]) |
| 95 return true; | 95 return true; |
| 96 } | 96 } |
| 97 | 97 |
| 98 return false; | 98 return false; |
| 99 } | 99 } |
| 100 | 100 |
| 101 // Constant used to represent an undefined l10n message id. | |
| 102 const int kUndefinedMessageId = -1; | |
| 103 | |
| 104 // Names of API modules that do not require a permission. | |
| 105 const char kBrowserActionModuleName[] = "browserAction"; | |
| 106 const char kBrowserActionsModuleName[] = "browserActions"; | |
| 107 const char kDevToolsModuleName[] = "devtools"; | |
| 108 const char kExtensionModuleName[] = "extension"; | |
| 109 const char kI18NModuleName[] = "i18n"; | |
| 110 const char kOmniboxModuleName[] = "omnibox"; | |
| 111 const char kPageActionModuleName[] = "pageAction"; | |
| 112 const char kPageActionsModuleName[] = "pageActions"; | |
| 113 const char kTestModuleName[] = "test"; | |
| 114 const char kTypesModuleName[] = "types"; | |
| 115 | |
| 116 // Names of modules that can be used without listing it in the permissions | |
| 117 // section of the manifest. | |
| 118 const char* kNonPermissionModuleNames[] = { | |
| 119 kBrowserActionModuleName, | |
| 120 kBrowserActionsModuleName, | |
| 121 kDevToolsModuleName, | |
| 122 kExtensionModuleName, | |
| 123 kI18NModuleName, | |
| 124 kOmniboxModuleName, | |
| 125 kPageActionModuleName, | |
| 126 kPageActionsModuleName, | |
| 127 kTestModuleName, | |
| 128 kTypesModuleName | |
| 129 }; | |
| 130 const size_t kNumNonPermissionModuleNames = | |
| 131 arraysize(kNonPermissionModuleNames); | |
| 132 | |
| 133 // Names of functions (within modules requiring permissions) that can be used | |
| 134 // without asking for the module permission. In other words, functions you can | |
| 135 // use with no permissions specified. | |
| 136 const char* kNonPermissionFunctionNames[] = { | |
| 137 "tabs.create", | |
| 138 "tabs.onRemoved", | |
| 139 "tabs.remove", | |
| 140 "tabs.update", | |
| 141 }; | |
| 142 const size_t kNumNonPermissionFunctionNames = | |
| 143 arraysize(kNonPermissionFunctionNames); | |
| 144 | |
| 145 // A singleton object containing global data needed by the extension objects. | 101 // A singleton object containing global data needed by the extension objects. |
| 146 class ExtensionConfig { | 102 class ExtensionConfig { |
| 147 public: | 103 public: |
| 148 static ExtensionConfig* GetInstance() { | 104 static ExtensionConfig* GetInstance() { |
| 149 return Singleton<ExtensionConfig>::get(); | 105 return Singleton<ExtensionConfig>::get(); |
| 150 } | 106 } |
| 151 | 107 |
| 152 Extension::PermissionMessage::MessageId GetPermissionMessageId( | |
| 153 const std::string& permission) { | |
| 154 return Extension::kPermissions[permission_map_[permission]].message_id; | |
| 155 } | |
| 156 | |
| 157 Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; } | 108 Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; } |
| 158 | 109 |
| 159 private: | 110 private: |
| 160 friend struct DefaultSingletonTraits<ExtensionConfig>; | 111 friend struct DefaultSingletonTraits<ExtensionConfig>; |
| 161 | 112 |
| 162 ExtensionConfig() { | 113 ExtensionConfig() { } |
| 163 for (size_t i = 0; i < Extension::kNumPermissions; ++i) | |
| 164 permission_map_[Extension::kPermissions[i].name] = i; | |
| 165 }; | |
| 166 | |
| 167 ~ExtensionConfig() { } | 114 ~ExtensionConfig() { } |
| 168 | 115 |
| 169 std::map<const std::string, size_t> permission_map_; | |
| 170 | |
| 171 // A whitelist of extensions that can script anywhere. Do not add to this | 116 // A whitelist of extensions that can script anywhere. Do not add to this |
| 172 // list (except in tests) without consulting the Extensions team first. | 117 // list (except in tests) without consulting the Extensions team first. |
| 173 // Note: Component extensions have this right implicitly and do not need to be | 118 // Note: Component extensions have this right implicitly and do not need to be |
| 174 // added to this list. | 119 // added to this list. |
| 175 Extension::ScriptingWhitelist scripting_whitelist_; | 120 Extension::ScriptingWhitelist scripting_whitelist_; |
| 176 }; | 121 }; |
| 177 | 122 |
| 178 // Aliased to kTabPermission for purposes of API checks, but not allowed | |
| 179 // in the permissions field of the manifest. | |
| 180 static const char kWindowPermission[] = "windows"; | |
| 181 | |
| 182 // Rank extension locations in a way that allows | 123 // Rank extension locations in a way that allows |
| 183 // Extension::GetHigherPriorityLocation() to compare locations. | 124 // Extension::GetHigherPriorityLocation() to compare locations. |
| 184 // An extension installed from two locations will have the location | 125 // An extension installed from two locations will have the location |
| 185 // with the higher rank, as returned by this function. The actual | 126 // with the higher rank, as returned by this function. The actual |
| 186 // integer values may change, and should never be persisted. | 127 // integer values may change, and should never be persisted. |
| 187 int GetLocationRank(Extension::Location location) { | 128 int GetLocationRank(Extension::Location location) { |
| 188 const int kInvalidRank = -1; | 129 const int kInvalidRank = -1; |
| 189 int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank. | 130 int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank. |
| 190 | 131 |
| 191 switch (location) { | 132 switch (location) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 EXTENSION_ICON_MEDIUM, | 198 EXTENSION_ICON_MEDIUM, |
| 258 EXTENSION_ICON_SMALL, | 199 EXTENSION_ICON_SMALL, |
| 259 EXTENSION_ICON_SMALLISH, | 200 EXTENSION_ICON_SMALLISH, |
| 260 EXTENSION_ICON_BITTY | 201 EXTENSION_ICON_BITTY |
| 261 }; | 202 }; |
| 262 | 203 |
| 263 const int Extension::kPageActionIconMaxSize = 19; | 204 const int Extension::kPageActionIconMaxSize = 19; |
| 264 const int Extension::kBrowserActionIconMaxSize = 19; | 205 const int Extension::kBrowserActionIconMaxSize = 19; |
| 265 const int Extension::kSidebarIconMaxSize = 16; | 206 const int Extension::kSidebarIconMaxSize = 16; |
| 266 | 207 |
| 267 // Explicit permissions -- permission declaration required. | |
| 268 const char Extension::kBackgroundPermission[] = "background"; | |
| 269 const char Extension::kBookmarkPermission[] = "bookmarks"; | |
| 270 const char Extension::kClipboardReadPermission[] = "clipboardRead"; | |
| 271 const char Extension::kClipboardWritePermission[] = "clipboardWrite"; | |
| 272 const char Extension::kContextMenusPermission[] = "contextMenus"; | |
| 273 const char Extension::kContentSettingsPermission[] = "contentSettings"; | |
| 274 const char Extension::kCookiePermission[] = "cookies"; | |
| 275 const char Extension::kChromePrivatePermission[] = "chromePrivate"; | |
| 276 const char Extension::kChromeosInfoPrivatePermission[] = "chromeosInfoPrivate"; | |
| 277 const char Extension::kDebuggerPermission[] = "debugger"; | |
| 278 const char Extension::kExperimentalPermission[] = "experimental"; | |
| 279 const char Extension::kFileBrowserHandlerPermission[] = "fileBrowserHandler"; | |
| 280 const char Extension::kFileBrowserPrivatePermission[] = "fileBrowserPrivate"; | |
| 281 const char Extension::kGeolocationPermission[] = "geolocation"; | |
| 282 const char Extension::kHistoryPermission[] = "history"; | |
| 283 const char Extension::kIdlePermission[] = "idle"; | |
| 284 const char Extension::kManagementPermission[] = "management"; | |
| 285 const char Extension::kMediaPlayerPrivatePermission[] = "mediaPlayerPrivate"; | |
| 286 const char Extension::kNotificationPermission[] = "notifications"; | |
| 287 const char Extension::kProxyPermission[] = "proxy"; | |
| 288 const char Extension::kTabPermission[] = "tabs"; | |
| 289 const char Extension::kUnlimitedStoragePermission[] = "unlimitedStorage"; | |
| 290 const char Extension::kWebstorePrivatePermission[] = "webstorePrivate"; | |
| 291 const char Extension::kWebSocketProxyPrivatePermission[] = | |
| 292 "webSocketProxyPrivate"; | |
| 293 | |
| 294 // In general, all permissions should have an install message. | |
| 295 // See ExtensionsTest.PermissionMessages for an explanation of each | |
| 296 // exception. | |
| 297 const Extension::Permission Extension::kPermissions[] = { | |
| 298 { kBackgroundPermission, PermissionMessage::ID_NONE }, | |
| 299 { kBookmarkPermission, PermissionMessage::ID_BOOKMARKS }, | |
| 300 { kChromePrivatePermission, PermissionMessage::ID_NONE }, | |
| 301 { kChromeosInfoPrivatePermission, PermissionMessage::ID_NONE }, | |
| 302 { kClipboardReadPermission, PermissionMessage::ID_CLIPBOARD }, | |
| 303 { kClipboardWritePermission, PermissionMessage::ID_NONE }, | |
| 304 { kContentSettingsPermission, PermissionMessage::ID_NONE }, | |
| 305 { kContextMenusPermission, PermissionMessage::ID_NONE }, | |
| 306 { kCookiePermission, PermissionMessage::ID_NONE }, | |
| 307 { kDebuggerPermission, PermissionMessage::ID_DEBUGGER }, | |
| 308 { kExperimentalPermission, PermissionMessage::ID_NONE }, | |
| 309 { kFileBrowserHandlerPermission, PermissionMessage::ID_NONE }, | |
| 310 { kFileBrowserPrivatePermission, PermissionMessage::ID_NONE }, | |
| 311 { kGeolocationPermission, PermissionMessage::ID_GEOLOCATION }, | |
| 312 { kHistoryPermission, PermissionMessage::ID_BROWSING_HISTORY }, | |
| 313 { kIdlePermission, PermissionMessage::ID_NONE }, | |
| 314 { kManagementPermission, PermissionMessage::ID_MANAGEMENT }, | |
| 315 { kMediaPlayerPrivatePermission, PermissionMessage::ID_NONE }, | |
| 316 { kNotificationPermission, PermissionMessage::ID_NONE }, | |
| 317 { kProxyPermission, PermissionMessage::ID_NONE }, | |
| 318 { kTabPermission, PermissionMessage::ID_TABS }, | |
| 319 { kUnlimitedStoragePermission, PermissionMessage::ID_NONE }, | |
| 320 { kWebSocketProxyPrivatePermission, PermissionMessage::ID_NONE }, | |
| 321 { kWebstorePrivatePermission, PermissionMessage::ID_NONE }, | |
| 322 }; | |
| 323 const size_t Extension::kNumPermissions = arraysize(Extension::kPermissions); | |
| 324 | |
| 325 const char* const Extension::kHostedAppPermissionNames[] = { | |
| 326 Extension::kBackgroundPermission, | |
| 327 Extension::kChromePrivatePermission, | |
| 328 Extension::kClipboardReadPermission, | |
| 329 Extension::kClipboardWritePermission, | |
| 330 Extension::kExperimentalPermission, | |
| 331 Extension::kGeolocationPermission, | |
| 332 Extension::kNotificationPermission, | |
| 333 Extension::kUnlimitedStoragePermission, | |
| 334 Extension::kWebstorePrivatePermission, | |
| 335 }; | |
| 336 const size_t Extension::kNumHostedAppPermissions = | |
| 337 arraysize(Extension::kHostedAppPermissionNames); | |
| 338 | |
| 339 const char* const Extension::kComponentPrivatePermissionNames[] = { | |
| 340 Extension::kFileBrowserPrivatePermission, | |
| 341 Extension::kWebstorePrivatePermission, | |
| 342 Extension::kMediaPlayerPrivatePermission, | |
| 343 Extension::kChromeosInfoPrivatePermission, | |
| 344 }; | |
| 345 const size_t Extension::kNumComponentPrivatePermissions = | |
| 346 arraysize(Extension::kComponentPrivatePermissionNames); | |
| 347 | |
| 348 // We purposefully don't put this into kPermissionNames. | |
| 349 const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage"; | |
| 350 | |
| 351 const int Extension::kValidWebExtentSchemes = | 208 const int Extension::kValidWebExtentSchemes = |
| 352 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS; | 209 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS; |
| 353 | 210 |
| 354 const int Extension::kValidHostPermissionSchemes = | 211 const int Extension::kValidHostPermissionSchemes = |
| 355 UserScript::kValidUserScriptSchemes | URLPattern::SCHEME_CHROMEUI; | 212 UserScript::kValidUserScriptSchemes | URLPattern::SCHEME_CHROMEUI; |
| 356 | 213 |
| 357 Extension::InputComponentInfo::InputComponentInfo() {} | 214 Extension::InputComponentInfo::InputComponentInfo() {} |
| 358 Extension::InputComponentInfo::~InputComponentInfo() {} | 215 Extension::InputComponentInfo::~InputComponentInfo() {} |
| 359 | 216 |
| 360 // | 217 // |
| 361 // PermissionMessage | |
| 362 // | |
| 363 | |
| 364 // static | |
| 365 Extension::PermissionMessage Extension::PermissionMessage::CreateFromMessageId( | |
| 366 Extension::PermissionMessage::MessageId message_id) { | |
| 367 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 368 if (message_id <= ID_NONE) | |
| 369 return PermissionMessage(message_id, string16()); | |
| 370 | |
| 371 string16 message = l10n_util::GetStringUTF16(kMessageIds[message_id]); | |
| 372 return PermissionMessage(message_id, message); | |
| 373 } | |
| 374 | |
| 375 // static | |
| 376 Extension::PermissionMessage Extension::PermissionMessage::CreateFromHostList( | |
| 377 const std::vector<std::string> hosts) { | |
| 378 CHECK(hosts.size() > 0); | |
| 379 | |
| 380 MessageId message_id; | |
| 381 string16 message; | |
| 382 switch (hosts.size()) { | |
| 383 case 1: | |
| 384 message_id = ID_HOSTS_1; | |
| 385 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 386 UTF8ToUTF16(hosts[0])); | |
| 387 break; | |
| 388 case 2: | |
| 389 message_id = ID_HOSTS_2; | |
| 390 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 391 UTF8ToUTF16(hosts[0]), | |
| 392 UTF8ToUTF16(hosts[1])); | |
| 393 break; | |
| 394 case 3: | |
| 395 message_id = ID_HOSTS_3; | |
| 396 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 397 UTF8ToUTF16(hosts[0]), | |
| 398 UTF8ToUTF16(hosts[1]), | |
| 399 UTF8ToUTF16(hosts[2])); | |
| 400 break; | |
| 401 default: | |
| 402 message_id = ID_HOSTS_4_OR_MORE; | |
| 403 message = l10n_util::GetStringFUTF16( | |
| 404 kMessageIds[message_id], | |
| 405 UTF8ToUTF16(hosts[0]), | |
| 406 UTF8ToUTF16(hosts[1]), | |
| 407 base::IntToString16(hosts.size() - 2)); | |
| 408 break; | |
| 409 } | |
| 410 | |
| 411 return PermissionMessage(message_id, message); | |
| 412 } | |
| 413 | |
| 414 Extension::PermissionMessage::PermissionMessage( | |
| 415 Extension::PermissionMessage::MessageId message_id, string16 message) | |
| 416 : message_id_(message_id), | |
| 417 message_(message) { | |
| 418 } | |
| 419 | |
| 420 const int Extension::PermissionMessage::kMessageIds[] = { | |
| 421 kUndefinedMessageId, // "unknown" | |
| 422 kUndefinedMessageId, // "none" | |
| 423 IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS, | |
| 424 IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION, | |
| 425 IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY, | |
| 426 IDS_EXTENSION_PROMPT_WARNING_TABS, | |
| 427 IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT, | |
| 428 IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, | |
| 429 IDS_EXTENSION_PROMPT_WARNING_1_HOST, | |
| 430 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, | |
| 431 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, | |
| 432 IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS, | |
| 433 IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS, | |
| 434 IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, | |
| 435 IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD | |
| 436 }; | |
| 437 | |
| 438 // | |
| 439 // Extension | 218 // Extension |
| 440 // | 219 // |
| 441 | 220 |
| 442 // static | 221 // static |
| 443 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 222 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
| 444 Location location, | 223 Location location, |
| 445 const DictionaryValue& value, | 224 const DictionaryValue& value, |
| 446 int flags, | 225 int flags, |
| 447 std::string* error) { | 226 std::string* error) { |
| 448 scoped_refptr<Extension> extension = new Extension(path, location); | 227 scoped_refptr<Extension> extension = new Extension(path, location); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 478 int loc2_rank = GetLocationRank(loc2); | 257 int loc2_rank = GetLocationRank(loc2); |
| 479 | 258 |
| 480 // If two different locations have the same rank, then we can not | 259 // If two different locations have the same rank, then we can not |
| 481 // deterministicly choose a location. | 260 // deterministicly choose a location. |
| 482 CHECK(loc1_rank != loc2_rank); | 261 CHECK(loc1_rank != loc2_rank); |
| 483 | 262 |
| 484 // Lowest rank has highest priority. | 263 // Lowest rank has highest priority. |
| 485 return (loc1_rank > loc2_rank ? loc1 : loc2 ); | 264 return (loc1_rank > loc2_rank ? loc1 : loc2 ); |
| 486 } | 265 } |
| 487 | 266 |
| 488 // static | 267 ExtensionPermissionMessages Extension::GetPermissionMessages() const { |
| 489 Extension::PermissionMessage::MessageId Extension::GetPermissionMessageId( | 268 return permission_set_->GetPermissionMessages(); |
| 490 const std::string& permission) { | |
| 491 return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission); | |
| 492 } | |
| 493 | |
| 494 Extension::PermissionMessages Extension::GetPermissionMessages() const { | |
| 495 PermissionMessages messages; | |
| 496 if (!plugins().empty()) { | |
| 497 messages.push_back(PermissionMessage::CreateFromMessageId( | |
| 498 PermissionMessage::ID_FULL_ACCESS)); | |
| 499 return messages; | |
| 500 } | |
| 501 | |
| 502 if (HasEffectiveAccessToAllHosts()) { | |
| 503 messages.push_back(PermissionMessage::CreateFromMessageId( | |
| 504 PermissionMessage::ID_HOSTS_ALL)); | |
| 505 } else { | |
| 506 std::vector<std::string> hosts = GetDistinctHostsForDisplay( | |
| 507 GetEffectiveHostPermissions().patterns()); | |
| 508 if (!hosts.empty()) | |
| 509 messages.push_back(PermissionMessage::CreateFromHostList(hosts)); | |
| 510 } | |
| 511 | |
| 512 std::set<PermissionMessage> simple_msgs = GetSimplePermissionMessages(); | |
| 513 messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end()); | |
| 514 | |
| 515 return messages; | |
| 516 } | 269 } |
| 517 | 270 |
| 518 std::vector<string16> Extension::GetPermissionMessageStrings() const { | 271 std::vector<string16> Extension::GetPermissionMessageStrings() const { |
| 519 std::vector<string16> messages; | 272 return permission_set_->GetWarningMessages(); |
| 520 PermissionMessages permissions = GetPermissionMessages(); | |
| 521 for (PermissionMessages::const_iterator i = permissions.begin(); | |
| 522 i != permissions.end(); ++i) | |
| 523 messages.push_back(i->message()); | |
| 524 return messages; | |
| 525 } | |
| 526 | |
| 527 std::set<Extension::PermissionMessage> | |
| 528 Extension::GetSimplePermissionMessages() const { | |
| 529 std::set<PermissionMessage> messages; | |
| 530 std::set<std::string>::const_iterator i; | |
| 531 for (i = api_permissions().begin(); i != api_permissions().end(); ++i) { | |
| 532 PermissionMessage::MessageId message_id = GetPermissionMessageId(*i); | |
| 533 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 534 if (message_id > PermissionMessage::ID_NONE) | |
| 535 messages.insert(PermissionMessage::CreateFromMessageId(message_id)); | |
| 536 } | |
| 537 return messages; | |
| 538 } | |
| 539 | |
| 540 // static | |
| 541 std::vector<std::string> Extension::GetDistinctHostsForDisplay( | |
| 542 const URLPatternList& list) { | |
| 543 return GetDistinctHosts(list, true); | |
| 544 } | |
| 545 | |
| 546 // static | |
| 547 bool Extension::IsElevatedHostList( | |
| 548 const URLPatternList& old_list, const URLPatternList& new_list) { | |
| 549 // TODO(jstritar): This is overly conservative with respect to subdomains. | |
| 550 // For example, going from *.google.com to www.google.com will be | |
| 551 // considered an elevation, even though it is not (http://crbug.com/65337). | |
| 552 | |
| 553 std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false); | |
| 554 std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false); | |
| 555 | |
| 556 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end()); | |
| 557 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end()); | |
| 558 std::set<std::string> new_hosts_only; | |
| 559 | |
| 560 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), | |
| 561 old_hosts_set.begin(), old_hosts_set.end(), | |
| 562 std::inserter(new_hosts_only, new_hosts_only.begin())); | |
| 563 | |
| 564 return !new_hosts_only.empty(); | |
| 565 } | |
| 566 | |
| 567 // Helper for GetDistinctHosts(): com > net > org > everything else. | |
| 568 static bool RcdBetterThan(const std::string& a, const std::string& b) { | |
| 569 if (a == b) | |
| 570 return false; | |
| 571 if (a == "com") | |
| 572 return true; | |
| 573 if (a == "net") | |
| 574 return b != "com"; | |
| 575 if (a == "org") | |
| 576 return b != "com" && b != "net"; | |
| 577 return false; | |
| 578 } | |
| 579 | |
| 580 // static | |
| 581 std::vector<std::string> Extension::GetDistinctHosts( | |
| 582 const URLPatternList& host_patterns, | |
| 583 bool include_rcd) { | |
| 584 // Use a vector to preserve order (also faster than a map on small sets). | |
| 585 // Each item is a host split into two parts: host without RCDs and | |
| 586 // current best RCD. | |
| 587 typedef std::vector<std::pair<std::string, std::string> > HostVector; | |
| 588 HostVector hosts_best_rcd; | |
| 589 for (size_t i = 0; i < host_patterns.size(); ++i) { | |
| 590 std::string host = host_patterns[i].host(); | |
| 591 | |
| 592 // Add the subdomain wildcard back to the host, if necessary. | |
| 593 if (host_patterns[i].match_subdomains()) | |
| 594 host = "*." + host; | |
| 595 | |
| 596 // If the host has an RCD, split it off so we can detect duplicates. | |
| 597 std::string rcd; | |
| 598 size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength( | |
| 599 host, false); | |
| 600 if (reg_len && reg_len != std::string::npos) { | |
| 601 if (include_rcd) // else leave rcd empty | |
| 602 rcd = host.substr(host.size() - reg_len); | |
| 603 host = host.substr(0, host.size() - reg_len); | |
| 604 } | |
| 605 | |
| 606 // Check if we've already seen this host. | |
| 607 HostVector::iterator it = hosts_best_rcd.begin(); | |
| 608 for (; it != hosts_best_rcd.end(); ++it) { | |
| 609 if (it->first == host) | |
| 610 break; | |
| 611 } | |
| 612 // If this host was found, replace the RCD if this one is better. | |
| 613 if (it != hosts_best_rcd.end()) { | |
| 614 if (include_rcd && RcdBetterThan(rcd, it->second)) | |
| 615 it->second = rcd; | |
| 616 } else { // Previously unseen host, append it. | |
| 617 hosts_best_rcd.push_back(std::make_pair(host, rcd)); | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 // Build up the final vector by concatenating hosts and RCDs. | |
| 622 std::vector<std::string> distinct_hosts; | |
| 623 for (HostVector::iterator it = hosts_best_rcd.begin(); | |
| 624 it != hosts_best_rcd.end(); ++it) | |
| 625 distinct_hosts.push_back(it->first + it->second); | |
| 626 return distinct_hosts; | |
| 627 } | 273 } |
| 628 | 274 |
| 629 FilePath Extension::MaybeNormalizePath(const FilePath& path) { | 275 FilePath Extension::MaybeNormalizePath(const FilePath& path) { |
| 630 #if defined(OS_WIN) | 276 #if defined(OS_WIN) |
| 631 // Normalize any drive letter to upper-case. We do this for consistency with | 277 // Normalize any drive letter to upper-case. We do this for consistency with |
| 632 // net_utils::FilePathToFileURL(), which does the same thing, to make string | 278 // net_utils::FilePathToFileURL(), which does the same thing, to make string |
| 633 // comparisons simpler. | 279 // comparisons simpler. |
| 634 std::wstring path_str = path.value(); | 280 std::wstring path_str = path.value(); |
| 635 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' && | 281 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' && |
| 636 path_str[1] == ':') | 282 path_str[1] == ':') |
| 637 path_str[0] += ('A' - 'a'); | 283 path_str[0] += ('A' - 'a'); |
| 638 | 284 |
| 639 return FilePath(path_str); | 285 return FilePath(path_str); |
| 640 #else | 286 #else |
| 641 return path; | 287 return path; |
| 642 #endif | 288 #endif |
| 643 } | 289 } |
| 644 | 290 |
| 645 // static | |
| 646 bool Extension::IsHostedAppPermission(const std::string& str) { | |
| 647 for (size_t i = 0; i < Extension::kNumHostedAppPermissions; ++i) { | |
| 648 if (str == Extension::kHostedAppPermissionNames[i]) { | |
| 649 return true; | |
| 650 } | |
| 651 } | |
| 652 return false; | |
| 653 } | |
| 654 | |
| 655 const std::string Extension::VersionString() const { | 291 const std::string Extension::VersionString() const { |
| 656 return version()->GetString(); | 292 return version()->GetString(); |
| 657 } | 293 } |
| 658 | 294 |
| 659 // static | 295 // static |
| 660 bool Extension::IsExtension(const FilePath& file_name) { | 296 bool Extension::IsExtension(const FilePath& file_name) { |
| 661 return file_name.MatchesExtension(chrome::kExtensionFileExtension); | 297 return file_name.MatchesExtension(chrome::kExtensionFileExtension); |
| 662 } | 298 } |
| 663 | 299 |
| 664 // static | 300 // static |
| (...skipping 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1611 output->append(" "); | 1247 output->append(" "); |
| 1612 output->append(is_public ? kPublic : kPrivate); | 1248 output->append(is_public ? kPublic : kPrivate); |
| 1613 output->append(" "); | 1249 output->append(" "); |
| 1614 output->append(kKeyInfoEndMarker); | 1250 output->append(kKeyInfoEndMarker); |
| 1615 output->append("\n"); | 1251 output->append("\n"); |
| 1616 | 1252 |
| 1617 return true; | 1253 return true; |
| 1618 } | 1254 } |
| 1619 | 1255 |
| 1620 // static | 1256 // static |
| 1621 bool Extension::IsPrivilegeIncrease(const bool granted_full_access, | |
| 1622 const std::set<std::string>& granted_apis, | |
| 1623 const URLPatternSet& granted_extent, | |
| 1624 const Extension* new_extension) { | |
| 1625 // If the extension had native code access, we don't need to go any further. | |
| 1626 // Things can't get any worse. | |
| 1627 if (granted_full_access) | |
| 1628 return false; | |
| 1629 | |
| 1630 // Otherwise, if the new extension has a plugin, it's a privilege increase. | |
| 1631 if (new_extension->HasFullPermissions()) | |
| 1632 return true; | |
| 1633 | |
| 1634 // If the extension hadn't been granted access to all hosts in the past, then | |
| 1635 // see if the extension requires more host permissions. | |
| 1636 if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) { | |
| 1637 if (new_extension->HasEffectiveAccessToAllHosts()) | |
| 1638 return true; | |
| 1639 | |
| 1640 const URLPatternSet new_extent = | |
| 1641 new_extension->GetEffectiveHostPermissions(); | |
| 1642 | |
| 1643 if (IsElevatedHostList(granted_extent.patterns(), new_extent.patterns())) | |
| 1644 return true; | |
| 1645 } | |
| 1646 | |
| 1647 std::set<std::string> new_apis = new_extension->api_permissions(); | |
| 1648 std::set<std::string> new_apis_only; | |
| 1649 std::set_difference(new_apis.begin(), new_apis.end(), | |
| 1650 granted_apis.begin(), granted_apis.end(), | |
| 1651 std::inserter(new_apis_only, new_apis_only.begin())); | |
| 1652 | |
| 1653 // Ignore API permissions that don't require user approval when deciding if | |
| 1654 // an extension has increased its privileges. | |
| 1655 size_t new_api_count = 0; | |
| 1656 for (std::set<std::string>::iterator i = new_apis_only.begin(); | |
| 1657 i != new_apis_only.end(); ++i) { | |
| 1658 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 1659 if (GetPermissionMessageId(*i) > PermissionMessage::ID_NONE) | |
| 1660 new_api_count++; | |
| 1661 } | |
| 1662 | |
| 1663 if (new_api_count) | |
| 1664 return true; | |
| 1665 | |
| 1666 return false; | |
| 1667 } | |
| 1668 | |
| 1669 // static | |
| 1670 void Extension::DecodeIcon(const Extension* extension, | 1257 void Extension::DecodeIcon(const Extension* extension, |
| 1671 Icons icon_size, | 1258 Icons icon_size, |
| 1672 scoped_ptr<SkBitmap>* result) { | 1259 scoped_ptr<SkBitmap>* result) { |
| 1673 FilePath icon_path = extension->GetIconResource( | 1260 FilePath icon_path = extension->GetIconResource( |
| 1674 icon_size, ExtensionIconSet::MATCH_EXACTLY).GetFilePath(); | 1261 icon_size, ExtensionIconSet::MATCH_EXACTLY).GetFilePath(); |
| 1675 DecodeIconFromPath(icon_path, icon_size, result); | 1262 DecodeIconFromPath(icon_path, icon_size, result); |
| 1676 } | 1263 } |
| 1677 | 1264 |
| 1678 // static | 1265 // static |
| 1679 void Extension::DecodeIconFromPath(const FilePath& icon_path, | 1266 void Extension::DecodeIconFromPath(const FilePath& icon_path, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1726 chrome::kStandardSchemeSeparator + extension_id + "/"); | 1313 chrome::kStandardSchemeSeparator + extension_id + "/"); |
| 1727 } | 1314 } |
| 1728 | 1315 |
| 1729 bool Extension::InitFromValue(const DictionaryValue& source, int flags, | 1316 bool Extension::InitFromValue(const DictionaryValue& source, int flags, |
| 1730 std::string* error) { | 1317 std::string* error) { |
| 1731 // When strict error checks are enabled, make URL pattern parsing strict. | 1318 // When strict error checks are enabled, make URL pattern parsing strict. |
| 1732 URLPattern::ParseOption parse_strictness = | 1319 URLPattern::ParseOption parse_strictness = |
| 1733 (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT | 1320 (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT |
| 1734 : URLPattern::PARSE_LENIENT); | 1321 : URLPattern::PARSE_LENIENT); |
| 1735 | 1322 |
| 1323 // Initialize permissions with an empty, default permission set. |
| 1324 permission_set_.reset(new ExtensionPermissionSet()); |
| 1325 |
| 1736 if (source.HasKey(keys::kPublicKey)) { | 1326 if (source.HasKey(keys::kPublicKey)) { |
| 1737 std::string public_key_bytes; | 1327 std::string public_key_bytes; |
| 1738 if (!source.GetString(keys::kPublicKey, | 1328 if (!source.GetString(keys::kPublicKey, |
| 1739 &public_key_) || | 1329 &public_key_) || |
| 1740 !ParsePEMKeyBytes(public_key_, | 1330 !ParsePEMKeyBytes(public_key_, |
| 1741 &public_key_bytes) || | 1331 &public_key_bytes) || |
| 1742 !GenerateId(public_key_bytes, &id_)) { | 1332 !GenerateId(public_key_bytes, &id_)) { |
| 1743 *error = errors::kInvalidKey; | 1333 *error = errors::kInvalidKey; |
| 1744 return false; | 1334 return false; |
| 1745 } | 1335 } |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2244 return false; | 1834 return false; |
| 2245 } | 1835 } |
| 2246 options_url_ = GetResourceURL(options_str); | 1836 options_url_ = GetResourceURL(options_str); |
| 2247 if (!options_url_.is_valid()) { | 1837 if (!options_url_.is_valid()) { |
| 2248 *error = errors::kInvalidOptionsPage; | 1838 *error = errors::kInvalidOptionsPage; |
| 2249 return false; | 1839 return false; |
| 2250 } | 1840 } |
| 2251 } | 1841 } |
| 2252 } | 1842 } |
| 2253 | 1843 |
| 1844 ExtensionAPIPermissionSet api_permissions; |
| 1845 URLPatternSet host_permissions; |
| 1846 |
| 2254 // Initialize the permissions (optional). | 1847 // Initialize the permissions (optional). |
| 2255 if (source.HasKey(keys::kPermissions)) { | 1848 if (source.HasKey(keys::kPermissions)) { |
| 2256 ListValue* permissions = NULL; | 1849 ListValue* permissions = NULL; |
| 2257 if (!source.GetList(keys::kPermissions, &permissions)) { | 1850 if (!source.GetList(keys::kPermissions, &permissions)) { |
| 2258 *error = ExtensionErrorUtils::FormatErrorMessage( | 1851 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2259 errors::kInvalidPermissions, ""); | 1852 errors::kInvalidPermissions, ""); |
| 2260 return false; | 1853 return false; |
| 2261 } | 1854 } |
| 2262 | 1855 |
| 2263 for (size_t i = 0; i < permissions->GetSize(); ++i) { | 1856 for (size_t i = 0; i < permissions->GetSize(); ++i) { |
| 2264 std::string permission_str; | 1857 std::string permission_str; |
| 2265 if (!permissions->GetString(i, &permission_str)) { | 1858 if (!permissions->GetString(i, &permission_str)) { |
| 2266 *error = ExtensionErrorUtils::FormatErrorMessage( | 1859 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2267 errors::kInvalidPermission, base::IntToString(i)); | 1860 errors::kInvalidPermission, base::IntToString(i)); |
| 2268 return false; | 1861 return false; |
| 2269 } | 1862 } |
| 2270 | 1863 |
| 1864 ExtensionAPIPermission* permission = |
| 1865 ExtensionPermissionsInfo::GetByName(permission_str); |
| 1866 |
| 2271 // Only COMPONENT extensions can use private APIs. | 1867 // Only COMPONENT extensions can use private APIs. |
| 2272 // TODO(asargent) - We want a more general purpose mechanism for this, | 1868 // TODO(asargent) - We want a more general purpose mechanism for this, |
| 2273 // and better error messages. (http://crbug.com/54013) | 1869 // and better error messages. (http://crbug.com/54013) |
| 2274 if (!IsComponentOnlyPermission(permission_str) | 1870 if (!IsComponentOnlyPermission(permission) |
| 2275 #ifndef NDEBUG | 1871 #ifndef NDEBUG |
| 2276 && !CommandLine::ForCurrentProcess()->HasSwitch( | 1872 && !CommandLine::ForCurrentProcess()->HasSwitch( |
| 2277 switches::kExposePrivateExtensionApi) | 1873 switches::kExposePrivateExtensionApi) |
| 2278 #endif | 1874 #endif |
| 2279 ) { | 1875 ) { |
| 2280 continue; | 1876 continue; |
| 2281 } | 1877 } |
| 2282 | 1878 |
| 2283 // Remap the old unlimited storage permission name. | |
| 2284 if (permission_str == kOldUnlimitedStoragePermission) | |
| 2285 permission_str = kUnlimitedStoragePermission; | |
| 2286 | |
| 2287 if (web_extent().is_empty() || location() == Extension::COMPONENT) { | 1879 if (web_extent().is_empty() || location() == Extension::COMPONENT) { |
| 2288 // Check if it's a module permission. If so, enable that permission. | 1880 // Check if it's a module permission. If so, enable that permission. |
| 2289 if (IsAPIPermission(permission_str)) { | 1881 if (permission != NULL) { |
| 2290 // Only allow the experimental API permission if the command line | 1882 // Only allow the experimental API permission if the command line |
| 2291 // flag is present, or if the extension is a component of Chrome. | 1883 // flag is present, or if the extension is a component of Chrome. |
| 2292 if (IsDisallowedExperimentalPermission(permission_str) && | 1884 if (IsDisallowedExperimentalPermission(permission->id()) && |
| 2293 location() != Extension::COMPONENT) { | 1885 location() != Extension::COMPONENT) { |
| 2294 *error = errors::kExperimentalFlagRequired; | 1886 *error = errors::kExperimentalFlagRequired; |
| 2295 return false; | 1887 return false; |
| 2296 } | 1888 } |
| 2297 api_permissions_.insert(permission_str); | 1889 api_permissions.insert(permission->id()); |
| 2298 continue; | 1890 continue; |
| 2299 } | 1891 } |
| 2300 } else { | 1892 } else { |
| 2301 // Hosted apps only get access to a subset of the valid permissions. | 1893 // Hosted apps only get access to a subset of the valid permissions. |
| 2302 if (IsHostedAppPermission(permission_str)) { | 1894 if (permission != NULL && permission->is_hosted_app()) { |
| 2303 if (IsDisallowedExperimentalPermission(permission_str)) { | 1895 if (IsDisallowedExperimentalPermission(permission->id())) { |
| 2304 *error = errors::kExperimentalFlagRequired; | 1896 *error = errors::kExperimentalFlagRequired; |
| 2305 return false; | 1897 return false; |
| 2306 } | 1898 } |
| 2307 api_permissions_.insert(permission_str); | 1899 api_permissions.insert(permission->id()); |
| 2308 continue; | 1900 continue; |
| 2309 } | 1901 } |
| 2310 } | 1902 } |
| 2311 | 1903 |
| 2312 // Check if it's a host pattern permission. | 1904 // Check if it's a host pattern permission. |
| 2313 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? | 1905 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? |
| 2314 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes); | 1906 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes); |
| 2315 | 1907 |
| 2316 URLPattern::ParseResult parse_result = pattern.Parse(permission_str, | 1908 URLPattern::ParseResult parse_result = pattern.Parse(permission_str, |
| 2317 parse_strictness); | 1909 parse_strictness); |
| 2318 if (parse_result == URLPattern::PARSE_SUCCESS) { | 1910 if (parse_result == URLPattern::PARSE_SUCCESS) { |
| 2319 if (!CanSpecifyHostPermission(pattern)) { | 1911 if (!CanSpecifyHostPermission(pattern)) { |
| 2320 *error = ExtensionErrorUtils::FormatErrorMessage( | 1912 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2321 errors::kInvalidPermissionScheme, base::IntToString(i)); | 1913 errors::kInvalidPermissionScheme, base::IntToString(i)); |
| 2322 return false; | 1914 return false; |
| 2323 } | 1915 } |
| 2324 | 1916 |
| 2325 // The path component is not used for host permissions, so we force it | 1917 // The path component is not used for host permissions, so we force it |
| 2326 // to match all paths. | 1918 // to match all paths. |
| 2327 pattern.SetPath("/*"); | 1919 pattern.SetPath("/*"); |
| 2328 | 1920 |
| 2329 if (pattern.MatchesScheme(chrome::kFileScheme) && | 1921 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 2330 !CanExecuteScriptEverywhere()) { | 1922 !CanExecuteScriptEverywhere()) { |
| 2331 wants_file_access_ = true; | 1923 wants_file_access_ = true; |
| 2332 if (!(flags & ALLOW_FILE_ACCESS)) | 1924 if (!(flags & ALLOW_FILE_ACCESS)) |
| 2333 pattern.set_valid_schemes( | 1925 pattern.set_valid_schemes( |
| 2334 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 1926 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 2335 } | 1927 } |
| 2336 | 1928 |
| 2337 host_permissions_.push_back(pattern); | 1929 host_permissions.AddPattern(pattern); |
| 2338 } | 1930 } |
| 2339 | 1931 |
| 2340 // If it's not a host permission, then it's probably an unknown API | 1932 // If it's not a host permission, then it's probably an unknown API |
| 2341 // permission. Do not throw an error so extensions can retain | 1933 // permission. Do not throw an error so extensions can retain |
| 2342 // backwards compatability (http://crbug.com/42742). | 1934 // backwards compatability (http://crbug.com/42742). |
| 2343 // TODO(jstritar): We can improve error messages by adding better | 1935 // TODO(jstritar): We can improve error messages by adding better |
| 2344 // validation of API permissions here. | 1936 // validation of API permissions here. |
| 2345 // TODO(skerner): Consider showing the reason |permission_str| is not | 1937 // TODO(skerner): Consider showing the reason |permission_str| is not |
| 2346 // a valid URL pattern if it is almost valid. For example, if it has | 1938 // a valid URL pattern if it is almost valid. For example, if it has |
| 2347 // a valid scheme, and failed to parse because it has a port, show an | 1939 // a valid scheme, and failed to parse because it has a port, show an |
| 2348 // error. | 1940 // error. |
| 2349 } | 1941 } |
| 2350 } | 1942 } |
| 2351 | 1943 |
| 2352 // Initialize background url (optional). | 1944 // Initialize background url (optional). |
| 2353 if (source.HasKey(keys::kBackground)) { | 1945 if (source.HasKey(keys::kBackground)) { |
| 2354 std::string background_str; | 1946 std::string background_str; |
| 2355 if (!source.GetString(keys::kBackground, &background_str)) { | 1947 if (!source.GetString(keys::kBackground, &background_str)) { |
| 2356 *error = errors::kInvalidBackground; | 1948 *error = errors::kInvalidBackground; |
| 2357 return false; | 1949 return false; |
| 2358 } | 1950 } |
| 2359 | 1951 |
| 2360 if (is_hosted_app()) { | 1952 if (is_hosted_app()) { |
| 2361 // Make sure "background" permission is set. | 1953 // Make sure "background" permission is set. |
| 2362 if (api_permissions_.find(kBackgroundPermission) == | 1954 if (!api_permissions.count(ExtensionAPIPermission::kBackground)) { |
| 2363 api_permissions_.end()) { | |
| 2364 *error = errors::kBackgroundPermissionNeeded; | 1955 *error = errors::kBackgroundPermissionNeeded; |
| 2365 return false; | 1956 return false; |
| 2366 } | 1957 } |
| 2367 // Hosted apps require an absolute URL. | 1958 // Hosted apps require an absolute URL. |
| 2368 GURL bg_page(background_str); | 1959 GURL bg_page(background_str); |
| 2369 if (!bg_page.is_valid()) { | 1960 if (!bg_page.is_valid()) { |
| 2370 *error = errors::kInvalidBackgroundInHostedApp; | 1961 *error = errors::kInvalidBackgroundInHostedApp; |
| 2371 return false; | 1962 return false; |
| 2372 } | 1963 } |
| 2373 | 1964 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 content_security_policy_ = content_security_policy; | 2183 content_security_policy_ = content_security_policy; |
| 2593 } | 2184 } |
| 2594 | 2185 |
| 2595 // Initialize devtools page url (optional). | 2186 // Initialize devtools page url (optional). |
| 2596 if (source.HasKey(keys::kDevToolsPage)) { | 2187 if (source.HasKey(keys::kDevToolsPage)) { |
| 2597 std::string devtools_str; | 2188 std::string devtools_str; |
| 2598 if (!source.GetString(keys::kDevToolsPage, &devtools_str)) { | 2189 if (!source.GetString(keys::kDevToolsPage, &devtools_str)) { |
| 2599 *error = errors::kInvalidDevToolsPage; | 2190 *error = errors::kInvalidDevToolsPage; |
| 2600 return false; | 2191 return false; |
| 2601 } | 2192 } |
| 2602 if (!HasApiPermission(Extension::kExperimentalPermission)) { | 2193 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { |
| 2603 *error = errors::kDevToolsExperimental; | 2194 *error = errors::kDevToolsExperimental; |
| 2604 return false; | 2195 return false; |
| 2605 } | 2196 } |
| 2606 devtools_url_ = GetResourceURL(devtools_str); | 2197 devtools_url_ = GetResourceURL(devtools_str); |
| 2607 } | 2198 } |
| 2608 | 2199 |
| 2609 // Initialize sidebar action (optional). | 2200 // Initialize sidebar action (optional). |
| 2610 if (source.HasKey(keys::kSidebar)) { | 2201 if (source.HasKey(keys::kSidebar)) { |
| 2611 DictionaryValue* sidebar_value = NULL; | 2202 DictionaryValue* sidebar_value = NULL; |
| 2612 if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) { | 2203 if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) { |
| 2613 *error = errors::kInvalidSidebar; | 2204 *error = errors::kInvalidSidebar; |
| 2614 return false; | 2205 return false; |
| 2615 } | 2206 } |
| 2616 if (!HasApiPermission(Extension::kExperimentalPermission)) { | 2207 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { |
| 2617 *error = errors::kSidebarExperimental; | 2208 *error = errors::kSidebarExperimental; |
| 2618 return false; | 2209 return false; |
| 2619 } | 2210 } |
| 2620 sidebar_defaults_.reset(LoadExtensionSidebarDefaults(sidebar_value, error)); | 2211 sidebar_defaults_.reset(LoadExtensionSidebarDefaults(sidebar_value, error)); |
| 2621 if (!sidebar_defaults_.get()) | 2212 if (!sidebar_defaults_.get()) |
| 2622 return false; // Failed to parse sidebar definition. | 2213 return false; // Failed to parse sidebar definition. |
| 2623 } | 2214 } |
| 2624 | 2215 |
| 2625 // Initialize text-to-speech voices (optional). | 2216 // Initialize text-to-speech voices (optional). |
| 2626 if (source.HasKey(keys::kTts)) { | 2217 if (source.HasKey(keys::kTts)) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2692 *error = errors::kInvalidIncognitoBehavior; | 2283 *error = errors::kInvalidIncognitoBehavior; |
| 2693 return false; | 2284 return false; |
| 2694 } | 2285 } |
| 2695 } | 2286 } |
| 2696 | 2287 |
| 2697 if (HasMultipleUISurfaces()) { | 2288 if (HasMultipleUISurfaces()) { |
| 2698 *error = errors::kOneUISurfaceOnly; | 2289 *error = errors::kOneUISurfaceOnly; |
| 2699 return false; | 2290 return false; |
| 2700 } | 2291 } |
| 2701 | 2292 |
| 2702 InitEffectiveHostPermissions(); | 2293 permission_set_.reset( |
| 2294 new ExtensionPermissionSet(this, api_permissions, host_permissions)); |
| 2703 | 2295 |
| 2704 // Although |source| is passed in as a const, it's still possible to modify | 2296 // Although |source| is passed in as a const, it's still possible to modify |
| 2705 // it. This is dangerous since the utility process re-uses |source| after | 2297 // it. This is dangerous since the utility process re-uses |source| after |
| 2706 // it calls InitFromValue, passing it up to the browser process which calls | 2298 // it calls InitFromValue, passing it up to the browser process which calls |
| 2707 // InitFromValue again. As a result, we need to make sure that nobody | 2299 // InitFromValue again. As a result, we need to make sure that nobody |
| 2708 // accidentally modifies it. | 2300 // accidentally modifies it. |
| 2709 DCHECK(source.Equals(manifest_value_.get())); | 2301 DCHECK(source.Equals(manifest_value_.get())); |
| 2710 | 2302 |
| 2711 return true; | 2303 return true; |
| 2712 } | 2304 } |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2883 // Only allow access to chrome://favicon to regular extensions. Component | 2475 // Only allow access to chrome://favicon to regular extensions. Component |
| 2884 // extensions can have access to all of chrome://*. | 2476 // extensions can have access to all of chrome://*. |
| 2885 return (pattern.host() == chrome::kChromeUIFaviconHost || | 2477 return (pattern.host() == chrome::kChromeUIFaviconHost || |
| 2886 CanExecuteScriptEverywhere()); | 2478 CanExecuteScriptEverywhere()); |
| 2887 } | 2479 } |
| 2888 | 2480 |
| 2889 // Otherwise, the valid schemes were handled by URLPattern. | 2481 // Otherwise, the valid schemes were handled by URLPattern. |
| 2890 return true; | 2482 return true; |
| 2891 } | 2483 } |
| 2892 | 2484 |
| 2893 // static | |
| 2894 bool Extension::HasApiPermission( | 2485 bool Extension::HasApiPermission( |
| 2895 const std::set<std::string>& api_permissions, | 2486 ExtensionAPIPermission::Id permission) const { |
| 2896 const std::string& function_name) { | 2487 return permission_set()->HasAPIPermission(permission); |
| 2897 std::string permission_name = function_name; | 2488 } |
| 2898 | 2489 |
| 2899 for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) { | 2490 bool Extension::HasApiPermission( |
| 2900 if (permission_name == kNonPermissionFunctionNames[i]) | 2491 const std::string& function_name) const { |
| 2901 return true; | 2492 return permission_set()->HasAccessToFunction(function_name); |
| 2902 } | 2493 } |
| 2903 | 2494 |
| 2904 // See if this is a function or event name first and strip out the package. | 2495 const URLPatternSet& Extension::GetEffectiveHostPermissions() const { |
| 2905 // Functions will be of the form package.function | 2496 return permission_set()->effective_hosts(); |
| 2906 // Events will be of the form package/id or package.optional.stuff | |
| 2907 size_t separator = function_name.find_first_of("./"); | |
| 2908 if (separator != std::string::npos) | |
| 2909 permission_name = function_name.substr(0, separator); | |
| 2910 | |
| 2911 // windows and tabs are the same permission. | |
| 2912 if (permission_name == kWindowPermission) | |
| 2913 permission_name = Extension::kTabPermission; | |
| 2914 | |
| 2915 if (api_permissions.count(permission_name)) | |
| 2916 return true; | |
| 2917 | |
| 2918 for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) { | |
| 2919 if (permission_name == kNonPermissionModuleNames[i]) { | |
| 2920 return true; | |
| 2921 } | |
| 2922 } | |
| 2923 | |
| 2924 return false; | |
| 2925 } | 2497 } |
| 2926 | 2498 |
| 2927 bool Extension::HasHostPermission(const GURL& url) const { | 2499 bool Extension::HasHostPermission(const GURL& url) const { |
| 2928 for (URLPatternList::const_iterator host = host_permissions().begin(); | 2500 if (url.SchemeIs(chrome::kChromeUIScheme) && |
| 2929 host != host_permissions().end(); ++host) { | 2501 url.host() != chrome::kChromeUIFaviconHost && |
| 2930 // Non-component extensions can only access chrome://favicon and no other | 2502 location() != Extension::COMPONENT) |
| 2931 // chrome:// scheme urls. | 2503 return false; |
| 2932 if (url.SchemeIs(chrome::kChromeUIScheme) && | 2504 return permission_set()->HasExplicitAccessToOrigin(url); |
| 2933 url.host() != chrome::kChromeUIFaviconHost && | |
| 2934 location() != Extension::COMPONENT) | |
| 2935 return false; | |
| 2936 | |
| 2937 if (host->MatchesURL(url)) | |
| 2938 return true; | |
| 2939 } | |
| 2940 return false; | |
| 2941 } | 2505 } |
| 2942 | 2506 |
| 2943 void Extension::InitEffectiveHostPermissions() { | 2507 bool Extension::IsComponentOnlyPermission( |
| 2944 // Some APIs effectively grant access to every site. New ones should be | 2508 const ExtensionAPIPermission* api) const { |
| 2945 // added here. (I'm looking at you, network API) | |
| 2946 if (HasApiPermission(api_permissions_, kProxyPermission) || | |
| 2947 !devtools_url_.is_empty()) { | |
| 2948 URLPattern all_urls(URLPattern::SCHEME_ALL); | |
| 2949 all_urls.set_match_all_urls(true); | |
| 2950 effective_host_permissions_.AddPattern(all_urls); | |
| 2951 return; | |
| 2952 } | |
| 2953 | |
| 2954 for (URLPatternList::const_iterator host = host_permissions().begin(); | |
| 2955 host != host_permissions().end(); ++host) | |
| 2956 effective_host_permissions_.AddPattern(*host); | |
| 2957 | |
| 2958 for (UserScriptList::const_iterator content_script = | |
| 2959 content_scripts().begin(); | |
| 2960 content_script != content_scripts().end(); ++content_script) { | |
| 2961 URLPatternList::const_iterator pattern = | |
| 2962 content_script->url_patterns().begin(); | |
| 2963 for (; pattern != content_script->url_patterns().end(); ++pattern) | |
| 2964 effective_host_permissions_.AddPattern(*pattern); | |
| 2965 } | |
| 2966 } | |
| 2967 | |
| 2968 bool Extension::IsComponentOnlyPermission(const std::string& permission) const { | |
| 2969 if (location() == Extension::COMPONENT) | 2509 if (location() == Extension::COMPONENT) |
| 2970 return true; | 2510 return true; |
| 2971 | 2511 |
| 2972 // Non-component extensions are not allowed to access private apis. | 2512 if (api == NULL) |
| 2973 for (size_t i = 0; i < Extension::kNumComponentPrivatePermissions; ++i) { | 2513 return true; |
| 2974 if (permission == Extension::kComponentPrivatePermissionNames[i]) | 2514 |
| 2975 return false; | 2515 return !api->is_component_only(); |
| 2976 } | |
| 2977 return true; | |
| 2978 } | 2516 } |
| 2979 | 2517 |
| 2980 bool Extension::HasMultipleUISurfaces() const { | 2518 bool Extension::HasMultipleUISurfaces() const { |
| 2981 int num_surfaces = 0; | 2519 int num_surfaces = 0; |
| 2982 | 2520 |
| 2983 if (page_action()) | 2521 if (page_action()) |
| 2984 ++num_surfaces; | 2522 ++num_surfaces; |
| 2985 | 2523 |
| 2986 if (browser_action()) | 2524 if (browser_action()) |
| 2987 ++num_surfaces; | 2525 ++num_surfaces; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3012 if (page_url.SchemeIs(chrome::kChromeUIScheme) && | 2550 if (page_url.SchemeIs(chrome::kChromeUIScheme) && |
| 3013 !CanExecuteScriptEverywhere()) | 2551 !CanExecuteScriptEverywhere()) |
| 3014 return false; | 2552 return false; |
| 3015 | 2553 |
| 3016 // If a script is specified, use its matches. | 2554 // If a script is specified, use its matches. |
| 3017 if (script) | 2555 if (script) |
| 3018 return script->MatchesURL(page_url); | 2556 return script->MatchesURL(page_url); |
| 3019 | 2557 |
| 3020 // Otherwise, see if this extension has permission to execute script | 2558 // Otherwise, see if this extension has permission to execute script |
| 3021 // programmatically on pages. | 2559 // programmatically on pages. |
| 3022 for (size_t i = 0; i < host_permissions_.size(); ++i) { | 2560 if (HasHostPermission(page_url)) |
| 3023 if (host_permissions_[i].MatchesURL(page_url)) | 2561 return true; |
| 3024 return true; | |
| 3025 } | |
| 3026 | 2562 |
| 3027 if (error) { | 2563 if (error) { |
| 3028 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, | 2564 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, |
| 3029 page_url.spec()); | 2565 page_url.spec()); |
| 3030 } | 2566 } |
| 3031 | 2567 |
| 3032 return false; | 2568 return false; |
| 3033 } | 2569 } |
| 3034 | 2570 |
| 3035 // static | |
| 3036 bool Extension::HasEffectiveAccessToAllHosts( | |
| 3037 const URLPatternSet& effective_host_permissions, | |
| 3038 const std::set<std::string>& api_permissions) { | |
| 3039 const URLPatternList patterns = effective_host_permissions.patterns(); | |
| 3040 for (URLPatternList::const_iterator host = patterns.begin(); | |
| 3041 host != patterns.end(); ++host) { | |
| 3042 if (host->match_all_urls() || | |
| 3043 (host->match_subdomains() && host->host().empty())) | |
| 3044 return true; | |
| 3045 } | |
| 3046 | |
| 3047 return false; | |
| 3048 } | |
| 3049 | |
| 3050 bool Extension::HasEffectiveAccessToAllHosts() const { | 2571 bool Extension::HasEffectiveAccessToAllHosts() const { |
| 3051 return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(), | 2572 return permission_set_->HasEffectiveAccessToAllHosts(); |
| 3052 api_permissions()); | |
| 3053 } | 2573 } |
| 3054 | 2574 |
| 3055 bool Extension::HasFullPermissions() const { | 2575 bool Extension::HasFullPermissions() const { |
| 3056 return !plugins().empty(); | 2576 return permission_set_->HasEffectiveFullAccess(); |
| 3057 } | 2577 } |
| 3058 | 2578 |
| 3059 bool Extension::ShowConfigureContextMenus() const { | 2579 bool Extension::ShowConfigureContextMenus() const { |
| 3060 // Don't show context menu for component extensions. We might want to show | 2580 // Don't show context menu for component extensions. We might want to show |
| 3061 // options for component extension button but now there is no component | 2581 // options for component extension button but now there is no component |
| 3062 // extension with options. All other menu items like uninstall have | 2582 // extension with options. All other menu items like uninstall have |
| 3063 // no sense for component extensions. | 2583 // no sense for component extensions. |
| 3064 return location() != Extension::COMPONENT; | 2584 return location() != Extension::COMPONENT; |
| 3065 } | 2585 } |
| 3066 | 2586 |
| 3067 bool Extension::IsDisallowedExperimentalPermission( | 2587 bool Extension::IsDisallowedExperimentalPermission( |
| 3068 const std::string& permission_str) const { | 2588 ExtensionAPIPermission::Id permission) const { |
| 3069 return permission_str == Extension::kExperimentalPermission && | 2589 return permission == ExtensionAPIPermission::kExperimental && |
| 3070 !CommandLine::ForCurrentProcess()->HasSwitch( | 2590 !CommandLine::ForCurrentProcess()->HasSwitch( |
| 3071 switches::kEnableExperimentalExtensionApis); | 2591 switches::kEnableExperimentalExtensionApis); |
| 3072 } | 2592 } |
| 3073 | 2593 |
| 3074 bool Extension::IsAPIPermission(const std::string& str) const { | |
| 3075 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { | |
| 3076 if (str == Extension::kPermissions[i].name) { | |
| 3077 return true; | |
| 3078 } | |
| 3079 } | |
| 3080 return false; | |
| 3081 } | |
| 3082 | |
| 3083 bool Extension::CanExecuteScriptEverywhere() const { | 2594 bool Extension::CanExecuteScriptEverywhere() const { |
| 3084 if (location() == Extension::COMPONENT | 2595 if (location() == Extension::COMPONENT |
| 3085 #ifndef NDEBUG | 2596 #ifndef NDEBUG |
| 3086 || CommandLine::ForCurrentProcess()->HasSwitch( | 2597 || CommandLine::ForCurrentProcess()->HasSwitch( |
| 3087 switches::kExposePrivateExtensionApi) | 2598 switches::kExposePrivateExtensionApi) |
| 3088 #endif | 2599 #endif |
| 3089 ) | 2600 ) |
| 3090 return true; | 2601 return true; |
| 3091 | 2602 |
| 3092 ScriptingWhitelist* whitelist = | 2603 ScriptingWhitelist* whitelist = |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3148 extension_location(location) { | 2659 extension_location(location) { |
| 3149 if (manifest) | 2660 if (manifest) |
| 3150 extension_manifest.reset(manifest->DeepCopy()); | 2661 extension_manifest.reset(manifest->DeepCopy()); |
| 3151 } | 2662 } |
| 3152 | 2663 |
| 3153 ExtensionInfo::~ExtensionInfo() {} | 2664 ExtensionInfo::~ExtensionInfo() {} |
| 3154 | 2665 |
| 3155 UninstalledExtensionInfo::UninstalledExtensionInfo( | 2666 UninstalledExtensionInfo::UninstalledExtensionInfo( |
| 3156 const Extension& extension) | 2667 const Extension& extension) |
| 3157 : extension_id(extension.id()), | 2668 : extension_id(extension.id()), |
| 3158 extension_api_permissions(extension.api_permissions()), | 2669 extension_api_permissions( |
| 2670 extension.permission_set()->GetAPIsAsStrings()), |
| 3159 extension_type(extension.GetType()), | 2671 extension_type(extension.GetType()), |
| 3160 update_url(extension.update_url()) {} | 2672 update_url(extension.update_url()) {} |
| 3161 | 2673 |
| 3162 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} | 2674 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} |
| 3163 | 2675 |
| 3164 | 2676 |
| 3165 UnloadedExtensionInfo::UnloadedExtensionInfo( | 2677 UnloadedExtensionInfo::UnloadedExtensionInfo( |
| 3166 const Extension* extension, | 2678 const Extension* extension, |
| 3167 Reason reason) | 2679 Reason reason) |
| 3168 : reason(reason), | 2680 : reason(reason), |
| 3169 already_disabled(false), | 2681 already_disabled(false), |
| 3170 extension(extension) {} | 2682 extension(extension) {} |
| OLD | NEW |