| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "base/json/json_file_value_serializer.h" | 6 #include "base/json/json_file_value_serializer.h" |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "chrome/common/chrome_paths.h" | 9 #include "chrome/common/chrome_paths.h" |
| 10 #include "chrome/common/chrome_switches.h" | 10 #include "chrome/common/chrome_switches.h" |
| 11 #include "chrome/common/extensions/extension_test_util.h" | 11 #include "chrome/common/extensions/extension_test_util.h" |
| 12 #include "chrome/common/extensions/features/feature_channel.h" | 12 #include "chrome/common/extensions/features/feature_channel.h" |
| 13 #include "chrome/common/extensions/permissions/chrome_permission_message_provide
r.h" | 13 #include "chrome/common/extensions/permissions/chrome_permission_message_provide
r.h" |
| 14 #include "chrome/grit/generated_resources.h" | 14 #include "chrome/grit/generated_resources.h" |
| 15 #include "extensions/common/error_utils.h" | 15 #include "extensions/common/error_utils.h" |
| 16 #include "extensions/common/extension.h" | 16 #include "extensions/common/extension.h" |
| 17 #include "extensions/common/extension_builder.h" | 17 #include "extensions/common/extension_builder.h" |
| 18 #include "extensions/common/permissions/permission_message_provider.h" | 18 #include "extensions/common/permissions/permission_message_provider.h" |
| 19 #include "extensions/common/permissions/permission_message_test_util.h" |
| 19 #include "extensions/common/permissions/permission_message_util.h" | 20 #include "extensions/common/permissions/permission_message_util.h" |
| 20 #include "extensions/common/permissions/permission_set.h" | 21 #include "extensions/common/permissions/permission_set.h" |
| 21 #include "extensions/common/permissions/permissions_data.h" | 22 #include "extensions/common/permissions/permissions_data.h" |
| 22 #include "extensions/common/permissions/permissions_info.h" | 23 #include "extensions/common/permissions/permissions_info.h" |
| 23 #include "extensions/common/permissions/socket_permission.h" | 24 #include "extensions/common/permissions/socket_permission.h" |
| 24 #include "extensions/common/value_builder.h" | 25 #include "extensions/common/value_builder.h" |
| 25 #include "extensions/strings/grit/extensions_strings.h" | 26 #include "extensions/strings/grit/extensions_strings.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 27 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
| 28 | 29 |
| (...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 EXPECT_FALSE(provider->IsPrivilegeIncrease(directory_permissions.get(), | 1068 EXPECT_FALSE(provider->IsPrivilegeIncrease(directory_permissions.get(), |
| 1068 write_permissions.get(), | 1069 write_permissions.get(), |
| 1069 Manifest::TYPE_PLATFORM_APP)); | 1070 Manifest::TYPE_PLATFORM_APP)); |
| 1070 EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions.get(), | 1071 EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions.get(), |
| 1071 write_directory_permissions.get(), | 1072 write_directory_permissions.get(), |
| 1072 Manifest::TYPE_PLATFORM_APP)); | 1073 Manifest::TYPE_PLATFORM_APP)); |
| 1073 } | 1074 } |
| 1074 | 1075 |
| 1075 TEST(PermissionsTest, GetWarningMessages_ManyHosts) { | 1076 TEST(PermissionsTest, GetWarningMessages_ManyHosts) { |
| 1076 scoped_refptr<Extension> extension; | 1077 scoped_refptr<Extension> extension; |
| 1077 | |
| 1078 extension = LoadManifest("permissions", "many-hosts.json"); | 1078 extension = LoadManifest("permissions", "many-hosts.json"); |
| 1079 std::vector<base::string16> warnings = | 1079 EXPECT_TRUE(VerifyOnePermissionMessage( |
| 1080 extension->permissions_data()->GetPermissionMessageStrings(); | 1080 extension->permissions_data(), |
| 1081 ASSERT_EQ(1u, warnings.size()); | 1081 "Read and change your data on encrypted.google.com and www.google.com")); |
| 1082 EXPECT_EQ( | |
| 1083 "Read and change your data on encrypted.google.com and " | |
| 1084 "www.google.com", | |
| 1085 base::UTF16ToUTF8(warnings[0])); | |
| 1086 } | 1082 } |
| 1087 | 1083 |
| 1088 TEST(PermissionsTest, GetWarningMessages_Plugins) { | 1084 TEST(PermissionsTest, GetWarningMessages_Plugins) { |
| 1089 scoped_refptr<Extension> extension; | 1085 scoped_refptr<Extension> extension; |
| 1090 scoped_refptr<PermissionSet> permissions; | |
| 1091 | |
| 1092 extension = LoadManifest("permissions", "plugins.json"); | 1086 extension = LoadManifest("permissions", "plugins.json"); |
| 1093 std::vector<base::string16> warnings = | 1087 // We don't parse the plugins key on Chrome OS, so it should not ask for any |
| 1094 extension->permissions_data()->GetPermissionMessageStrings(); | |
| 1095 // We don't parse the plugins key on Chrome OS, so it should not ask for any | |
| 1096 // permissions. | 1088 // permissions. |
| 1097 #if defined(OS_CHROMEOS) | 1089 #if defined(OS_CHROMEOS) |
| 1098 ASSERT_EQ(0u, warnings.size()); | 1090 EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data())); |
| 1099 #else | 1091 #else |
| 1100 ASSERT_EQ(1u, warnings.size()); | 1092 EXPECT_TRUE(VerifyOnePermissionMessage( |
| 1101 EXPECT_EQ( | 1093 extension->permissions_data(), |
| 1102 "Read and change all your data on your computer and the websites " | 1094 "Read and change all your data on your computer and the websites you " |
| 1103 "you visit", | 1095 "visit")); |
| 1104 base::UTF16ToUTF8(warnings[0])); | |
| 1105 #endif | 1096 #endif |
| 1106 } | 1097 } |
| 1107 | 1098 |
| 1108 TEST(PermissionsTest, GetWarningMessages_AudioVideo) { | 1099 TEST(PermissionsTest, GetWarningMessages_AudioVideo) { |
| 1109 // Both audio and video present. | 1100 // Both audio and video present. |
| 1110 scoped_refptr<Extension> extension = | 1101 scoped_refptr<Extension> extension = |
| 1111 LoadManifest("permissions", "audio-video.json"); | 1102 LoadManifest("permissions", "audio-video.json"); |
| 1112 const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); | 1103 const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); |
| 1113 PermissionSet* set = const_cast<PermissionSet*>( | 1104 PermissionSet* set = const_cast<PermissionSet*>( |
| 1114 extension->permissions_data()->active_permissions().get()); | 1105 extension->permissions_data()->active_permissions().get()); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 warnings, "Read and change all your data on the websites you visit")); | 1203 warnings, "Read and change all your data on the websites you visit")); |
| 1213 } | 1204 } |
| 1214 | 1205 |
| 1215 TEST(PermissionsTest, GetWarningMessages_Serial) { | 1206 TEST(PermissionsTest, GetWarningMessages_Serial) { |
| 1216 scoped_refptr<Extension> extension = | 1207 scoped_refptr<Extension> extension = |
| 1217 LoadManifest("permissions", "serial.json"); | 1208 LoadManifest("permissions", "serial.json"); |
| 1218 | 1209 |
| 1219 EXPECT_TRUE(extension->is_platform_app()); | 1210 EXPECT_TRUE(extension->is_platform_app()); |
| 1220 EXPECT_TRUE( | 1211 EXPECT_TRUE( |
| 1221 extension->permissions_data()->HasAPIPermission(APIPermission::kSerial)); | 1212 extension->permissions_data()->HasAPIPermission(APIPermission::kSerial)); |
| 1222 std::vector<base::string16> warnings = | 1213 EXPECT_TRUE(VerifyOnePermissionMessage(extension->permissions_data(), |
| 1223 extension->permissions_data()->GetPermissionMessageStrings(); | 1214 "Access your serial devices")); |
| 1224 EXPECT_TRUE(Contains(warnings, "Access your serial devices")); | |
| 1225 ASSERT_EQ(1u, warnings.size()); | |
| 1226 } | 1215 } |
| 1227 | 1216 |
| 1228 TEST(PermissionsTest, GetWarningMessages_Socket_AnyHost) { | 1217 TEST(PermissionsTest, GetWarningMessages_Socket_AnyHost) { |
| 1229 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); | 1218 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); |
| 1230 | 1219 |
| 1231 scoped_refptr<Extension> extension = | 1220 scoped_refptr<Extension> extension = |
| 1232 LoadManifest("permissions", "socket_any_host.json"); | 1221 LoadManifest("permissions", "socket_any_host.json"); |
| 1233 EXPECT_TRUE(extension->is_platform_app()); | 1222 EXPECT_TRUE(extension->is_platform_app()); |
| 1234 EXPECT_TRUE( | 1223 EXPECT_TRUE( |
| 1235 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); | 1224 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); |
| 1236 std::vector<base::string16> warnings = | 1225 EXPECT_TRUE(VerifyOnePermissionMessage( |
| 1237 extension->permissions_data()->GetPermissionMessageStrings(); | 1226 extension->permissions_data(), |
| 1238 EXPECT_EQ(1u, warnings.size()); | 1227 "Exchange data with any computer on the local network or internet")); |
| 1239 EXPECT_TRUE(Contains(warnings, "Exchange data with any computer " | |
| 1240 "on the local network or internet")); | |
| 1241 } | 1228 } |
| 1242 | 1229 |
| 1243 TEST(PermissionsTest, GetWarningMessages_Socket_OneDomainTwoHostnames) { | 1230 TEST(PermissionsTest, GetWarningMessages_Socket_OneDomainTwoHostnames) { |
| 1244 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); | 1231 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); |
| 1245 | 1232 |
| 1246 scoped_refptr<Extension> extension = | 1233 scoped_refptr<Extension> extension = |
| 1247 LoadManifest("permissions", "socket_one_domain_two_hostnames.json"); | 1234 LoadManifest("permissions", "socket_one_domain_two_hostnames.json"); |
| 1248 EXPECT_TRUE(extension->is_platform_app()); | 1235 EXPECT_TRUE(extension->is_platform_app()); |
| 1249 EXPECT_TRUE( | 1236 EXPECT_TRUE( |
| 1250 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); | 1237 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); |
| 1251 std::vector<base::string16> warnings = | |
| 1252 extension->permissions_data()->GetPermissionMessageStrings(); | |
| 1253 | 1238 |
| 1254 // Verify the warnings, including support for unicode characters, the fact | 1239 // Verify the warnings, including support for unicode characters, the fact |
| 1255 // that domain host warnings come before specific host warnings, and the fact | 1240 // that domain host warnings come before specific host warnings, and the fact |
| 1256 // that domains and hostnames are in alphabetical order regardless of the | 1241 // that domains and hostnames are in alphabetical order regardless of the |
| 1257 // order in the manifest file. | 1242 // order in the manifest file. |
| 1258 EXPECT_EQ(2u, warnings.size()); | 1243 EXPECT_TRUE(VerifyTwoPermissionMessages( |
| 1259 if (warnings.size() > 0) | 1244 extension->permissions_data(), |
| 1260 EXPECT_EQ(warnings[0], | 1245 "Exchange data with any computer in the domain example.org", |
| 1261 base::UTF8ToUTF16("Exchange data with any computer in the domain " | 1246 "Exchange data with the computers named: " |
| 1262 "example.org")); | 1247 "b\xC3\xA5r.example.com foo.example.com", |
| 1263 if (warnings.size() > 1) | 1248 // "\xC3\xA5" = UTF-8 for lowercase A with ring above |
| 1264 EXPECT_EQ(warnings[1], | 1249 true)); |
| 1265 base::UTF8ToUTF16("Exchange data with the computers named: " | |
| 1266 "b\xC3\xA5r.example.com foo.example.com")); | |
| 1267 // "\xC3\xA5" = UTF-8 for lowercase A with ring above | |
| 1268 } | 1250 } |
| 1269 | 1251 |
| 1270 TEST(PermissionsTest, GetWarningMessages_Socket_TwoDomainsOneHostname) { | 1252 TEST(PermissionsTest, GetWarningMessages_Socket_TwoDomainsOneHostname) { |
| 1271 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); | 1253 ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV); |
| 1272 | 1254 |
| 1273 scoped_refptr<Extension> extension = | 1255 scoped_refptr<Extension> extension = |
| 1274 LoadManifest("permissions", "socket_two_domains_one_hostname.json"); | 1256 LoadManifest("permissions", "socket_two_domains_one_hostname.json"); |
| 1275 EXPECT_TRUE(extension->is_platform_app()); | 1257 EXPECT_TRUE(extension->is_platform_app()); |
| 1276 EXPECT_TRUE( | 1258 EXPECT_TRUE( |
| 1277 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); | 1259 extension->permissions_data()->HasAPIPermission(APIPermission::kSocket)); |
| 1278 std::vector<base::string16> warnings = | |
| 1279 extension->permissions_data()->GetPermissionMessageStrings(); | |
| 1280 | 1260 |
| 1281 // Verify the warnings, including the fact that domain host warnings come | 1261 // Verify the warnings, including the fact that domain host warnings come |
| 1282 // before specific host warnings and the fact that domains and hostnames are | 1262 // before specific host warnings and the fact that domains and hostnames are |
| 1283 // in alphabetical order regardless of the order in the manifest file. | 1263 // in alphabetical order regardless of the order in the manifest file. |
| 1284 EXPECT_EQ(2u, warnings.size()); | 1264 EXPECT_TRUE(VerifyTwoPermissionMessages( |
| 1285 if (warnings.size() > 0) | 1265 extension->permissions_data(), |
| 1286 EXPECT_EQ(warnings[0], | 1266 "Exchange data with any computer in the domains: " |
| 1287 base::UTF8ToUTF16("Exchange data with any computer in the " | 1267 "example.com foo.example.org", |
| 1288 "domains: example.com foo.example.org")); | 1268 "Exchange data with the computer named bar.example.org", |
| 1289 if (warnings.size() > 1) | 1269 true)); |
| 1290 EXPECT_EQ(warnings[1], | |
| 1291 base::UTF8ToUTF16("Exchange data with the computer named " | |
| 1292 "bar.example.org")); | |
| 1293 } | 1270 } |
| 1294 | 1271 |
| 1295 TEST(PermissionsTest, GetWarningMessages_PlatformApppHosts) { | 1272 // Since platform apps always use isolated storage, they can't (silently) |
| 1273 // access user data on other domains, so there's no need to prompt about host |
| 1274 // permissions. See crbug.com/255229. |
| 1275 TEST(PermissionsTest, GetWarningMessages_PlatformAppHosts) { |
| 1296 scoped_refptr<Extension> extension; | 1276 scoped_refptr<Extension> extension; |
| 1297 | 1277 |
| 1298 extension = LoadManifest("permissions", "platform_app_hosts.json"); | 1278 extension = LoadManifest("permissions", "platform_app_hosts.json"); |
| 1299 EXPECT_TRUE(extension->is_platform_app()); | 1279 EXPECT_TRUE(extension->is_platform_app()); |
| 1300 std::vector<base::string16> warnings = | 1280 EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data())); |
| 1301 extension->permissions_data()->GetPermissionMessageStrings(); | |
| 1302 ASSERT_EQ(0u, warnings.size()); | |
| 1303 | 1281 |
| 1304 extension = LoadManifest("permissions", "platform_app_all_urls.json"); | 1282 extension = LoadManifest("permissions", "platform_app_all_urls.json"); |
| 1305 EXPECT_TRUE(extension->is_platform_app()); | 1283 EXPECT_TRUE(extension->is_platform_app()); |
| 1306 warnings = extension->permissions_data()->GetPermissionMessageStrings(); | 1284 EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data())); |
| 1307 ASSERT_EQ(0u, warnings.size()); | |
| 1308 } | 1285 } |
| 1309 | 1286 |
| 1310 bool ShowsAllHostsWarning(const std::string& pattern) { | 1287 testing::AssertionResult ShowsAllHostsWarning(const std::string& pattern) { |
| 1311 scoped_refptr<Extension> extension = | 1288 scoped_refptr<Extension> extension = |
| 1312 ExtensionBuilder() | 1289 ExtensionBuilder() |
| 1313 .SetManifest(DictionaryBuilder() | 1290 .SetManifest(DictionaryBuilder() |
| 1314 .Set("name", "TLDWildCardTest") | 1291 .Set("name", "TLDWildCardTest") |
| 1315 .Set("version", "0.1.0") | 1292 .Set("version", "0.1.0") |
| 1316 .Set("permissions", ListBuilder().Append(pattern)) | 1293 .Set("permissions", ListBuilder().Append(pattern)) |
| 1317 .Build()) | 1294 .Build()) |
| 1318 .Build(); | 1295 .Build(); |
| 1319 | 1296 |
| 1320 std::vector<base::string16> warnings = | 1297 return VerifyHasPermissionMessage( |
| 1321 extension->permissions_data()->GetPermissionMessageStrings(); | 1298 extension->permissions_data(), |
| 1322 | 1299 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)); |
| 1323 if (warnings.empty()) | |
| 1324 return false; | |
| 1325 | |
| 1326 if (warnings[0] != | |
| 1327 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)) { | |
| 1328 return false; | |
| 1329 } | |
| 1330 | |
| 1331 return true; | |
| 1332 } | 1300 } |
| 1333 | 1301 |
| 1334 TEST(PermissionsTest, GetWarningMessages_TLDWildcardTreatedAsAllHosts) { | 1302 TEST(PermissionsTest, GetWarningMessages_TLDWildcardTreatedAsAllHosts) { |
| 1335 EXPECT_TRUE(ShowsAllHostsWarning("http://*.com/*")); // most popular. | 1303 EXPECT_TRUE(ShowsAllHostsWarning("http://*.com/*")); // most popular. |
| 1336 EXPECT_TRUE(ShowsAllHostsWarning("http://*.org/*")); // sanity check. | 1304 EXPECT_TRUE(ShowsAllHostsWarning("http://*.org/*")); // sanity check. |
| 1337 EXPECT_TRUE(ShowsAllHostsWarning("http://*.co.uk/*")); // eTLD. | 1305 EXPECT_TRUE(ShowsAllHostsWarning("http://*.co.uk/*")); // eTLD. |
| 1338 EXPECT_TRUE(ShowsAllHostsWarning("http://*.de/*")); // foreign country tld. | 1306 EXPECT_TRUE(ShowsAllHostsWarning("http://*.de/*")); // foreign country tld. |
| 1339 | 1307 |
| 1340 // We should still show the normal permissions (i.e., "Can access your data on | 1308 // We should still show the normal permissions (i.e., "Can access your data on |
| 1341 // *.rdcronin.com") for things that are not TLDs. | 1309 // *.rdcronin.com") for things that are not TLDs. |
| (...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1744 } | 1712 } |
| 1745 | 1713 |
| 1746 TEST(PermissionsTest, SyncFileSystemPermission) { | 1714 TEST(PermissionsTest, SyncFileSystemPermission) { |
| 1747 scoped_refptr<Extension> extension = LoadManifest( | 1715 scoped_refptr<Extension> extension = LoadManifest( |
| 1748 "permissions", "sync_file_system.json"); | 1716 "permissions", "sync_file_system.json"); |
| 1749 APIPermissionSet apis; | 1717 APIPermissionSet apis; |
| 1750 apis.insert(APIPermission::kSyncFileSystem); | 1718 apis.insert(APIPermission::kSyncFileSystem); |
| 1751 EXPECT_TRUE(extension->is_platform_app()); | 1719 EXPECT_TRUE(extension->is_platform_app()); |
| 1752 EXPECT_TRUE(extension->permissions_data()->HasAPIPermission( | 1720 EXPECT_TRUE(extension->permissions_data()->HasAPIPermission( |
| 1753 APIPermission::kSyncFileSystem)); | 1721 APIPermission::kSyncFileSystem)); |
| 1754 std::vector<base::string16> warnings = | 1722 EXPECT_TRUE(VerifyOnePermissionMessage( |
| 1755 extension->permissions_data()->GetPermissionMessageStrings(); | 1723 extension->permissions_data(), |
| 1756 EXPECT_TRUE(Contains(warnings, "Store data in your Google Drive account")); | 1724 "Store data in your Google Drive account")); |
| 1757 ASSERT_EQ(1u, warnings.size()); | |
| 1758 } | 1725 } |
| 1759 | 1726 |
| 1760 // Make sure that we don't crash when we're trying to show the permissions | 1727 // Make sure that we don't crash when we're trying to show the permissions |
| 1761 // even though chrome://thumb (and everything that's not chrome://favicon with | 1728 // even though chrome://thumb (and everything that's not chrome://favicon with |
| 1762 // a chrome:// scheme) is not a valid permission. | 1729 // a chrome:// scheme) is not a valid permission. |
| 1763 // More details here: crbug/246314. | 1730 // More details here: crbug/246314. |
| 1764 TEST(PermissionsTest, ChromeURLs) { | 1731 TEST(PermissionsTest, ChromeURLs) { |
| 1765 URLPatternSet allowed_hosts; | 1732 URLPatternSet allowed_hosts; |
| 1766 allowed_hosts.AddPattern( | 1733 allowed_hosts.AddPattern( |
| 1767 URLPattern(URLPattern::SCHEME_ALL, "http://www.google.com/")); | 1734 URLPattern(URLPattern::SCHEME_ALL, "http://www.google.com/")); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1787 scoped_refptr<const PermissionSet> permissions_dwr( | 1754 scoped_refptr<const PermissionSet> permissions_dwr( |
| 1788 extension_dwr->permissions_data()->active_permissions()); | 1755 extension_dwr->permissions_data()->active_permissions()); |
| 1789 | 1756 |
| 1790 EXPECT_FALSE(PermissionMessageProvider::Get()-> | 1757 EXPECT_FALSE(PermissionMessageProvider::Get()-> |
| 1791 IsPrivilegeIncrease(permissions.get(), | 1758 IsPrivilegeIncrease(permissions.get(), |
| 1792 permissions_dwr.get(), | 1759 permissions_dwr.get(), |
| 1793 extension->GetType())); | 1760 extension->GetType())); |
| 1794 } | 1761 } |
| 1795 | 1762 |
| 1796 } // namespace extensions | 1763 } // namespace extensions |
| OLD | NEW |