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

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

Issue 4687005: Track permissions granted to extensions in prefs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: incorporate feedback Created 10 years, 1 month 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "app/l10n_util.h" 9 #include "app/l10n_util.h"
10 #include "base/base64.h" 10 #include "base/base64.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 static void ConvertHexadecimalToIDAlphabet(std::string* id) { 64 static void ConvertHexadecimalToIDAlphabet(std::string* id) {
65 for (size_t i = 0; i < id->size(); ++i) { 65 for (size_t i = 0; i < id->size(); ++i) {
66 int val; 66 int val;
67 if (base::HexStringToInt(id->begin() + i, id->begin() + i + 1, &val)) 67 if (base::HexStringToInt(id->begin() + i, id->begin() + i + 1, &val))
68 (*id)[i] = val + 'a'; 68 (*id)[i] = val + 'a';
69 else 69 else
70 (*id)[i] = 'a'; 70 (*id)[i] = 'a';
71 } 71 }
72 } 72 }
73 73
74 const int kValidWebExtentSchemes =
75 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
76
77 // These keys are allowed by all crx files (apps, extensions, themes, etc). 74 // These keys are allowed by all crx files (apps, extensions, themes, etc).
78 static const char* kBaseCrxKeys[] = { 75 static const char* kBaseCrxKeys[] = {
79 keys::kCurrentLocale, 76 keys::kCurrentLocale,
80 keys::kDefaultLocale, 77 keys::kDefaultLocale,
81 keys::kDescription, 78 keys::kDescription,
82 keys::kIcons, 79 keys::kIcons,
83 keys::kName, 80 keys::kName,
84 keys::kPublicKey, 81 keys::kPublicKey,
85 keys::kSignature, 82 keys::kSignature,
86 keys::kVersion, 83 keys::kVersion,
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 Extension::kNotificationPermission, 240 Extension::kNotificationPermission,
244 Extension::kUnlimitedStoragePermission, 241 Extension::kUnlimitedStoragePermission,
245 Extension::kWebstorePrivatePermission, 242 Extension::kWebstorePrivatePermission,
246 }; 243 };
247 const size_t Extension::kNumHostedAppPermissions = 244 const size_t Extension::kNumHostedAppPermissions =
248 arraysize(Extension::kHostedAppPermissionNames); 245 arraysize(Extension::kHostedAppPermissionNames);
249 246
250 // We purposefully don't put this into kPermissionNames. 247 // We purposefully don't put this into kPermissionNames.
251 const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage"; 248 const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage";
252 249
250 const int Extension::kValidWebExtentSchemes =
251 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
252
253 // 253 //
254 // Extension 254 // Extension
255 // 255 //
256 256
257 // static 257 // static
258 scoped_refptr<Extension> Extension::Create(const FilePath& path, 258 scoped_refptr<Extension> Extension::Create(const FilePath& path,
259 Location location, 259 Location location,
260 const DictionaryValue& value, 260 const DictionaryValue& value,
261 bool require_key, 261 bool require_key,
262 std::string* error) { 262 std::string* error) {
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 output->append(" "); 1072 output->append(" ");
1073 output->append(is_public ? kPublic : kPrivate); 1073 output->append(is_public ? kPublic : kPrivate);
1074 output->append(" "); 1074 output->append(" ");
1075 output->append(kKeyInfoEndMarker); 1075 output->append(kKeyInfoEndMarker);
1076 output->append("\n"); 1076 output->append("\n");
1077 1077
1078 return true; 1078 return true;
1079 } 1079 }
1080 1080
1081 // static 1081 // static
1082 // TODO(aa): A problem with this code is that we silently allow upgrades to 1082 bool Extension::IsPrivilegeIncrease(const std::set<std::string>& granted_apis,
1083 // extensions that require less permissions than the current version, but then 1083 const ExtensionExtent& granted_extent,
1084 // we don't silently allow them to go back. In order to fix this, we would need 1084 const Extension* old_extension,
1085 // to remember the max set of permissions we ever granted a single extension.
1086 bool Extension::IsPrivilegeIncrease(const Extension* old_extension,
1087 const Extension* new_extension) { 1085 const Extension* new_extension) {
1088 // If the old extension had native code access, we don't need to go any 1086 if (old_extension) {
1089 // further. Things can't get any worse. 1087 // If the old extension had native code access, we don't need to go any
1090 if (old_extension->plugins().size() > 0) 1088 // further. Things can't get any worse.
1091 return false; 1089 if (old_extension->plugins().size() > 0)
Aaron Boodman 2010/11/23 00:06:38 I think this method should not be passed the old_e
1090 return false;
1092 1091
1093 // Otherwise, if the new extension has a plugin, it's a privilege increase. 1092 // Otherwise, if the new extension has a plugin, it's a privilege increase.
1094 if (new_extension->plugins().size() > 0) 1093 if (new_extension->plugins().size() > 0)
1095 return true; 1094 return true;
1095 }
1096 1096
1097 // If we are increasing the set of hosts we have access to (not 1097 // If the extension hadn't been granted access to all hosts in the past, then
1098 // counting scheme differences), it's a privilege increase. 1098 // see if the extension requires more host permissions.
1099 if (!old_extension->HasEffectiveAccessToAllHosts()) { 1099 if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) {
1100 if (new_extension->HasEffectiveAccessToAllHosts()) 1100 if (new_extension->HasEffectiveAccessToAllHosts())
1101 return true; 1101 return true;
1102 1102
1103 // TODO(erikkay) This will trip when you add a new distinct hostname, 1103 const ExtensionExtent new_extent =
1104 // but we should unique based on RCD as well. crbug.com/57042 1104 new_extension->GetEffectiveHostPermissions();
1105 std::vector<std::string> old_hosts = old_extension->GetDistinctHosts(); 1105 std::vector<std::string> new_hosts =
1106 std::vector<std::string> new_hosts = new_extension->GetDistinctHosts(); 1106 GetDistinctHosts(new_extent.patterns());
1107 std::vector<std::string> old_hosts =
1108 GetDistinctHosts(granted_extent.patterns());
1109
1107 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end()); 1110 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end());
1108 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end()); 1111 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end());
1109 std::set<std::string> new_only; 1112 std::set<std::string> new_hosts_only;
1113
1110 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), 1114 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
1111 old_hosts_set.begin(), old_hosts_set.end(), 1115 old_hosts_set.begin(), old_hosts_set.end(),
1112 std::inserter(new_only, new_only.end())); 1116 std::inserter(new_hosts_only, new_hosts_only.end()));
1113 if (new_only.size()) 1117
1118 if (new_hosts_only.size())
1114 return true; 1119 return true;
1115 } 1120 }
1116 1121
1117 std::set<string16> old_messages = 1122 std::set<std::string> new_apis = new_extension->api_permissions();
1118 old_extension->GetSimplePermissionMessages(); 1123 std::set<std::string> new_apis_only;
1119 std::set<string16> new_messages = 1124 std::set_difference(new_apis.begin(), new_apis.end(),
1120 new_extension->GetSimplePermissionMessages(); 1125 granted_apis.begin(), granted_apis.end(),
1121 std::set<string16> new_only; 1126 std::inserter(new_apis_only, new_apis_only.end()));
1122 std::set_difference(new_messages.begin(), new_messages.end(),
1123 old_messages.begin(), old_messages.end(),
1124 std::inserter(new_only, new_only.end()));
1125 1127
1126 // If there are any new permission messages, then it's an increase. 1128 // Ignore API permissions that don't require user approval when deciding if
1127 if (!new_only.empty()) 1129 // an extension has increased its privileges.
1130 size_t new_api_count = 0;
1131 for (std::set<std::string>::iterator i = new_apis_only.begin();
1132 i != new_apis_only.end(); ++i) {
1133 if (GetPermissionMessageId(*i))
1134 new_api_count++;
1135 }
1136
1137 if (new_api_count)
1128 return true; 1138 return true;
1129 1139
1130 return false; 1140 return false;
1131 } 1141 }
1132 1142
1133 // static 1143 // static
1134 void Extension::DecodeIcon(const Extension* extension, 1144 void Extension::DecodeIcon(const Extension* extension,
1135 Icons icon_size, 1145 Icons icon_size,
1136 scoped_ptr<SkBitmap>* result) { 1146 scoped_ptr<SkBitmap>* result) {
1137 FilePath icon_path = extension->GetIconResource( 1147 FilePath icon_path = extension->GetIconResource(
(...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after
1699 continue; 1709 continue;
1700 } 1710 }
1701 } else { 1711 } else {
1702 // Hosted apps only get access to a subset of the valid permissions. 1712 // Hosted apps only get access to a subset of the valid permissions.
1703 if (IsHostedAppPermission(permission_str)) { 1713 if (IsHostedAppPermission(permission_str)) {
1704 api_permissions_.insert(permission_str); 1714 api_permissions_.insert(permission_str);
1705 continue; 1715 continue;
1706 } 1716 }
1707 } 1717 }
1708 1718
1709 // Otherwise, it's a host pattern permission. 1719 // Check if it's a host pattern permission.
1710 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? 1720 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
1711 URLPattern::SCHEME_ALL : 1721 URLPattern::SCHEME_ALL :
1712 (UserScript::kValidUserScriptSchemes | 1722 (UserScript::kValidUserScriptSchemes |
1713 URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE); 1723 URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE);
1714 1724
1715 if (URLPattern::PARSE_SUCCESS != pattern.Parse(permission_str)) { 1725 if (URLPattern::PARSE_SUCCESS == pattern.Parse(permission_str)) {
1716 *error = ExtensionErrorUtils::FormatErrorMessage( 1726 if (!CanSpecifyHostPermission(pattern)) {
1717 errors::kInvalidPermission, base::IntToString(i)); 1727 *error = ExtensionErrorUtils::FormatErrorMessage(
1718 return false; 1728 errors::kInvalidPermissionScheme, base::IntToString(i));
1729 return false;
1730 }
1731
1732 // The path component is not used for host permissions, so we force it
1733 // to match all paths.
1734 pattern.set_path("/*");
1735
1736 host_permissions_.push_back(pattern);
1719 } 1737 }
1720 1738
1721 if (!CanSpecifyHostPermission(pattern)) { 1739 // If it's not a host permission, then it's probably an unknown API
1722 *error = ExtensionErrorUtils::FormatErrorMessage( 1740 // permission. Do not throw an error so extensions can retain
1723 errors::kInvalidPermissionScheme, base::IntToString(i)); 1741 // backwards compatability (http://crbug.com/42742).
1724 return false; 1742 // TODO(jstritar): We could add better validation of API permissions here
1725 } 1743 // if we'd like to improve error messages.
1726
1727 // The path component is not used for host permissions, so we force it to
1728 // match all paths.
1729 pattern.set_path("/*");
1730
1731 host_permissions_.push_back(pattern);
1732 } 1744 }
1733 } 1745 }
1734 1746
1735 if (source.HasKey(keys::kDefaultLocale)) { 1747 if (source.HasKey(keys::kDefaultLocale)) {
1736 if (!source.GetString(keys::kDefaultLocale, 1748 if (!source.GetString(keys::kDefaultLocale,
1737 &default_locale_) || 1749 &default_locale_) ||
1738 default_locale_.empty()) { 1750 default_locale_.empty()) {
1739 *error = errors::kInvalidDefaultLocale; 1751 *error = errors::kInvalidDefaultLocale;
1740 return false; 1752 return false;
1741 } 1753 }
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after
2115 } 2127 }
2116 2128
2117 if (error) { 2129 if (error) {
2118 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, 2130 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
2119 page_url.spec()); 2131 page_url.spec());
2120 } 2132 }
2121 2133
2122 return false; 2134 return false;
2123 } 2135 }
2124 2136
2125 bool Extension::HasEffectiveAccessToAllHosts() const { 2137 // static
2138 bool Extension::HasEffectiveAccessToAllHosts(
2139 const ExtensionExtent& effective_host_permissions,
2140 const std::set<std::string>& api_permissions) {
2126 // Some APIs effectively grant access to every site. New ones should be 2141 // Some APIs effectively grant access to every site. New ones should be
2127 // added here. (I'm looking at you, network API) 2142 // added here. (I'm looking at you, network API)
2128 if (HasApiPermission(kProxyPermission)) 2143 if (HasApiPermission(api_permissions, kProxyPermission))
2129 return true; 2144 return true;
2130 2145
2131 for (URLPatternList::const_iterator host = host_permissions().begin(); 2146 const URLPatternList patterns = effective_host_permissions.patterns();
2132 host != host_permissions().end(); ++host) { 2147 for (URLPatternList::const_iterator host = patterns.begin();
2148 host != patterns.end(); ++host) {
2133 if (host->match_subdomains() && host->host().empty()) 2149 if (host->match_subdomains() && host->host().empty())
2134 return true; 2150 return true;
2135 } 2151 }
2136 2152
2137 for (UserScriptList::const_iterator content_script =
2138 content_scripts().begin();
2139 content_script != content_scripts().end(); ++content_script) {
2140 UserScript::PatternList::const_iterator pattern =
2141 content_script->url_patterns().begin();
2142 for (; pattern != content_script->url_patterns().end(); ++pattern) {
2143 if (pattern->match_subdomains() && pattern->host().empty())
2144 return true;
2145 }
2146 }
2147
2148 return false; 2153 return false;
2149 } 2154 }
2150 2155
2156 bool Extension::HasEffectiveAccessToAllHosts() const {
2157 return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(),
2158 api_permissions());
2159 }
2160
2151 bool Extension::IsAPIPermission(const std::string& str) const { 2161 bool Extension::IsAPIPermission(const std::string& str) const {
2152 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { 2162 for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
2153 if (str == Extension::kPermissions[i].name) { 2163 if (str == Extension::kPermissions[i].name) {
2154 // Only allow the experimental API permission if the command line 2164 // Only allow the experimental API permission if the command line
2155 // flag is present, or if the extension is a component of Chrome. 2165 // flag is present, or if the extension is a component of Chrome.
2156 if (str == Extension::kExperimentalPermission) { 2166 if (str == Extension::kExperimentalPermission) {
2157 if (CommandLine::ForCurrentProcess()->HasSwitch( 2167 if (CommandLine::ForCurrentProcess()->HasSwitch(
2158 switches::kEnableExperimentalExtensionApis)) { 2168 switches::kEnableExperimentalExtensionApis)) {
2159 return true; 2169 return true;
2160 } else if (location() == Extension::COMPONENT) { 2170 } else if (location() == Extension::COMPONENT) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
2209 UninstalledExtensionInfo::UninstalledExtensionInfo( 2219 UninstalledExtensionInfo::UninstalledExtensionInfo(
2210 const Extension& extension) 2220 const Extension& extension)
2211 : extension_id(extension.id()), 2221 : extension_id(extension.id()),
2212 extension_api_permissions(extension.api_permissions()), 2222 extension_api_permissions(extension.api_permissions()),
2213 is_theme(extension.is_theme()), 2223 is_theme(extension.is_theme()),
2214 is_app(extension.is_app()), 2224 is_app(extension.is_app()),
2215 converted_from_user_script(extension.converted_from_user_script()), 2225 converted_from_user_script(extension.converted_from_user_script()),
2216 update_url(extension.update_url()) {} 2226 update_url(extension.update_url()) {}
2217 2227
2218 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} 2228 UninstalledExtensionInfo::~UninstalledExtensionInfo() {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698