| 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 bool granted_full_access, |
| 1083 // extensions that require less permissions than the current version, but then | 1083 const std::set<std::string>& granted_apis, |
| 1084 // we don't silently allow them to go back. In order to fix this, we would need | 1084 const ExtensionExtent& granted_extent, |
| 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 the extension had native code access, we don't need to go any further. |
| 1089 // further. Things can't get any worse. | 1087 // Things can't get any worse. |
| 1090 if (old_extension->plugins().size() > 0) | 1088 if (granted_full_access) |
| 1091 return false; | 1089 return false; |
| 1092 | 1090 |
| 1093 // Otherwise, if the new extension has a plugin, it's a privilege increase. | 1091 // Otherwise, if the new extension has a plugin, it's a privilege increase. |
| 1094 if (new_extension->plugins().size() > 0) | 1092 if (new_extension->plugins().size() > 0) |
| 1095 return true; | 1093 return true; |
| 1096 | 1094 |
| 1097 // If we are increasing the set of hosts we have access to (not | 1095 // If the extension hadn't been granted access to all hosts in the past, then |
| 1098 // counting scheme differences), it's a privilege increase. | 1096 // see if the extension requires more host permissions. |
| 1099 if (!old_extension->HasEffectiveAccessToAllHosts()) { | 1097 if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) { |
| 1100 if (new_extension->HasEffectiveAccessToAllHosts()) | 1098 if (new_extension->HasEffectiveAccessToAllHosts()) |
| 1101 return true; | 1099 return true; |
| 1102 | 1100 |
| 1103 // TODO(erikkay) This will trip when you add a new distinct hostname, | 1101 const ExtensionExtent new_extent = |
| 1104 // but we should unique based on RCD as well. crbug.com/57042 | 1102 new_extension->GetEffectiveHostPermissions(); |
| 1105 std::vector<std::string> old_hosts = old_extension->GetDistinctHosts(); | 1103 std::vector<std::string> new_hosts = |
| 1106 std::vector<std::string> new_hosts = new_extension->GetDistinctHosts(); | 1104 GetDistinctHosts(new_extent.patterns()); |
| 1105 std::vector<std::string> old_hosts = |
| 1106 GetDistinctHosts(granted_extent.patterns()); |
| 1107 |
| 1107 std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end()); | 1108 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()); | 1109 std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end()); |
| 1109 std::set<std::string> new_only; | 1110 std::set<std::string> new_hosts_only; |
| 1111 |
| 1110 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), | 1112 std::set_difference(new_hosts_set.begin(), new_hosts_set.end(), |
| 1111 old_hosts_set.begin(), old_hosts_set.end(), | 1113 old_hosts_set.begin(), old_hosts_set.end(), |
| 1112 std::inserter(new_only, new_only.end())); | 1114 std::inserter(new_hosts_only, new_hosts_only.end())); |
| 1113 if (new_only.size()) | 1115 |
| 1116 if (new_hosts_only.size()) |
| 1114 return true; | 1117 return true; |
| 1115 } | 1118 } |
| 1116 | 1119 |
| 1117 std::set<string16> old_messages = | 1120 std::set<std::string> new_apis = new_extension->api_permissions(); |
| 1118 old_extension->GetSimplePermissionMessages(); | 1121 std::set<std::string> new_apis_only; |
| 1119 std::set<string16> new_messages = | 1122 std::set_difference(new_apis.begin(), new_apis.end(), |
| 1120 new_extension->GetSimplePermissionMessages(); | 1123 granted_apis.begin(), granted_apis.end(), |
| 1121 std::set<string16> new_only; | 1124 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 | 1125 |
| 1126 // If there are any new permission messages, then it's an increase. | 1126 // Ignore API permissions that don't require user approval when deciding if |
| 1127 if (!new_only.empty()) | 1127 // an extension has increased its privileges. |
| 1128 size_t new_api_count = 0; |
| 1129 for (std::set<std::string>::iterator i = new_apis_only.begin(); |
| 1130 i != new_apis_only.end(); ++i) { |
| 1131 if (GetPermissionMessageId(*i)) |
| 1132 new_api_count++; |
| 1133 } |
| 1134 |
| 1135 if (new_api_count) |
| 1128 return true; | 1136 return true; |
| 1129 | 1137 |
| 1130 return false; | 1138 return false; |
| 1131 } | 1139 } |
| 1132 | 1140 |
| 1133 // static | 1141 // static |
| 1134 void Extension::DecodeIcon(const Extension* extension, | 1142 void Extension::DecodeIcon(const Extension* extension, |
| 1135 Icons icon_size, | 1143 Icons icon_size, |
| 1136 scoped_ptr<SkBitmap>* result) { | 1144 scoped_ptr<SkBitmap>* result) { |
| 1137 FilePath icon_path = extension->GetIconResource( | 1145 FilePath icon_path = extension->GetIconResource( |
| (...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 continue; | 1707 continue; |
| 1700 } | 1708 } |
| 1701 } else { | 1709 } else { |
| 1702 // Hosted apps only get access to a subset of the valid permissions. | 1710 // Hosted apps only get access to a subset of the valid permissions. |
| 1703 if (IsHostedAppPermission(permission_str)) { | 1711 if (IsHostedAppPermission(permission_str)) { |
| 1704 api_permissions_.insert(permission_str); | 1712 api_permissions_.insert(permission_str); |
| 1705 continue; | 1713 continue; |
| 1706 } | 1714 } |
| 1707 } | 1715 } |
| 1708 | 1716 |
| 1709 // Otherwise, it's a host pattern permission. | 1717 // Check if it's a host pattern permission. |
| 1710 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? | 1718 URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? |
| 1711 URLPattern::SCHEME_ALL : | 1719 URLPattern::SCHEME_ALL : |
| 1712 (UserScript::kValidUserScriptSchemes | | 1720 (UserScript::kValidUserScriptSchemes | |
| 1713 URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE); | 1721 URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE); |
| 1714 | 1722 |
| 1715 if (URLPattern::PARSE_SUCCESS != pattern.Parse(permission_str)) { | 1723 if (URLPattern::PARSE_SUCCESS == pattern.Parse(permission_str)) { |
| 1716 *error = ExtensionErrorUtils::FormatErrorMessage( | 1724 if (!CanSpecifyHostPermission(pattern)) { |
| 1717 errors::kInvalidPermission, base::IntToString(i)); | 1725 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 1718 return false; | 1726 errors::kInvalidPermissionScheme, base::IntToString(i)); |
| 1727 return false; |
| 1728 } |
| 1729 |
| 1730 // The path component is not used for host permissions, so we force it |
| 1731 // to match all paths. |
| 1732 pattern.set_path("/*"); |
| 1733 |
| 1734 host_permissions_.push_back(pattern); |
| 1719 } | 1735 } |
| 1720 | 1736 |
| 1721 if (!CanSpecifyHostPermission(pattern)) { | 1737 // If it's not a host permission, then it's probably an unknown API |
| 1722 *error = ExtensionErrorUtils::FormatErrorMessage( | 1738 // permission. Do not throw an error so extensions can retain |
| 1723 errors::kInvalidPermissionScheme, base::IntToString(i)); | 1739 // backwards compatability (http://crbug.com/42742). |
| 1724 return false; | 1740 // TODO(jstritar): We can improve error messages by adding better |
| 1725 } | 1741 // validation of API permissions here. |
| 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 } | 1742 } |
| 1733 } | 1743 } |
| 1734 | 1744 |
| 1735 if (source.HasKey(keys::kDefaultLocale)) { | 1745 if (source.HasKey(keys::kDefaultLocale)) { |
| 1736 if (!source.GetString(keys::kDefaultLocale, | 1746 if (!source.GetString(keys::kDefaultLocale, |
| 1737 &default_locale_) || | 1747 &default_locale_) || |
| 1738 default_locale_.empty()) { | 1748 default_locale_.empty()) { |
| 1739 *error = errors::kInvalidDefaultLocale; | 1749 *error = errors::kInvalidDefaultLocale; |
| 1740 return false; | 1750 return false; |
| 1741 } | 1751 } |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2115 } | 2125 } |
| 2116 | 2126 |
| 2117 if (error) { | 2127 if (error) { |
| 2118 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, | 2128 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, |
| 2119 page_url.spec()); | 2129 page_url.spec()); |
| 2120 } | 2130 } |
| 2121 | 2131 |
| 2122 return false; | 2132 return false; |
| 2123 } | 2133 } |
| 2124 | 2134 |
| 2125 bool Extension::HasEffectiveAccessToAllHosts() const { | 2135 // static |
| 2136 bool Extension::HasEffectiveAccessToAllHosts( |
| 2137 const ExtensionExtent& effective_host_permissions, |
| 2138 const std::set<std::string>& api_permissions) { |
| 2126 // Some APIs effectively grant access to every site. New ones should be | 2139 // Some APIs effectively grant access to every site. New ones should be |
| 2127 // added here. (I'm looking at you, network API) | 2140 // added here. (I'm looking at you, network API) |
| 2128 if (HasApiPermission(kProxyPermission)) | 2141 if (HasApiPermission(api_permissions, kProxyPermission)) |
| 2129 return true; | 2142 return true; |
| 2130 | 2143 |
| 2131 for (URLPatternList::const_iterator host = host_permissions().begin(); | 2144 const URLPatternList patterns = effective_host_permissions.patterns(); |
| 2132 host != host_permissions().end(); ++host) { | 2145 for (URLPatternList::const_iterator host = patterns.begin(); |
| 2146 host != patterns.end(); ++host) { |
| 2133 if (host->match_subdomains() && host->host().empty()) | 2147 if (host->match_subdomains() && host->host().empty()) |
| 2134 return true; | 2148 return true; |
| 2135 } | 2149 } |
| 2136 | 2150 |
| 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; | 2151 return false; |
| 2149 } | 2152 } |
| 2150 | 2153 |
| 2154 bool Extension::HasEffectiveAccessToAllHosts() const { |
| 2155 return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(), |
| 2156 api_permissions()); |
| 2157 } |
| 2158 |
| 2151 bool Extension::IsAPIPermission(const std::string& str) const { | 2159 bool Extension::IsAPIPermission(const std::string& str) const { |
| 2152 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { | 2160 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { |
| 2153 if (str == Extension::kPermissions[i].name) { | 2161 if (str == Extension::kPermissions[i].name) { |
| 2154 // Only allow the experimental API permission if the command line | 2162 // Only allow the experimental API permission if the command line |
| 2155 // flag is present, or if the extension is a component of Chrome. | 2163 // flag is present, or if the extension is a component of Chrome. |
| 2156 if (str == Extension::kExperimentalPermission) { | 2164 if (str == Extension::kExperimentalPermission) { |
| 2157 if (CommandLine::ForCurrentProcess()->HasSwitch( | 2165 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 2158 switches::kEnableExperimentalExtensionApis)) { | 2166 switches::kEnableExperimentalExtensionApis)) { |
| 2159 return true; | 2167 return true; |
| 2160 } else if (location() == Extension::COMPONENT) { | 2168 } else if (location() == Extension::COMPONENT) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2209 UninstalledExtensionInfo::UninstalledExtensionInfo( | 2217 UninstalledExtensionInfo::UninstalledExtensionInfo( |
| 2210 const Extension& extension) | 2218 const Extension& extension) |
| 2211 : extension_id(extension.id()), | 2219 : extension_id(extension.id()), |
| 2212 extension_api_permissions(extension.api_permissions()), | 2220 extension_api_permissions(extension.api_permissions()), |
| 2213 is_theme(extension.is_theme()), | 2221 is_theme(extension.is_theme()), |
| 2214 is_app(extension.is_app()), | 2222 is_app(extension.is_app()), |
| 2215 converted_from_user_script(extension.converted_from_user_script()), | 2223 converted_from_user_script(extension.converted_from_user_script()), |
| 2216 update_url(extension.update_url()) {} | 2224 update_url(extension.update_url()) {} |
| 2217 | 2225 |
| 2218 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} | 2226 UninstalledExtensionInfo::~UninstalledExtensionInfo() {} |
| OLD | NEW |