Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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() {} |
| OLD | NEW |