| 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 : type(INPUT_COMPONENT_TYPE_NONE), | 215 : type(INPUT_COMPONENT_TYPE_NONE), |
| 359 shortcut_alt(false), | 216 shortcut_alt(false), |
| 360 shortcut_ctrl(false), | 217 shortcut_ctrl(false), |
| 361 shortcut_shift(false) { | 218 shortcut_shift(false) { |
| 362 } | 219 } |
| 363 | 220 |
| 364 Extension::InputComponentInfo::~InputComponentInfo() {} | 221 Extension::InputComponentInfo::~InputComponentInfo() {} |
| 365 | 222 |
| 366 // | 223 // |
| 367 // PermissionMessage | |
| 368 // | |
| 369 | |
| 370 // static | |
| 371 Extension::PermissionMessage Extension::PermissionMessage::CreateFromMessageId( | |
| 372 Extension::PermissionMessage::MessageId message_id) { | |
| 373 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 374 if (message_id <= ID_NONE) | |
| 375 return PermissionMessage(message_id, string16()); | |
| 376 | |
| 377 string16 message = l10n_util::GetStringUTF16(kMessageIds[message_id]); | |
| 378 return PermissionMessage(message_id, message); | |
| 379 } | |
| 380 | |
| 381 // static | |
| 382 Extension::PermissionMessage Extension::PermissionMessage::CreateFromHostList( | |
| 383 const std::vector<std::string> hosts) { | |
| 384 CHECK(hosts.size() > 0); | |
| 385 | |
| 386 MessageId message_id; | |
| 387 string16 message; | |
| 388 switch (hosts.size()) { | |
| 389 case 1: | |
| 390 message_id = ID_HOSTS_1; | |
| 391 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 392 UTF8ToUTF16(hosts[0])); | |
| 393 break; | |
| 394 case 2: | |
| 395 message_id = ID_HOSTS_2; | |
| 396 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 397 UTF8ToUTF16(hosts[0]), | |
| 398 UTF8ToUTF16(hosts[1])); | |
| 399 break; | |
| 400 case 3: | |
| 401 message_id = ID_HOSTS_3; | |
| 402 message = l10n_util::GetStringFUTF16(kMessageIds[message_id], | |
| 403 UTF8ToUTF16(hosts[0]), | |
| 404 UTF8ToUTF16(hosts[1]), | |
| 405 UTF8ToUTF16(hosts[2])); | |
| 406 break; | |
| 407 default: | |
| 408 message_id = ID_HOSTS_4_OR_MORE; | |
| 409 message = l10n_util::GetStringFUTF16( | |
| 410 kMessageIds[message_id], | |
| 411 UTF8ToUTF16(hosts[0]), | |
| 412 UTF8ToUTF16(hosts[1]), | |
| 413 base::IntToString16(hosts.size() - 2)); | |
| 414 break; | |
| 415 } | |
| 416 | |
| 417 return PermissionMessage(message_id, message); | |
| 418 } | |
| 419 | |
| 420 Extension::PermissionMessage::PermissionMessage( | |
| 421 Extension::PermissionMessage::MessageId message_id, string16 message) | |
| 422 : message_id_(message_id), | |
| 423 message_(message) { | |
| 424 } | |
| 425 | |
| 426 const int Extension::PermissionMessage::kMessageIds[] = { | |
| 427 kUndefinedMessageId, // "unknown" | |
| 428 kUndefinedMessageId, // "none" | |
| 429 IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS, | |
| 430 IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION, | |
| 431 IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY, | |
| 432 IDS_EXTENSION_PROMPT_WARNING_TABS, | |
| 433 IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT, | |
| 434 IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, | |
| 435 IDS_EXTENSION_PROMPT_WARNING_1_HOST, | |
| 436 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, | |
| 437 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, | |
| 438 IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS, | |
| 439 IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS, | |
| 440 IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, | |
| 441 IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD | |
| 442 }; | |
| 443 | |
| 444 // | |
| 445 // Extension | 224 // Extension |
| 446 // | 225 // |
| 447 | 226 |
| 448 // static | 227 // static |
| 449 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 228 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
| 450 Location location, | 229 Location location, |
| 451 const DictionaryValue& value, | 230 const DictionaryValue& value, |
| 452 int flags, | 231 int flags, |
| 453 std::string* error) { | 232 std::string* error) { |
| 454 scoped_refptr<Extension> extension = new Extension(path, location); | 233 scoped_refptr<Extension> extension = new Extension(path, location); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 484 int loc2_rank = GetLocationRank(loc2); | 263 int loc2_rank = GetLocationRank(loc2); |
| 485 | 264 |
| 486 // If two different locations have the same rank, then we can not | 265 // If two different locations have the same rank, then we can not |
| 487 // deterministicly choose a location. | 266 // deterministicly choose a location. |
| 488 CHECK(loc1_rank != loc2_rank); | 267 CHECK(loc1_rank != loc2_rank); |
| 489 | 268 |
| 490 // Lowest rank has highest priority. | 269 // Lowest rank has highest priority. |
| 491 return (loc1_rank > loc2_rank ? loc1 : loc2 ); | 270 return (loc1_rank > loc2_rank ? loc1 : loc2 ); |
| 492 } | 271 } |
| 493 | 272 |
| 494 // static | 273 ExtensionPermissionMessages Extension::GetPermissionMessages() const { |
| 495 Extension::PermissionMessage::MessageId Extension::GetPermissionMessageId( | 274 return permission_set_->GetPermissionMessages(); |
| 496 const std::string& permission) { | |
| 497 return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission); | |
| 498 } | |
| 499 | |
| 500 Extension::PermissionMessages Extension::GetPermissionMessages() const { | |
| 501 PermissionMessages messages; | |
| 502 if (!plugins().empty()) { | |
| 503 messages.push_back(PermissionMessage::CreateFromMessageId( | |
| 504 PermissionMessage::ID_FULL_ACCESS)); | |
| 505 return messages; | |
| 506 } | |
| 507 | |
| 508 if (HasEffectiveAccessToAllHosts()) { | |
| 509 messages.push_back(PermissionMessage::CreateFromMessageId( | |
| 510 PermissionMessage::ID_HOSTS_ALL)); | |
| 511 } else { | |
| 512 std::vector<std::string> hosts = GetDistinctHostsForDisplay( | |
| 513 GetEffectiveHostPermissions().patterns()); | |
| 514 if (!hosts.empty()) | |
| 515 messages.push_back(PermissionMessage::CreateFromHostList(hosts)); | |
| 516 } | |
| 517 | |
| 518 std::set<PermissionMessage> simple_msgs = GetSimplePermissionMessages(); | |
| 519 messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end()); | |
| 520 | |
| 521 return messages; | |
| 522 } | 275 } |
| 523 | 276 |
| 524 std::vector<string16> Extension::GetPermissionMessageStrings() const { | 277 std::vector<string16> Extension::GetPermissionMessageStrings() const { |
| 525 std::vector<string16> messages; | 278 return permission_set_->GetWarningMessages(); |
| 526 PermissionMessages permissions = GetPermissionMessages(); | |
| 527 for (PermissionMessages::const_iterator i = permissions.begin(); | |
| 528 i != permissions.end(); ++i) | |
| 529 messages.push_back(i->message()); | |
| 530 return messages; | |
| 531 } | |
| 532 | |
| 533 std::set<Extension::PermissionMessage> | |
| 534 Extension::GetSimplePermissionMessages() const { | |
| 535 std::set<PermissionMessage> messages; | |
| 536 std::set<std::string>::const_iterator i; | |
| 537 for (i = api_permissions().begin(); i != api_permissions().end(); ++i) { | |
| 538 PermissionMessage::MessageId message_id = GetPermissionMessageId(*i); | |
| 539 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 540 if (message_id > PermissionMessage::ID_NONE) | |
| 541 messages.insert(PermissionMessage::CreateFromMessageId(message_id)); | |
| 542 } | |
| 543 return messages; | |
| 544 } | |
| 545 | |
| 546 // static | |
| 547 std::vector<std::string> Extension::GetDistinctHostsForDisplay( | |
| 548 const URLPatternList& list) { | |
| 549 return GetDistinctHosts(list, true); | |
| 550 } | |
| 551 | |
| 552 // static | |
| 553 bool Extension::IsElevatedHostList( | |
| 554 const URLPatternList& old_list, const URLPatternList& new_list) { | |
| 555 // TODO(jstritar): This is overly conservative with respect to subdomains. | |
| 556 // For example, going from *.google.com to www.google.com will be | |
| 557 // considered an elevation, even though it is not (http://crbug.com/65337). | |
| 558 | |
| 559 std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false); | |
| 560 std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false); | |
| 561 | |
| 562 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end()); | |
| 563 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end()); | |
| 564 std::set<std::string> new_hosts_only; | |
| 565 | |
| 566 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), | |
| 567 old_hosts_set.begin(), old_hosts_set.end(), | |
| 568 std::inserter(new_hosts_only, new_hosts_only.begin())); | |
| 569 | |
| 570 return !new_hosts_only.empty(); | |
| 571 } | |
| 572 | |
| 573 // Helper for GetDistinctHosts(): com > net > org > everything else. | |
| 574 static bool RcdBetterThan(const std::string& a, const std::string& b) { | |
| 575 if (a == b) | |
| 576 return false; | |
| 577 if (a == "com") | |
| 578 return true; | |
| 579 if (a == "net") | |
| 580 return b != "com"; | |
| 581 if (a == "org") | |
| 582 return b != "com" && b != "net"; | |
| 583 return false; | |
| 584 } | |
| 585 | |
| 586 // static | |
| 587 std::vector<std::string> Extension::GetDistinctHosts( | |
| 588 const URLPatternList& host_patterns, | |
| 589 bool include_rcd) { | |
| 590 // Use a vector to preserve order (also faster than a map on small sets). | |
| 591 // Each item is a host split into two parts: host without RCDs and | |
| 592 // current best RCD. | |
| 593 typedef std::vector<std::pair<std::string, std::string> > HostVector; | |
| 594 HostVector hosts_best_rcd; | |
| 595 for (size_t i = 0; i < host_patterns.size(); ++i) { | |
| 596 std::string host = host_patterns[i].host(); | |
| 597 | |
| 598 // Add the subdomain wildcard back to the host, if necessary. | |
| 599 if (host_patterns[i].match_subdomains()) | |
| 600 host = "*." + host; | |
| 601 | |
| 602 // If the host has an RCD, split it off so we can detect duplicates. | |
| 603 std::string rcd; | |
| 604 size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength( | |
| 605 host, false); | |
| 606 if (reg_len && reg_len != std::string::npos) { | |
| 607 if (include_rcd) // else leave rcd empty | |
| 608 rcd = host.substr(host.size() - reg_len); | |
| 609 host = host.substr(0, host.size() - reg_len); | |
| 610 } | |
| 611 | |
| 612 // Check if we've already seen this host. | |
| 613 HostVector::iterator it = hosts_best_rcd.begin(); | |
| 614 for (; it != hosts_best_rcd.end(); ++it) { | |
| 615 if (it->first == host) | |
| 616 break; | |
| 617 } | |
| 618 // If this host was found, replace the RCD if this one is better. | |
| 619 if (it != hosts_best_rcd.end()) { | |
| 620 if (include_rcd && RcdBetterThan(rcd, it->second)) | |
| 621 it->second = rcd; | |
| 622 } else { // Previously unseen host, append it. | |
| 623 hosts_best_rcd.push_back(std::make_pair(host, rcd)); | |
| 624 } | |
| 625 } | |
| 626 | |
| 627 // Build up the final vector by concatenating hosts and RCDs. | |
| 628 std::vector<std::string> distinct_hosts; | |
| 629 for (HostVector::iterator it = hosts_best_rcd.begin(); | |
| 630 it != hosts_best_rcd.end(); ++it) | |
| 631 distinct_hosts.push_back(it->first + it->second); | |
| 632 return distinct_hosts; | |
| 633 } | 279 } |
| 634 | 280 |
| 635 FilePath Extension::MaybeNormalizePath(const FilePath& path) { | 281 FilePath Extension::MaybeNormalizePath(const FilePath& path) { |
| 636 #if defined(OS_WIN) | 282 #if defined(OS_WIN) |
| 637 // Normalize any drive letter to upper-case. We do this for consistency with | 283 // Normalize any drive letter to upper-case. We do this for consistency with |
| 638 // net_utils::FilePathToFileURL(), which does the same thing, to make string | 284 // net_utils::FilePathToFileURL(), which does the same thing, to make string |
| 639 // comparisons simpler. | 285 // comparisons simpler. |
| 640 std::wstring path_str = path.value(); | 286 std::wstring path_str = path.value(); |
| 641 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' && | 287 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' && |
| 642 path_str[1] == ':') | 288 path_str[1] == ':') |
| 643 path_str[0] += ('A' - 'a'); | 289 path_str[0] += ('A' - 'a'); |
| 644 | 290 |
| 645 return FilePath(path_str); | 291 return FilePath(path_str); |
| 646 #else | 292 #else |
| 647 return path; | 293 return path; |
| 648 #endif | 294 #endif |
| 649 } | 295 } |
| 650 | 296 |
| 651 // static | |
| 652 bool Extension::IsHostedAppPermission(const std::string& str) { | |
| 653 for (size_t i = 0; i < Extension::kNumHostedAppPermissions; ++i) { | |
| 654 if (str == Extension::kHostedAppPermissionNames[i]) { | |
| 655 return true; | |
| 656 } | |
| 657 } | |
| 658 return false; | |
| 659 } | |
| 660 | |
| 661 const std::string Extension::VersionString() const { | 297 const std::string Extension::VersionString() const { |
| 662 return version()->GetString(); | 298 return version()->GetString(); |
| 663 } | 299 } |
| 664 | 300 |
| 665 // static | 301 // static |
| 666 bool Extension::IsExtension(const FilePath& file_name) { | 302 bool Extension::IsExtension(const FilePath& file_name) { |
| 667 return file_name.MatchesExtension(chrome::kExtensionFileExtension); | 303 return file_name.MatchesExtension(chrome::kExtensionFileExtension); |
| 668 } | 304 } |
| 669 | 305 |
| 670 // static | 306 // static |
| (...skipping 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 output->append(" "); | 1253 output->append(" "); |
| 1618 output->append(is_public ? kPublic : kPrivate); | 1254 output->append(is_public ? kPublic : kPrivate); |
| 1619 output->append(" "); | 1255 output->append(" "); |
| 1620 output->append(kKeyInfoEndMarker); | 1256 output->append(kKeyInfoEndMarker); |
| 1621 output->append("\n"); | 1257 output->append("\n"); |
| 1622 | 1258 |
| 1623 return true; | 1259 return true; |
| 1624 } | 1260 } |
| 1625 | 1261 |
| 1626 // static | 1262 // static |
| 1627 bool Extension::IsPrivilegeIncrease(const bool granted_full_access, | |
| 1628 const std::set<std::string>& granted_apis, | |
| 1629 const URLPatternSet& granted_extent, | |
| 1630 const Extension* new_extension) { | |
| 1631 // If the extension had native code access, we don't need to go any further. | |
| 1632 // Things can't get any worse. | |
| 1633 if (granted_full_access) | |
| 1634 return false; | |
| 1635 | |
| 1636 // Otherwise, if the new extension has a plugin, it's a privilege increase. | |
| 1637 if (new_extension->HasFullPermissions()) | |
| 1638 return true; | |
| 1639 | |
| 1640 // If the extension hadn't been granted access to all hosts in the past, then | |
| 1641 // see if the extension requires more host permissions. | |
| 1642 if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) { | |
| 1643 if (new_extension->HasEffectiveAccessToAllHosts()) | |
| 1644 return true; | |
| 1645 | |
| 1646 const URLPatternSet new_extent = | |
| 1647 new_extension->GetEffectiveHostPermissions(); | |
| 1648 | |
| 1649 if (IsElevatedHostList(granted_extent.patterns(), new_extent.patterns())) | |
| 1650 return true; | |
| 1651 } | |
| 1652 | |
| 1653 std::set<std::string> new_apis = new_extension->api_permissions(); | |
| 1654 std::set<std::string> new_apis_only; | |
| 1655 std::set_difference(new_apis.begin(), new_apis.end(), | |
| 1656 granted_apis.begin(), granted_apis.end(), | |
| 1657 std::inserter(new_apis_only, new_apis_only.begin())); | |
| 1658 | |
| 1659 // Ignore API permissions that don't require user approval when deciding if | |
| 1660 // an extension has increased its privileges. | |
| 1661 size_t new_api_count = 0; | |
| 1662 for (std::set<std::string>::iterator i = new_apis_only.begin(); | |
| 1663 i != new_apis_only.end(); ++i) { | |
| 1664 DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN); | |
| 1665 if (GetPermissionMessageId(*i) > PermissionMessage::ID_NONE) | |
| 1666 new_api_count++; | |
| 1667 } | |
| 1668 | |
| 1669 if (new_api_count) | |
| 1670 return true; | |
| 1671 | |
| 1672 return false; | |
| 1673 } | |
| 1674 | |
| 1675 // static | |
| 1676 void Extension::DecodeIcon(const Extension* extension, | 1263 void Extension::DecodeIcon(const Extension* extension, |
| 1677 Icons icon_size, | 1264 Icons icon_size, |
| 1678 scoped_ptr<SkBitmap>* result) { | 1265 scoped_ptr<SkBitmap>* result) { |
| 1679 FilePath icon_path = extension->GetIconResource( | 1266 FilePath icon_path = extension->GetIconResource( |
| 1680 icon_size, ExtensionIconSet::MATCH_EXACTLY).GetFilePath(); | 1267 icon_size, ExtensionIconSet::MATCH_EXACTLY).GetFilePath(); |
| 1681 DecodeIconFromPath(icon_path, icon_size, result); | 1268 DecodeIconFromPath(icon_path, icon_size, result); |
| 1682 } | 1269 } |
| 1683 | 1270 |
| 1684 // static | 1271 // static |
| 1685 void Extension::DecodeIconFromPath(const FilePath& icon_path, | 1272 void Extension::DecodeIconFromPath(const FilePath& icon_path, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1732 chrome::kStandardSchemeSeparator + extension_id + "/"); | 1319 chrome::kStandardSchemeSeparator + extension_id + "/"); |
| 1733 } | 1320 } |
| 1734 | 1321 |
| 1735 bool Extension::InitFromValue(const DictionaryValue& source, int flags, | 1322 bool Extension::InitFromValue(const DictionaryValue& source, int flags, |
| 1736 std::string* error) { | 1323 std::string* error) { |
| 1737 // When strict error checks are enabled, make URL pattern parsing strict. | 1324 // When strict error checks are enabled, make URL pattern parsing strict. |
| 1738 URLPattern::ParseOption parse_strictness = | 1325 URLPattern::ParseOption parse_strictness = |
| 1739 (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT | 1326 (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT |
| 1740 : URLPattern::PARSE_LENIENT); | 1327 : URLPattern::PARSE_LENIENT); |
| 1741 | 1328 |
| 1329 // Initialize permissions with an empty, default permission set. |
| 1330 permission_set_.reset(new ExtensionPermissionSet()); |
| 1331 |
| 1742 if (source.HasKey(keys::kPublicKey)) { | 1332 if (source.HasKey(keys::kPublicKey)) { |
| 1743 std::string public_key_bytes; | 1333 std::string public_key_bytes; |
| 1744 if (!source.GetString(keys::kPublicKey, | 1334 if (!source.GetString(keys::kPublicKey, |
| 1745 &public_key_) || | 1335 &public_key_) || |
| 1746 !ParsePEMKeyBytes(public_key_, | 1336 !ParsePEMKeyBytes(public_key_, |
| 1747 &public_key_bytes) || | 1337 &public_key_bytes) || |
| 1748 !GenerateId(public_key_bytes, &id_)) { | 1338 !GenerateId(public_key_bytes, &id_)) { |
| 1749 *error = errors::kInvalidKey; | 1339 *error = errors::kInvalidKey; |
| 1750 return false; | 1340 return false; |
| 1751 } | 1341 } |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2250 return false; | 1840 return false; |
| 2251 } | 1841 } |
| 2252 options_url_ = GetResourceURL(options_str); | 1842 options_url_ = GetResourceURL(options_str); |
| 2253 if (!options_url_.is_valid()) { | 1843 if (!options_url_.is_valid()) { |
| 2254 *error = errors::kInvalidOptionsPage; | 1844 *error = errors::kInvalidOptionsPage; |
| 2255 return false; | 1845 return false; |
| 2256 } | 1846 } |
| 2257 } | 1847 } |
| 2258 } | 1848 } |
| 2259 | 1849 |
| 1850 ExtensionAPIPermissionSet api_permissions; |
| 1851 URLPatternSet host_permissions; |
| 1852 |
| 2260 // Initialize the permissions (optional). | 1853 // Initialize the permissions (optional). |
| 2261 if (source.HasKey(keys::kPermissions)) { | 1854 if (source.HasKey(keys::kPermissions)) { |
| 2262 ListValue* permissions = NULL; | 1855 ListValue* permissions = NULL; |
| 2263 if (!source.GetList(keys::kPermissions, &permissions)) { | 1856 if (!source.GetList(keys::kPermissions, &permissions)) { |
| 2264 *error = ExtensionErrorUtils::FormatErrorMessage( | 1857 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2265 errors::kInvalidPermissions, ""); | 1858 errors::kInvalidPermissions, ""); |
| 2266 return false; | 1859 return false; |
| 2267 } | 1860 } |
| 2268 | 1861 |
| 2269 for (size_t i = 0; i < permissions->GetSize(); ++i) { | 1862 for (size_t i = 0; i < permissions->GetSize(); ++i) { |
| 2270 std::string permission_str; | 1863 std::string permission_str; |
| 2271 if (!permissions->GetString(i, &permission_str)) { | 1864 if (!permissions->GetString(i, &permission_str)) { |
| 2272 *error = ExtensionErrorUtils::FormatErrorMessage( | 1865 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2273 errors::kInvalidPermission, base::IntToString(i)); | 1866 errors::kInvalidPermission, base::IntToString(i)); |
| 2274 return false; | 1867 return false; |
| 2275 } | 1868 } |
| 2276 | 1869 |
| 1870 ExtensionAPIPermission* permission = |
| 1871 ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str); |
| 1872 |
| 2277 // Only COMPONENT extensions can use private APIs. | 1873 // Only COMPONENT extensions can use private APIs. |
| 2278 // TODO(asargent) - We want a more general purpose mechanism for this, | 1874 // TODO(asargent) - We want a more general purpose mechanism for this, |
| 2279 // and better error messages. (http://crbug.com/54013) | 1875 // and better error messages. (http://crbug.com/54013) |
| 2280 if (!IsComponentOnlyPermission(permission_str) | 1876 if (!IsComponentOnlyPermission(permission) |
| 2281 #ifndef NDEBUG | 1877 #ifndef NDEBUG |
| 2282 && !CommandLine::ForCurrentProcess()->HasSwitch( | 1878 && !CommandLine::ForCurrentProcess()->HasSwitch( |
| 2283 switches::kExposePrivateExtensionApi) | 1879 switches::kExposePrivateExtensionApi) |
| 2284 #endif | 1880 #endif |
| 2285 ) { | 1881 ) { |
| 2286 continue; | 1882 continue; |
| 2287 } | 1883 } |
| 2288 | 1884 |
| 2289 // Remap the old unlimited storage permission name. | |
| 2290 if (permission_str == kOldUnlimitedStoragePermission) | |
| 2291 permission_str = kUnlimitedStoragePermission; | |
| 2292 | |
| 2293 if (web_extent().is_empty() || location() == Extension::COMPONENT) { | 1885 if (web_extent().is_empty() || location() == Extension::COMPONENT) { |
| 2294 // Check if it's a module permission. If so, enable that permission. | 1886 // Check if it's a module permission. If so, enable that permission. |
| 2295 if (IsAPIPermission(permission_str)) { | 1887 if (permission != NULL) { |
| 2296 // Only allow the experimental API permission if the command line | 1888 // Only allow the experimental API permission if the command line |
| 2297 // flag is present, or if the extension is a component of Chrome. | 1889 // flag is present, or if the extension is a component of Chrome. |
| 2298 if (IsDisallowedExperimentalPermission(permission_str) && | 1890 if (IsDisallowedExperimentalPermission(permission->id()) && |
| 2299 location() != Extension::COMPONENT) { | 1891 location() != Extension::COMPONENT) { |
| 2300 *error = errors::kExperimentalFlagRequired; | 1892 *error = errors::kExperimentalFlagRequired; |
| 2301 return false; | 1893 return false; |
| 2302 } | 1894 } |
| 2303 api_permissions_.insert(permission_str); | 1895 api_permissions.insert(permission->id()); |
| 2304 continue; | 1896 continue; |
| 2305 } | 1897 } |
| 2306 } else { | 1898 } else { |
| 2307 // Hosted apps only get access to a subset of the valid permissions. | 1899 // Hosted apps only get access to a subset of the valid permissions. |
| 2308 if (IsHostedAppPermission(permission_str)) { | 1900 if (permission != NULL && permission->is_hosted_app()) { |
| 2309 if (IsDisallowedExperimentalPermission(permission_str)) { | 1901 if (IsDisallowedExperimentalPermission(permission->id())) { |
| 2310 *error = errors::kExperimentalFlagRequired; | 1902 *error = errors::kExperimentalFlagRequired; |
| 2311 return false; | 1903 return false; |
| 2312 } | 1904 } |
| 2313 api_permissions_.insert(permission_str); | 1905 api_permissions.insert(permission->id()); |
| 2314 continue; | 1906 continue; |
| 2315 } | 1907 } |
| 2316 } | 1908 } |
| 2317 | 1909 |
| 2318 // Check if it's a host pattern permission. | 1910 // Check if it's a host pattern permission. |
| 2319 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? | 1911 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? |
| 2320 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes); | 1912 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes); |
| 2321 | 1913 |
| 2322 URLPattern::ParseResult parse_result = pattern.Parse(permission_str, | 1914 URLPattern::ParseResult parse_result = pattern.Parse(permission_str, |
| 2323 parse_strictness); | 1915 parse_strictness); |
| 2324 if (parse_result == URLPattern::PARSE_SUCCESS) { | 1916 if (parse_result == URLPattern::PARSE_SUCCESS) { |
| 2325 if (!CanSpecifyHostPermission(pattern)) { | 1917 if (!CanSpecifyHostPermission(pattern)) { |
| 2326 *error = ExtensionErrorUtils::FormatErrorMessage( | 1918 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 2327 errors::kInvalidPermissionScheme, base::IntToString(i)); | 1919 errors::kInvalidPermissionScheme, base::IntToString(i)); |
| 2328 return false; | 1920 return false; |
| 2329 } | 1921 } |
| 2330 | 1922 |
| 2331 // The path component is not used for host permissions, so we force it | 1923 // The path component is not used for host permissions, so we force it |
| 2332 // to match all paths. | 1924 // to match all paths. |
| 2333 pattern.SetPath("/*"); | 1925 pattern.SetPath("/*"); |
| 2334 | 1926 |
| 2335 if (pattern.MatchesScheme(chrome::kFileScheme) && | 1927 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 2336 !CanExecuteScriptEverywhere()) { | 1928 !CanExecuteScriptEverywhere()) { |
| 2337 wants_file_access_ = true; | 1929 wants_file_access_ = true; |
| 2338 if (!(flags & ALLOW_FILE_ACCESS)) | 1930 if (!(flags & ALLOW_FILE_ACCESS)) |
| 2339 pattern.set_valid_schemes( | 1931 pattern.set_valid_schemes( |
| 2340 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 1932 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 2341 } | 1933 } |
| 2342 | 1934 |
| 2343 host_permissions_.push_back(pattern); | 1935 host_permissions.AddPattern(pattern); |
| 2344 } | 1936 } |
| 2345 | 1937 |
| 2346 // If it's not a host permission, then it's probably an unknown API | 1938 // If it's not a host permission, then it's probably an unknown API |
| 2347 // permission. Do not throw an error so extensions can retain | 1939 // permission. Do not throw an error so extensions can retain |
| 2348 // backwards compatability (http://crbug.com/42742). | 1940 // backwards compatability (http://crbug.com/42742). |
| 2349 // TODO(jstritar): We can improve error messages by adding better | 1941 // TODO(jstritar): We can improve error messages by adding better |
| 2350 // validation of API permissions here. | 1942 // validation of API permissions here. |
| 2351 // TODO(skerner): Consider showing the reason |permission_str| is not | 1943 // TODO(skerner): Consider showing the reason |permission_str| is not |
| 2352 // a valid URL pattern if it is almost valid. For example, if it has | 1944 // a valid URL pattern if it is almost valid. For example, if it has |
| 2353 // a valid scheme, and failed to parse because it has a port, show an | 1945 // a valid scheme, and failed to parse because it has a port, show an |
| 2354 // error. | 1946 // error. |
| 2355 } | 1947 } |
| 2356 } | 1948 } |
| 2357 | 1949 |
| 2358 // Initialize background url (optional). | 1950 // Initialize background url (optional). |
| 2359 if (source.HasKey(keys::kBackground)) { | 1951 if (source.HasKey(keys::kBackground)) { |
| 2360 std::string background_str; | 1952 std::string background_str; |
| 2361 if (!source.GetString(keys::kBackground, &background_str)) { | 1953 if (!source.GetString(keys::kBackground, &background_str)) { |
| 2362 *error = errors::kInvalidBackground; | 1954 *error = errors::kInvalidBackground; |
| 2363 return false; | 1955 return false; |
| 2364 } | 1956 } |
| 2365 | 1957 |
| 2366 if (is_hosted_app()) { | 1958 if (is_hosted_app()) { |
| 2367 // Make sure "background" permission is set. | 1959 // Make sure "background" permission is set. |
| 2368 if (api_permissions_.find(kBackgroundPermission) == | 1960 if (!api_permissions.count(ExtensionAPIPermission::kBackground)) { |
| 2369 api_permissions_.end()) { | |
| 2370 *error = errors::kBackgroundPermissionNeeded; | 1961 *error = errors::kBackgroundPermissionNeeded; |
| 2371 return false; | 1962 return false; |
| 2372 } | 1963 } |
| 2373 // Hosted apps require an absolute URL. | 1964 // Hosted apps require an absolute URL. |
| 2374 GURL bg_page(background_str); | 1965 GURL bg_page(background_str); |
| 2375 if (!bg_page.is_valid()) { | 1966 if (!bg_page.is_valid()) { |
| 2376 *error = errors::kInvalidBackgroundInHostedApp; | 1967 *error = errors::kInvalidBackgroundInHostedApp; |
| 2377 return false; | 1968 return false; |
| 2378 } | 1969 } |
| 2379 | 1970 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2598 content_security_policy_ = content_security_policy; | 2189 content_security_policy_ = content_security_policy; |
| 2599 } | 2190 } |
| 2600 | 2191 |
| 2601 // Initialize devtools page url (optional). | 2192 // Initialize devtools page url (optional). |
| 2602 if (source.HasKey(keys::kDevToolsPage)) { | 2193 if (source.HasKey(keys::kDevToolsPage)) { |
| 2603 std::string devtools_str; | 2194 std::string devtools_str; |
| 2604 if (!source.GetString(keys::kDevToolsPage, &devtools_str)) { | 2195 if (!source.GetString(keys::kDevToolsPage, &devtools_str)) { |
| 2605 *error = errors::kInvalidDevToolsPage; | 2196 *error = errors::kInvalidDevToolsPage; |
| 2606 return false; | 2197 return false; |
| 2607 } | 2198 } |
| 2608 if (!HasApiPermission(Extension::kExperimentalPermission)) { | 2199 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { |
| 2609 *error = errors::kDevToolsExperimental; | 2200 *error = errors::kDevToolsExperimental; |
| 2610 return false; | 2201 return false; |
| 2611 } | 2202 } |
| 2612 devtools_url_ = GetResourceURL(devtools_str); | 2203 devtools_url_ = GetResourceURL(devtools_str); |
| 2613 } | 2204 } |
| 2614 | 2205 |
| 2615 // Initialize sidebar action (optional). | 2206 // Initialize sidebar action (optional). |
| 2616 if (source.HasKey(keys::kSidebar)) { | 2207 if (source.HasKey(keys::kSidebar)) { |
| 2617 DictionaryValue* sidebar_value = NULL; | 2208 DictionaryValue* sidebar_value = NULL; |
| 2618 if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) { | 2209 if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) { |
| 2619 *error = errors::kInvalidSidebar; | 2210 *error = errors::kInvalidSidebar; |
| 2620 return false; | 2211 return false; |
| 2621 } | 2212 } |
| 2622 if (!HasApiPermission(Extension::kExperimentalPermission)) { | 2213 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { |
| 2623 *error = errors::kSidebarExperimental; | 2214 *error = errors::kSidebarExperimental; |
| 2624 return false; | 2215 return false; |
| 2625 } | 2216 } |
| 2626 sidebar_defaults_.reset(LoadExtensionSidebarDefaults(sidebar_value, error)); | 2217 sidebar_defaults_.reset(LoadExtensionSidebarDefaults(sidebar_value, error)); |
| 2627 if (!sidebar_defaults_.get()) | 2218 if (!sidebar_defaults_.get()) |
| 2628 return false; // Failed to parse sidebar definition. | 2219 return false; // Failed to parse sidebar definition. |
| 2629 } | 2220 } |
| 2630 | 2221 |
| 2631 // Initialize text-to-speech voices (optional). | 2222 // Initialize text-to-speech voices (optional). |
| 2632 if (source.HasKey(keys::kTts)) { | 2223 if (source.HasKey(keys::kTts)) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2698 *error = errors::kInvalidIncognitoBehavior; | 2289 *error = errors::kInvalidIncognitoBehavior; |
| 2699 return false; | 2290 return false; |
| 2700 } | 2291 } |
| 2701 } | 2292 } |
| 2702 | 2293 |
| 2703 if (HasMultipleUISurfaces()) { | 2294 if (HasMultipleUISurfaces()) { |
| 2704 *error = errors::kOneUISurfaceOnly; | 2295 *error = errors::kOneUISurfaceOnly; |
| 2705 return false; | 2296 return false; |
| 2706 } | 2297 } |
| 2707 | 2298 |
| 2708 InitEffectiveHostPermissions(); | 2299 permission_set_.reset( |
| 2300 new ExtensionPermissionSet(this, api_permissions, host_permissions)); |
| 2709 | 2301 |
| 2710 // Although |source| is passed in as a const, it's still possible to modify | 2302 // Although |source| is passed in as a const, it's still possible to modify |
| 2711 // it. This is dangerous since the utility process re-uses |source| after | 2303 // it. This is dangerous since the utility process re-uses |source| after |
| 2712 // it calls InitFromValue, passing it up to the browser process which calls | 2304 // it calls InitFromValue, passing it up to the browser process which calls |
| 2713 // InitFromValue again. As a result, we need to make sure that nobody | 2305 // InitFromValue again. As a result, we need to make sure that nobody |
| 2714 // accidentally modifies it. | 2306 // accidentally modifies it. |
| 2715 DCHECK(source.Equals(manifest_value_.get())); | 2307 DCHECK(source.Equals(manifest_value_.get())); |
| 2716 | 2308 |
| 2717 return true; | 2309 return true; |
| 2718 } | 2310 } |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2889 // Only allow access to chrome://favicon to regular extensions. Component | 2481 // Only allow access to chrome://favicon to regular extensions. Component |
| 2890 // extensions can have access to all of chrome://*. | 2482 // extensions can have access to all of chrome://*. |
| 2891 return (pattern.host() == chrome::kChromeUIFaviconHost || | 2483 return (pattern.host() == chrome::kChromeUIFaviconHost || |
| 2892 CanExecuteScriptEverywhere()); | 2484 CanExecuteScriptEverywhere()); |
| 2893 } | 2485 } |
| 2894 | 2486 |
| 2895 // Otherwise, the valid schemes were handled by URLPattern. | 2487 // Otherwise, the valid schemes were handled by URLPattern. |
| 2896 return true; | 2488 return true; |
| 2897 } | 2489 } |
| 2898 | 2490 |
| 2899 // static | 2491 bool Extension::HasAPIPermission( |
| 2900 bool Extension::HasApiPermission( | 2492 ExtensionAPIPermission::ID permission) const { |
| 2901 const std::set<std::string>& api_permissions, | 2493 return permission_set()->HasAPIPermission(permission); |
| 2902 const std::string& function_name) { | 2494 } |
| 2903 std::string permission_name = function_name; | |
| 2904 | 2495 |
| 2905 for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) { | 2496 bool Extension::HasAPIPermission( |
| 2906 if (permission_name == kNonPermissionFunctionNames[i]) | 2497 const std::string& function_name) const { |
| 2907 return true; | 2498 return permission_set()->HasAccessToFunction(function_name); |
| 2908 } | 2499 } |
| 2909 | 2500 |
| 2910 // See if this is a function or event name first and strip out the package. | 2501 const URLPatternSet& Extension::GetEffectiveHostPermissions() const { |
| 2911 // Functions will be of the form package.function | 2502 return permission_set()->effective_hosts(); |
| 2912 // Events will be of the form package/id or package.optional.stuff | |
| 2913 size_t separator = function_name.find_first_of("./"); | |
| 2914 if (separator != std::string::npos) | |
| 2915 permission_name = function_name.substr(0, separator); | |
| 2916 | |
| 2917 // windows and tabs are the same permission. | |
| 2918 if (permission_name == kWindowPermission) | |
| 2919 permission_name = Extension::kTabPermission; | |
| 2920 | |
| 2921 if (api_permissions.count(permission_name)) | |
| 2922 return true; | |
| 2923 | |
| 2924 for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) { | |
| 2925 if (permission_name == kNonPermissionModuleNames[i]) { | |
| 2926 return true; | |
| 2927 } | |
| 2928 } | |
| 2929 | |
| 2930 return false; | |
| 2931 } | 2503 } |
| 2932 | 2504 |
| 2933 bool Extension::HasHostPermission(const GURL& url) const { | 2505 bool Extension::HasHostPermission(const GURL& url) const { |
| 2934 for (URLPatternList::const_iterator host = host_permissions().begin(); | 2506 if (url.SchemeIs(chrome::kChromeUIScheme) && |
| 2935 host != host_permissions().end(); ++host) { | 2507 url.host() != chrome::kChromeUIFaviconHost && |
| 2936 // Non-component extensions can only access chrome://favicon and no other | 2508 location() != Extension::COMPONENT) |
| 2937 // chrome:// scheme urls. | 2509 return false; |
| 2938 if (url.SchemeIs(chrome::kChromeUIScheme) && | 2510 return permission_set()->HasExplicitAccessToOrigin(url); |
| 2939 url.host() != chrome::kChromeUIFaviconHost && | |
| 2940 location() != Extension::COMPONENT) | |
| 2941 return false; | |
| 2942 | |
| 2943 if (host->MatchesURL(url)) | |
| 2944 return true; | |
| 2945 } | |
| 2946 return false; | |
| 2947 } | 2511 } |
| 2948 | 2512 |
| 2949 void Extension::InitEffectiveHostPermissions() { | 2513 bool Extension::IsComponentOnlyPermission( |
| 2950 // Some APIs effectively grant access to every site. New ones should be | 2514 const ExtensionAPIPermission* api) const { |
| 2951 // added here. (I'm looking at you, network API) | |
| 2952 if (HasApiPermission(api_permissions_, kProxyPermission) || | |
| 2953 !devtools_url_.is_empty()) { | |
| 2954 URLPattern all_urls(URLPattern::SCHEME_ALL); | |
| 2955 all_urls.set_match_all_urls(true); | |
| 2956 effective_host_permissions_.AddPattern(all_urls); | |
| 2957 return; | |
| 2958 } | |
| 2959 | |
| 2960 for (URLPatternList::const_iterator host = host_permissions().begin(); | |
| 2961 host != host_permissions().end(); ++host) | |
| 2962 effective_host_permissions_.AddPattern(*host); | |
| 2963 | |
| 2964 for (UserScriptList::const_iterator content_script = | |
| 2965 content_scripts().begin(); | |
| 2966 content_script != content_scripts().end(); ++content_script) { | |
| 2967 URLPatternList::const_iterator pattern = | |
| 2968 content_script->url_patterns().begin(); | |
| 2969 for (; pattern != content_script->url_patterns().end(); ++pattern) | |
| 2970 effective_host_permissions_.AddPattern(*pattern); | |
| 2971 } | |
| 2972 } | |
| 2973 | |
| 2974 bool Extension::IsComponentOnlyPermission(const std::string& permission) const { | |
| 2975 if (location() == Extension::COMPONENT) | 2515 if (location() == Extension::COMPONENT) |
| 2976 return true; | 2516 return true; |
| 2977 | 2517 |
| 2978 // Non-component extensions are not allowed to access private apis. | 2518 if (api == NULL) |
| 2979 for (size_t i = 0; i < Extension::kNumComponentPrivatePermissions; ++i) { | 2519 return true; |
| 2980 if (permission == Extension::kComponentPrivatePermissionNames[i]) | 2520 |
| 2981 return false; | 2521 return !api->is_component_only(); |
| 2982 } | |
| 2983 return true; | |
| 2984 } | 2522 } |
| 2985 | 2523 |
| 2986 bool Extension::HasMultipleUISurfaces() const { | 2524 bool Extension::HasMultipleUISurfaces() const { |
| 2987 int num_surfaces = 0; | 2525 int num_surfaces = 0; |
| 2988 | 2526 |
| 2989 if (page_action()) | 2527 if (page_action()) |
| 2990 ++num_surfaces; | 2528 ++num_surfaces; |
| 2991 | 2529 |
| 2992 if (browser_action()) | 2530 if (browser_action()) |
| 2993 ++num_surfaces; | 2531 ++num_surfaces; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3018 if (page_url.SchemeIs(chrome::kChromeUIScheme) && | 2556 if (page_url.SchemeIs(chrome::kChromeUIScheme) && |
| 3019 !CanExecuteScriptEverywhere()) | 2557 !CanExecuteScriptEverywhere()) |
| 3020 return false; | 2558 return false; |
| 3021 | 2559 |
| 3022 // If a script is specified, use its matches. | 2560 // If a script is specified, use its matches. |
| 3023 if (script) | 2561 if (script) |
| 3024 return script->MatchesURL(page_url); | 2562 return script->MatchesURL(page_url); |
| 3025 | 2563 |
| 3026 // Otherwise, see if this extension has permission to execute script | 2564 // Otherwise, see if this extension has permission to execute script |
| 3027 // programmatically on pages. | 2565 // programmatically on pages. |
| 3028 for (size_t i = 0; i < host_permissions_.size(); ++i) { | 2566 if (permission_set()->HasExplicitAccessToOrigin(page_url)) |
| 3029 if (host_permissions_[i].MatchesURL(page_url)) | 2567 return true; |
| 3030 return true; | |
| 3031 } | |
| 3032 | 2568 |
| 3033 if (error) { | 2569 if (error) { |
| 3034 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, | 2570 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, |
| 3035 page_url.spec()); | 2571 page_url.spec()); |
| 3036 } | 2572 } |
| 3037 | 2573 |
| 3038 return false; | 2574 return false; |
| 3039 } | 2575 } |
| 3040 | 2576 |
| 3041 // static | |
| 3042 bool Extension::HasEffectiveAccessToAllHosts( | |
| 3043 const URLPatternSet& effective_host_permissions, | |
| 3044 const std::set<std::string>& api_permissions) { | |
| 3045 const URLPatternList patterns = effective_host_permissions.patterns(); | |
| 3046 for (URLPatternList::const_iterator host = patterns.begin(); | |
| 3047 host != patterns.end(); ++host) { | |
| 3048 if (host->match_all_urls() || | |
| 3049 (host->match_subdomains() && host->host().empty())) | |
| 3050 return true; | |
| 3051 } | |
| 3052 | |
| 3053 return false; | |
| 3054 } | |
| 3055 | |
| 3056 bool Extension::HasEffectiveAccessToAllHosts() const { | 2577 bool Extension::HasEffectiveAccessToAllHosts() const { |
| 3057 return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(), | 2578 return permission_set_->HasEffectiveAccessToAllHosts(); |
| 3058 api_permissions()); | |
| 3059 } | 2579 } |
| 3060 | 2580 |
| 3061 bool Extension::HasFullPermissions() const { | 2581 bool Extension::HasFullPermissions() const { |
| 3062 return !plugins().empty(); | 2582 return permission_set_->HasEffectiveFullAccess(); |
| 3063 } | 2583 } |
| 3064 | 2584 |
| 3065 bool Extension::ShowConfigureContextMenus() const { | 2585 bool Extension::ShowConfigureContextMenus() const { |
| 3066 // Don't show context menu for component extensions. We might want to show | 2586 // Don't show context menu for component extensions. We might want to show |
| 3067 // options for component extension button but now there is no component | 2587 // options for component extension button but now there is no component |
| 3068 // extension with options. All other menu items like uninstall have | 2588 // extension with options. All other menu items like uninstall have |
| 3069 // no sense for component extensions. | 2589 // no sense for component extensions. |
| 3070 return location() != Extension::COMPONENT; | 2590 return location() != Extension::COMPONENT; |
| 3071 } | 2591 } |
| 3072 | 2592 |
| 3073 bool Extension::IsDisallowedExperimentalPermission( | 2593 bool Extension::IsDisallowedExperimentalPermission( |
| 3074 const std::string& permission_str) const { | 2594 ExtensionAPIPermission::ID permission) const { |
| 3075 return permission_str == Extension::kExperimentalPermission && | 2595 return permission == ExtensionAPIPermission::kExperimental && |
| 3076 !CommandLine::ForCurrentProcess()->HasSwitch( | 2596 !CommandLine::ForCurrentProcess()->HasSwitch( |
| 3077 switches::kEnableExperimentalExtensionApis); | 2597 switches::kEnableExperimentalExtensionApis); |
| 3078 } | 2598 } |
| 3079 | 2599 |
| 3080 bool Extension::IsAPIPermission(const std::string& str) const { | |
| 3081 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { | |
| 3082 if (str == Extension::kPermissions[i].name) { | |
| 3083 return true; | |
| 3084 } | |
| 3085 } | |
| 3086 return false; | |
| 3087 } | |
| 3088 | |
| 3089 bool Extension::CanExecuteScriptEverywhere() const { | 2600 bool Extension::CanExecuteScriptEverywhere() const { |
| 3090 if (location() == Extension::COMPONENT | 2601 if (location() == Extension::COMPONENT |
| 3091 #ifndef NDEBUG | 2602 #ifndef NDEBUG |
| 3092 || CommandLine::ForCurrentProcess()->HasSwitch( | 2603 || CommandLine::ForCurrentProcess()->HasSwitch( |
| 3093 switches::kExposePrivateExtensionApi) | 2604 switches::kExposePrivateExtensionApi) |
| 3094 #endif | 2605 #endif |
| 3095 ) | 2606 ) |
| 3096 return true; | 2607 return true; |
| 3097 | 2608 |
| 3098 ScriptingWhitelist* whitelist = | 2609 ScriptingWhitelist* whitelist = |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3154 extension_location(location) { | 2665 extension_location(location) { |
| 3155 if (manifest) | 2666 if (manifest) |
| 3156 extension_manifest.reset(manifest->DeepCopy()); | 2667 extension_manifest.reset(manifest->DeepCopy()); |
| 3157 } | 2668 } |
| 3158 | 2669 |
| 3159 ExtensionInfo::~ExtensionInfo() {} | 2670 ExtensionInfo::~ExtensionInfo() {} |
| 3160 | 2671 |
| 3161 UninstalledExtensionInfo::UninstalledExtensionInfo( | 2672 UninstalledExtensionInfo::UninstalledExtensionInfo( |
| 3162 const Extension& extension) | 2673 const Extension& extension) |
| 3163 : extension_id(extension.id()), | 2674 : extension_id(extension.id()), |
| 3164 extension_api_permissions(extension.api_permissions()), | 2675 extension_api_permissions( |
| 2676 extension.permission_set()->GetAPIsAsStrings()), |
| 3165 extension_type(extension.GetType()), | 2677 extension_type(extension.GetType()), |
| 3166 update_url(extension.update_url()) {} | 2678 update_url(extension.update_url()) {} |
| 3167 | 2679 |
| 3168 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} | 2680 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} |
| 3169 | 2681 |
| 3170 | 2682 |
| 3171 UnloadedExtensionInfo::UnloadedExtensionInfo( | 2683 UnloadedExtensionInfo::UnloadedExtensionInfo( |
| 3172 const Extension* extension, | 2684 const Extension* extension, |
| 3173 Reason reason) | 2685 Reason reason) |
| 3174 : reason(reason), | 2686 : reason(reason), |
| 3175 already_disabled(false), | 2687 already_disabled(false), |
| 3176 extension(extension) {} | 2688 extension(extension) {} |
| OLD | NEW |