extension_unittest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/common/extension.h"
  5. #include "base/command_line.h"
  6. #include "base/test/scoped_command_line.h"
  7. #include "base/test/scoped_feature_list.h"
  8. #include "extensions/common/error_utils.h"
  9. #include "extensions/common/extension_features.h"
  10. #include "extensions/common/manifest_constants.h"
  11. #include "extensions/common/switches.h"
  12. #include "extensions/common/value_builder.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. #include "third_party/abseil-cpp/absl/types/optional.h"
  15. using extensions::mojom::ManifestLocation;
  16. namespace extensions {
  17. namespace {
  18. std::string GetVersionTooHighWarning(int max_version, int supplied_version) {
  19. return ErrorUtils::FormatErrorMessage(
  20. manifest_errors::kManifestVersionTooHighWarning,
  21. base::NumberToString(max_version),
  22. base::NumberToString(supplied_version));
  23. }
  24. testing::AssertionResult RunManifestVersionSuccess(
  25. std::unique_ptr<base::DictionaryValue> manifest,
  26. Manifest::Type expected_type,
  27. int expected_manifest_version,
  28. base::StringPiece expected_warning = "",
  29. Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS,
  30. ManifestLocation manifest_location = ManifestLocation::kInternal) {
  31. std::string error;
  32. scoped_refptr<const Extension> extension = Extension::Create(
  33. base::FilePath(), manifest_location, *manifest, custom_flag, &error);
  34. if (!extension) {
  35. return testing::AssertionFailure()
  36. << "Extension creation failed: " << error;
  37. }
  38. if (extension->GetType() != expected_type) {
  39. return testing::AssertionFailure()
  40. << "Wrong type: " << extension->GetType();
  41. }
  42. if (extension->manifest_version() != expected_manifest_version) {
  43. return testing::AssertionFailure()
  44. << "Wrong manifest version: " << extension->manifest_version();
  45. }
  46. std::string manifest_version_warning;
  47. for (const auto& warning : extension->install_warnings()) {
  48. if (warning.key == manifest_keys::kManifestVersion) {
  49. manifest_version_warning = warning.message;
  50. break;
  51. }
  52. }
  53. if (expected_warning != manifest_version_warning) {
  54. return testing::AssertionFailure()
  55. << "Expected warning: '" << expected_warning << "', Found Warning: '"
  56. << manifest_version_warning << "'";
  57. }
  58. return testing::AssertionSuccess();
  59. }
  60. testing::AssertionResult RunManifestVersionFailure(
  61. std::unique_ptr<base::DictionaryValue> manifest,
  62. Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
  63. std::string error;
  64. scoped_refptr<const Extension> extension =
  65. Extension::Create(base::FilePath(), ManifestLocation::kInternal,
  66. *manifest, custom_flag, &error);
  67. if (extension)
  68. return testing::AssertionFailure() << "Extension creation succeeded.";
  69. return testing::AssertionSuccess();
  70. }
  71. testing::AssertionResult RunCreationWithFlags(
  72. const base::DictionaryValue* manifest,
  73. mojom::ManifestLocation location,
  74. Manifest::Type expected_type,
  75. Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
  76. std::string error;
  77. scoped_refptr<const Extension> extension = Extension::Create(
  78. base::FilePath(), location, *manifest, custom_flag, &error);
  79. if (!extension) {
  80. return testing::AssertionFailure()
  81. << "Extension creation failed: " << error;
  82. }
  83. if (extension->GetType() != expected_type) {
  84. return testing::AssertionFailure()
  85. << "Wrong type: " << extension->GetType();
  86. }
  87. return testing::AssertionSuccess();
  88. }
  89. } // namespace
  90. // TODO(devlin): Move tests from chrome/common/extensions/extension_unittest.cc
  91. // that don't depend on //chrome into here.
  92. TEST(ExtensionTest, ExtensionManifestVersions) {
  93. auto get_manifest = [](absl::optional<int> manifest_version) {
  94. DictionaryBuilder builder;
  95. builder.Set("name", "My Extension")
  96. .Set("version", "0.1")
  97. .Set("description", "An awesome extension");
  98. if (manifest_version)
  99. builder.Set("manifest_version", *manifest_version);
  100. return builder.Build();
  101. };
  102. const Manifest::Type kType = Manifest::TYPE_EXTENSION;
  103. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2));
  104. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3));
  105. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(4), kType, 4,
  106. GetVersionTooHighWarning(3, 4)));
  107. // Loading an unpacked MV2 extension should emit a warning.
  108. EXPECT_TRUE(RunManifestVersionSuccess(
  109. get_manifest(2), kType, 2,
  110. manifest_errors::kManifestV2IsDeprecatedWarning, Extension::NO_FLAGS,
  111. ManifestLocation::kUnpacked));
  112. // Manifest v1 is deprecated, and should not load.
  113. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1)));
  114. // Omitting the key defaults to v1 for extensions.
  115. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(absl::nullopt)));
  116. // '0' and '-1' are invalid values.
  117. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(0)));
  118. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(-1)));
  119. {
  120. // Manifest v1 should only load if a command line switch is used.
  121. base::test::ScopedCommandLine command_line;
  122. command_line.GetProcessCommandLine()->AppendSwitch(
  123. switches::kAllowLegacyExtensionManifests);
  124. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1));
  125. EXPECT_TRUE(
  126. RunManifestVersionSuccess(get_manifest(absl::nullopt), kType, 1));
  127. }
  128. }
  129. TEST(ExtensionTest, PlatformAppManifestVersions) {
  130. auto get_manifest = [](absl::optional<int> manifest_version) {
  131. DictionaryBuilder background;
  132. background.Set("scripts", ListBuilder().Append("background.js").Build());
  133. DictionaryBuilder builder;
  134. builder.Set("name", "My Platform App")
  135. .Set("version", "0.1")
  136. .Set("description", "A platform app")
  137. .Set("app",
  138. DictionaryBuilder().Set("background", background.Build()).Build());
  139. if (manifest_version)
  140. builder.Set("manifest_version", *manifest_version);
  141. return builder.Build();
  142. };
  143. const Manifest::Type kType = Manifest::TYPE_PLATFORM_APP;
  144. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2));
  145. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3));
  146. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(4), kType, 4,
  147. GetVersionTooHighWarning(3, 4)));
  148. // Omitting the key defaults to v2 for platform apps.
  149. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(absl::nullopt), kType, 2));
  150. // Manifest v1 is deprecated, and should not load.
  151. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1)));
  152. // '0' and '-1' are invalid values.
  153. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(0)));
  154. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(-1)));
  155. {
  156. // Manifest v1 should not load for platform apps, even with the command line
  157. // switch.
  158. base::test::ScopedCommandLine command_line;
  159. command_line.GetProcessCommandLine()->AppendSwitch(
  160. switches::kAllowLegacyExtensionManifests);
  161. EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1)));
  162. }
  163. }
  164. TEST(ExtensionTest, HostedAppManifestVersions) {
  165. auto get_manifest = [](absl::optional<int> manifest_version) {
  166. DictionaryBuilder builder;
  167. DictionaryBuilder app;
  168. app.Set("urls", ListBuilder().Append("http://example.com").Build());
  169. builder.Set("name", "My Hosted App")
  170. .Set("version", "0.1")
  171. .Set("description", "A hosted app")
  172. .Set("app", app.Build());
  173. if (manifest_version)
  174. builder.Set("manifest_version", *manifest_version);
  175. return builder.Build();
  176. };
  177. const Manifest::Type kType = Manifest::TYPE_HOSTED_APP;
  178. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2));
  179. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3));
  180. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(4), kType, 4,
  181. GetVersionTooHighWarning(3, 4)));
  182. // Manifest v1 is deprecated, but should still load for hosted apps.
  183. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1));
  184. // Omitting the key defaults to v1 for hosted apps, and v1 is still allowed.
  185. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(absl::nullopt), kType, 1));
  186. // Requiring the modern manifest version should make hosted apps require v2.
  187. EXPECT_TRUE(RunManifestVersionFailure(
  188. get_manifest(1), Extension::REQUIRE_MODERN_MANIFEST_VERSION));
  189. }
  190. TEST(ExtensionTest, UserScriptManifestVersions) {
  191. auto get_manifest = [](absl::optional<int> manifest_version) {
  192. DictionaryBuilder builder;
  193. builder.Set("name", "My Extension")
  194. .Set("version", "0.1")
  195. .Set("description", "An awesome extension")
  196. .Set("converted_from_user_script", true);
  197. if (manifest_version)
  198. builder.Set("manifest_version", *manifest_version);
  199. return builder.Build();
  200. };
  201. const Manifest::Type kType = Manifest::TYPE_USER_SCRIPT;
  202. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2));
  203. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3));
  204. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(4), kType, 4,
  205. GetVersionTooHighWarning(3, 4)));
  206. // Manifest v1 is deprecated, but should still load for user scripts.
  207. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1));
  208. // Omitting the key defaults to v1 for user scripts, but v1 is still allowed.
  209. EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(absl::nullopt), kType, 1));
  210. // Requiring the modern manifest version should make user scripts require v2.
  211. EXPECT_TRUE(RunManifestVersionFailure(
  212. get_manifest(1), Extension::REQUIRE_MODERN_MANIFEST_VERSION));
  213. }
  214. TEST(ExtensionTest, LoginScreenFlag) {
  215. DictionaryBuilder builder;
  216. builder.Set("name", "My Extension")
  217. .Set("version", "0.1")
  218. .Set("description", "An awesome extension")
  219. .Set("manifest_version", 2);
  220. std::unique_ptr<base::DictionaryValue> manifest = builder.Build();
  221. EXPECT_TRUE(
  222. RunCreationWithFlags(manifest.get(), ManifestLocation::kExternalPolicy,
  223. Manifest::TYPE_EXTENSION, Extension::NO_FLAGS));
  224. EXPECT_TRUE(RunCreationWithFlags(
  225. manifest.get(), ManifestLocation::kExternalPolicy,
  226. Manifest::TYPE_LOGIN_SCREEN_EXTENSION, Extension::FOR_LOGIN_SCREEN));
  227. }
  228. } // namespace extensions