Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: chrome/common/extensions/extension.cc

Issue 8313006: Allow webstore extensions to use experimental permissions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 1111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 *error = errors::kInvalidLaunchHeight; 1122 *error = errors::kInvalidLaunchHeight;
1123 return false; 1123 return false;
1124 } 1124 }
1125 } 1125 }
1126 1126
1127 return true; 1127 return true;
1128 } 1128 }
1129 1129
1130 bool Extension::LoadAppIsolation(const DictionaryValue* manifest, 1130 bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
1131 std::string* error) { 1131 std::string* error) {
1132 // Only parse app isolation features if this switch is present.
1133 if (!CommandLine::ForCurrentProcess()->HasSwitch(
1134 switches::kEnableExperimentalExtensionApis))
1135 return true;
1136
1137 Value* temp = NULL; 1132 Value* temp = NULL;
1138 if (!manifest->Get(keys::kIsolation, &temp)) 1133 if (!manifest->Get(keys::kIsolation, &temp))
1139 return true; 1134 return true;
1140 1135
1141 if (temp->GetType() != Value::TYPE_LIST) { 1136 if (temp->GetType() != Value::TYPE_LIST) {
1142 *error = errors::kInvalidIsolation; 1137 *error = errors::kInvalidIsolation;
1143 return false; 1138 return false;
1144 } 1139 }
1145 1140
1146 ListValue* isolation_list = static_cast<ListValue*>(temp); 1141 ListValue* isolation_list = static_cast<ListValue*>(temp);
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 1484
1490 // Initialize name. 1485 // Initialize name.
1491 string16 localized_name; 1486 string16 localized_name;
1492 if (!source.GetString(keys::kName, &localized_name)) { 1487 if (!source.GetString(keys::kName, &localized_name)) {
1493 *error = errors::kInvalidName; 1488 *error = errors::kInvalidName;
1494 return false; 1489 return false;
1495 } 1490 }
1496 base::i18n::AdjustStringForLocaleDirection(&localized_name); 1491 base::i18n::AdjustStringForLocaleDirection(&localized_name);
1497 name_ = UTF16ToUTF8(localized_name); 1492 name_ = UTF16ToUTF8(localized_name);
1498 1493
1494 // Initialize the permissions (optional).
1495 ExtensionAPIPermissionSet api_permissions;
1496 URLPatternSet host_permissions;
1497 if (!ParsePermissions(&source,
1498 keys::kPermissions,
1499 flags,
1500 error,
1501 &api_permissions,
1502 &host_permissions)) {
1503 return false;
1504 }
1505
1506 // Initialize the optional permissions (optional).
1507 ExtensionAPIPermissionSet optional_api_permissions;
1508 URLPatternSet optional_host_permissions;
1509 if (!ParsePermissions(&source,
1510 keys::kOptionalPermissions,
1511 flags,
1512 error,
1513 &optional_api_permissions,
1514 &optional_host_permissions)) {
1515 return false;
1516 }
1517
1499 // Initialize description (if present). 1518 // Initialize description (if present).
1500 if (source.HasKey(keys::kDescription)) { 1519 if (source.HasKey(keys::kDescription)) {
1501 if (!source.GetString(keys::kDescription, 1520 if (!source.GetString(keys::kDescription,
1502 &description_)) { 1521 &description_)) {
1503 *error = errors::kInvalidDescription; 1522 *error = errors::kInvalidDescription;
1504 return false; 1523 return false;
1505 } 1524 }
1506 } 1525 }
1507 1526
1508 // Initialize homepage url (if present). 1527 // Initialize homepage url (if present).
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
1776 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); 1795 errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
1777 return false; 1796 return false;
1778 } 1797 }
1779 1798
1780 nacl_modules_.push_back(NaClModuleInfo()); 1799 nacl_modules_.push_back(NaClModuleInfo());
1781 nacl_modules_.back().url = GetResourceURL(path_str); 1800 nacl_modules_.back().url = GetResourceURL(path_str);
1782 nacl_modules_.back().mime_type = mime_type; 1801 nacl_modules_.back().mime_type = mime_type;
1783 } 1802 }
1784 } 1803 }
1785 1804
1786 // Initialize toolstrips. This is deprecated for public use. 1805 // Initialize toolstrips.
1787 // NOTE(erikkay) Although deprecated, we intend to preserve this parsing 1806 // TODO(aa): Remove this and all the related tests, docs, etc.
1788 // code indefinitely. Please contact me or Joi for details as to why. 1807 // See: crbug.com/100488.
1789 if (CommandLine::ForCurrentProcess()->HasSwitch( 1808 if (api_permissions.count(ExtensionAPIPermission::kExperimental) &&
1790 switches::kEnableExperimentalExtensionApis) &&
1791 source.HasKey(keys::kToolstrips)) { 1809 source.HasKey(keys::kToolstrips)) {
1792 ListValue* list_value = NULL; 1810 ListValue* list_value = NULL;
1793 if (!source.GetList(keys::kToolstrips, &list_value)) { 1811 if (!source.GetList(keys::kToolstrips, &list_value)) {
1794 *error = errors::kInvalidToolstrips; 1812 *error = errors::kInvalidToolstrips;
1795 return false; 1813 return false;
1796 } 1814 }
1797 1815
1798 for (size_t i = 0; i < list_value->GetSize(); ++i) { 1816 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1799 GURL toolstrip; 1817 GURL toolstrip;
1800 DictionaryValue* toolstrip_value = NULL; 1818 DictionaryValue* toolstrip_value = NULL;
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1916 } 1934 }
1917 1935
1918 // Load App settings. 1936 // Load App settings.
1919 if (!LoadIsApp(manifest_value_.get(), error) || 1937 if (!LoadIsApp(manifest_value_.get(), error) ||
1920 !LoadExtent(manifest_value_.get(), keys::kWebURLs, 1938 !LoadExtent(manifest_value_.get(), keys::kWebURLs,
1921 &extent_, 1939 &extent_,
1922 errors::kInvalidWebURLs, errors::kInvalidWebURL, 1940 errors::kInvalidWebURLs, errors::kInvalidWebURL,
1923 parse_strictness, error) || 1941 parse_strictness, error) ||
1924 !EnsureNotHybridApp(manifest_value_.get(), error) || 1942 !EnsureNotHybridApp(manifest_value_.get(), error) ||
1925 !LoadLaunchURL(manifest_value_.get(), error) || 1943 !LoadLaunchURL(manifest_value_.get(), error) ||
1926 !LoadLaunchContainer(manifest_value_.get(), error) || 1944 !LoadLaunchContainer(manifest_value_.get(), error))
1927 !LoadAppIsolation(manifest_value_.get(), error)) {
1928 return false; 1945 return false;
1946
1947 if (api_permissions.count(ExtensionAPIPermission::kExperimental)) {
1948 if (!LoadAppIsolation(manifest_value_.get(), error))
1949 return false;
1929 } 1950 }
1930 1951
1931 // Initialize options page url (optional). 1952 // Initialize options page url (optional).
1932 // Function LoadIsApp() set is_app_ above. 1953 // Function LoadIsApp() set is_app_ above.
1933 if (source.HasKey(keys::kOptionsPage)) { 1954 if (source.HasKey(keys::kOptionsPage)) {
1934 std::string options_str; 1955 std::string options_str;
1935 if (!source.GetString(keys::kOptionsPage, &options_str)) { 1956 if (!source.GetString(keys::kOptionsPage, &options_str)) {
1936 *error = errors::kInvalidOptionsPage; 1957 *error = errors::kInvalidOptionsPage;
1937 return false; 1958 return false;
1938 } 1959 }
(...skipping 14 matching lines...) Expand all
1953 return false; 1974 return false;
1954 } 1975 }
1955 options_url_ = GetResourceURL(options_str); 1976 options_url_ = GetResourceURL(options_str);
1956 if (!options_url_.is_valid()) { 1977 if (!options_url_.is_valid()) {
1957 *error = errors::kInvalidOptionsPage; 1978 *error = errors::kInvalidOptionsPage;
1958 return false; 1979 return false;
1959 } 1980 }
1960 } 1981 }
1961 } 1982 }
1962 1983
1963 // Initialize the permissions (optional).
1964 ExtensionAPIPermissionSet api_permissions;
1965 URLPatternSet host_permissions;
1966 if (!ParsePermissions(&source,
1967 keys::kPermissions,
1968 flags,
1969 error,
1970 &api_permissions,
1971 &host_permissions)) {
1972 return false;
1973 }
1974
1975 // Initialize the optional permissions (optional).
1976 ExtensionAPIPermissionSet optional_api_permissions;
1977 URLPatternSet optional_host_permissions;
1978 if (!ParsePermissions(&source,
1979 keys::kOptionalPermissions,
1980 flags,
1981 error,
1982 &optional_api_permissions,
1983 &optional_host_permissions)) {
1984 return false;
1985 }
1986
1987 // Initialize background url (optional). 1984 // Initialize background url (optional).
1988 if (source.HasKey(keys::kBackground)) { 1985 if (source.HasKey(keys::kBackground)) {
1989 std::string background_str; 1986 std::string background_str;
1990 if (!source.GetString(keys::kBackground, &background_str)) { 1987 if (!source.GetString(keys::kBackground, &background_str)) {
1991 *error = errors::kInvalidBackground; 1988 *error = errors::kInvalidBackground;
1992 return false; 1989 return false;
1993 } 1990 }
1994 1991
1995 if (is_hosted_app()) { 1992 if (is_hosted_app()) {
1996 // Make sure "background" permission is set. 1993 // Make sure "background" permission is set.
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
2063 chrome_url_overrides_[page] = GetResourceURL(val); 2060 chrome_url_overrides_[page] = GetResourceURL(val);
2064 } 2061 }
2065 2062
2066 // An extension may override at most one page. 2063 // An extension may override at most one page.
2067 if (overrides->size() > 1) { 2064 if (overrides->size() > 1) {
2068 *error = errors::kMultipleOverrides; 2065 *error = errors::kMultipleOverrides;
2069 return false; 2066 return false;
2070 } 2067 }
2071 } 2068 }
2072 2069
2073 if (CommandLine::ForCurrentProcess()->HasSwitch( 2070 if (api_permissions.count(ExtensionAPIPermission::kExperimental) &&
2074 switches::kEnableExperimentalExtensionApis) &&
2075 source.HasKey(keys::kInputComponents)) { 2071 source.HasKey(keys::kInputComponents)) {
2076 ListValue* list_value = NULL; 2072 ListValue* list_value = NULL;
2077 if (!source.GetList(keys::kInputComponents, &list_value)) { 2073 if (!source.GetList(keys::kInputComponents, &list_value)) {
2078 *error = errors::kInvalidInputComponents; 2074 *error = errors::kInvalidInputComponents;
2079 return false; 2075 return false;
2080 } 2076 }
2081 2077
2082 for (size_t i = 0; i < list_value->GetSize(); ++i) { 2078 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2083 DictionaryValue* module_value = NULL; 2079 DictionaryValue* module_value = NULL;
2084 std::string name_str; 2080 std::string name_str;
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
2591 std::string permission_str; 2587 std::string permission_str;
2592 if (!permissions->GetString(i, &permission_str)) { 2588 if (!permissions->GetString(i, &permission_str)) {
2593 *error = ExtensionErrorUtils::FormatErrorMessage( 2589 *error = ExtensionErrorUtils::FormatErrorMessage(
2594 errors::kInvalidPermission, base::IntToString(i)); 2590 errors::kInvalidPermission, base::IntToString(i));
2595 return false; 2591 return false;
2596 } 2592 }
2597 2593
2598 ExtensionAPIPermission* permission = 2594 ExtensionAPIPermission* permission =
2599 ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str); 2595 ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str);
2600 2596
2601 // Only COMPONENT extensions can use private APIs. 2597 if (permission != NULL) {
2602 // TODO(asargent) - We want a more general purpose mechanism for this, 2598 if (CanSpecifyAPIPermission(permission, error))
2603 // and better error messages. (http://crbug.com/54013) 2599 api_permissions->insert(permission->id());
2604 if (!IsComponentOnlyPermission(permission) 2600
2605 #ifndef NDEBUG 2601 // Sometimes when you can't specify an API permission we ignore it
2606 && !CommandLine::ForCurrentProcess()->HasSwitch( 2602 // silently. This seems like a bug. Specifically, crbug.com/100489.
2607 switches::kExposePrivateExtensionApi) 2603 if (!error->empty())
2608 #endif 2604 return false;
2609 ) { 2605
2610 continue; 2606 continue;
2611 } 2607 }
2612 2608
2613 if (web_extent().is_empty() || location() == Extension::COMPONENT) {
2614 // Check if it's a module permission. If so, enable that permission.
2615 if (permission != NULL) {
2616 // Only allow the experimental API permission if the command line
2617 // flag is present, or if the extension is a component of Chrome.
2618 if (IsDisallowedExperimentalPermission(permission->id()) &&
2619 location() != Extension::COMPONENT) {
2620 *error = errors::kExperimentalFlagRequired;
2621 return false;
2622 }
2623 api_permissions->insert(permission->id());
2624 continue;
2625 }
2626 } else {
2627 // Hosted apps only get access to a subset of the valid permissions.
2628 if (permission != NULL && permission->is_hosted_app()) {
2629 if (IsDisallowedExperimentalPermission(permission->id())) {
2630 *error = errors::kExperimentalFlagRequired;
2631 return false;
2632 }
2633 api_permissions->insert(permission->id());
2634 continue;
2635 }
2636 }
2637
2638 // Check if it's a host pattern permission. 2609 // Check if it's a host pattern permission.
2639 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? 2610 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
2640 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes); 2611 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes);
2641 2612
2642 URLPattern::ParseResult parse_result = pattern.Parse(permission_str, 2613 URLPattern::ParseResult parse_result = pattern.Parse(permission_str,
2643 parse_strictness); 2614 parse_strictness);
2644 if (parse_result == URLPattern::PARSE_SUCCESS) { 2615 if (parse_result == URLPattern::PARSE_SUCCESS) {
2645 if (!CanSpecifyHostPermission(pattern)) { 2616 if (!CanSpecifyHostPermission(pattern)) {
2646 *error = ExtensionErrorUtils::FormatErrorMessage( 2617 *error = ExtensionErrorUtils::FormatErrorMessage(
2647 errors::kInvalidPermissionScheme, base::IntToString(i)); 2618 errors::kInvalidPermissionScheme, base::IntToString(i));
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
2753 base::AutoLock auto_lock(runtime_data_lock_); 2724 base::AutoLock auto_lock(runtime_data_lock_);
2754 runtime_data_.SetActivePermissions(permissions); 2725 runtime_data_.SetActivePermissions(permissions);
2755 } 2726 }
2756 2727
2757 scoped_refptr<const ExtensionPermissionSet> 2728 scoped_refptr<const ExtensionPermissionSet>
2758 Extension::GetActivePermissions() const { 2729 Extension::GetActivePermissions() const {
2759 base::AutoLock auto_lock(runtime_data_lock_); 2730 base::AutoLock auto_lock(runtime_data_lock_);
2760 return runtime_data_.GetActivePermissions(); 2731 return runtime_data_.GetActivePermissions();
2761 } 2732 }
2762 2733
2763 bool Extension::IsComponentOnlyPermission(
2764 const ExtensionAPIPermission* api) const {
2765 if (location() == Extension::COMPONENT)
2766 return true;
2767
2768 if (api == NULL)
2769 return true;
2770
2771 return !api->is_component_only();
2772 }
2773
2774 bool Extension::HasMultipleUISurfaces() const { 2734 bool Extension::HasMultipleUISurfaces() const {
2775 int num_surfaces = 0; 2735 int num_surfaces = 0;
2776 2736
2777 if (page_action()) 2737 if (page_action())
2778 ++num_surfaces; 2738 ++num_surfaces;
2779 2739
2780 if (browser_action()) 2740 if (browser_action())
2781 ++num_surfaces; 2741 ++num_surfaces;
2782 2742
2783 if (is_app()) 2743 if (is_app())
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
2835 return location() != Extension::COMPONENT; 2795 return location() != Extension::COMPONENT;
2836 } 2796 }
2837 2797
2838 bool Extension::ImplicitlyDelaysNetworkStartup() const { 2798 bool Extension::ImplicitlyDelaysNetworkStartup() const {
2839 // Network requests should be deferred until any extensions that might want 2799 // Network requests should be deferred until any extensions that might want
2840 // to observe or modify them are loaded. 2800 // to observe or modify them are loaded.
2841 return HasAPIPermission(ExtensionAPIPermission::kWebNavigation) || 2801 return HasAPIPermission(ExtensionAPIPermission::kWebNavigation) ||
2842 HasAPIPermission(ExtensionAPIPermission::kWebRequest); 2802 HasAPIPermission(ExtensionAPIPermission::kWebRequest);
2843 } 2803 }
2844 2804
2845 bool Extension::IsDisallowedExperimentalPermission( 2805 bool Extension::CanSpecifyAPIPermission(
2846 ExtensionAPIPermission::ID permission) const { 2806 const ExtensionAPIPermission* permission,
2847 return permission == ExtensionAPIPermission::kExperimental && 2807 std::string* error) const {
2848 !CommandLine::ForCurrentProcess()->HasSwitch( 2808 if (permission->is_component_only()) {
2849 switches::kEnableExperimentalExtensionApis); 2809 if (!CanSpecifyComponentOnlyPermission())
2810 return false;
2811 }
2812
2813 if (permission->id() == ExtensionAPIPermission::kExperimental) {
2814 if (!CanSpecifyExperimentalPermission()) {
2815 *error = errors::kExperimentalFlagRequired;
2816 return false;
2817 }
2818 }
2819
2820 if (is_hosted_app()) {
2821 if (!CanSpecifyPermissionForHostedApp(permission))
2822 return false;
2823 }
2824
2825 return true;
2826 }
2827
2828 bool Extension::CanSpecifyComponentOnlyPermission() const {
2829 // Only COMPONENT extensions can use private APIs.
2830 // TODO(asargent) - We want a more general purpose mechanism for this,
2831 // and better error messages. (http://crbug.com/54013)
2832 if (location_ == Extension::COMPONENT)
2833 return true;
2834
2835 #ifndef NDEBUG
2836 if (CommandLine::ForCurrentProcess()->HasSwitch(
2837 switches::kExposePrivateExtensionApi)) {
2838 return true;
2839 }
2840 #endif
2841
2842 return false;
2843 }
2844
2845 bool Extension::CanSpecifyExperimentalPermission() const {
2846 if (location_ == Extension::COMPONENT)
2847 return true;
2848
2849 if (CommandLine::ForCurrentProcess()->HasSwitch(
2850 switches::kEnableExperimentalExtensionApis)) {
2851 return true;
2852 }
2853
2854 // We rely on the webstore to check access to experimental. This way we can
2855 // whitelist extensions to have access to experimental in just the store, and
2856 // not have to push a new version of the client.
2857 if (from_webstore())
2858 return true;
2859
2860 return false;
2861 }
2862
2863 bool Extension::CanSpecifyPermissionForHostedApp(
2864 const ExtensionAPIPermission* permission) const {
2865 if (location_ == Extension::COMPONENT)
2866 return true;
2867
2868 if (permission->is_hosted_app())
2869 return true;
2870
2871 return false;
2850 } 2872 }
2851 2873
2852 bool Extension::CanExecuteScriptEverywhere() const { 2874 bool Extension::CanExecuteScriptEverywhere() const {
2853 if (location() == Extension::COMPONENT 2875 if (location() == Extension::COMPONENT
2854 #ifndef NDEBUG 2876 #ifndef NDEBUG
2855 || CommandLine::ForCurrentProcess()->HasSwitch( 2877 || CommandLine::ForCurrentProcess()->HasSwitch(
2856 switches::kExposePrivateExtensionApi) 2878 switches::kExposePrivateExtensionApi)
2857 #endif 2879 #endif
2858 ) 2880 )
2859 return true; 2881 return true;
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
2989 already_disabled(false), 3011 already_disabled(false),
2990 extension(extension) {} 3012 extension(extension) {}
2991 3013
2992 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3014 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
2993 const Extension* extension, 3015 const Extension* extension,
2994 const ExtensionPermissionSet* permissions, 3016 const ExtensionPermissionSet* permissions,
2995 Reason reason) 3017 Reason reason)
2996 : reason(reason), 3018 : reason(reason),
2997 extension(extension), 3019 extension(extension),
2998 permissions(permissions) {} 3020 permissions(permissions) {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698