Chromium Code Reviews| 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 "chrome/common/extensions/extension_file_util.h" | 5 #include "chrome/common/extensions/extension_file_util.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include <set> |
| 8 #include "base/files/scoped_temp_dir.h" | 8 |
| 9 #include "base/json/json_string_value_serializer.h" | |
| 10 #include "base/path_service.h" | 9 #include "base/path_service.h" |
| 11 #include "base/strings/stringprintf.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "chrome/common/chrome_paths.h" | 10 #include "chrome/common/chrome_paths.h" |
| 14 #include "extensions/common/constants.h" | |
| 15 #include "extensions/common/extension.h" | 11 #include "extensions/common/extension.h" |
| 12 #include "extensions/common/file_util.h" | |
| 16 #include "extensions/common/manifest.h" | 13 #include "extensions/common/manifest.h" |
| 17 #include "extensions/common/manifest_constants.h" | |
| 18 #include "grit/generated_resources.h" | |
| 19 #include "testing/gmock/include/gmock/gmock.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 21 #include "ui/base/l10n/l10n_util.h" | |
| 22 | 15 |
| 23 using extensions::Extension; | 16 namespace extensions { |
| 24 using extensions::Manifest; | |
| 25 | 17 |
| 26 namespace keys = extensions::manifest_keys; | 18 typedef testing::Test ExtensionFileUtilTest; |
| 27 | 19 |
| 28 class ExtensionFileUtilTest : public testing::Test { | 20 // Test that a browser action extension returns a path to an icon. |
| 29 }; | 21 TEST_F(ExtensionFileUtilTest, GetBrowserImagePaths) { |
|
James Cook
2014/04/12 00:03:22
I added this trivial unit test mostly to give this
| |
| 30 | |
| 31 TEST_F(ExtensionFileUtilTest, InstallUninstallGarbageCollect) { | |
| 32 base::ScopedTempDir temp; | |
| 33 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 34 | |
| 35 // Create a source extension. | |
| 36 std::string extension_id("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); | |
| 37 std::string version("1.0"); | |
| 38 base::FilePath src = temp.path().AppendASCII(extension_id); | |
| 39 ASSERT_TRUE(base::CreateDirectory(src)); | |
| 40 | |
| 41 // Create a extensions tree. | |
| 42 base::FilePath all_extensions = temp.path().AppendASCII("extensions"); | |
| 43 ASSERT_TRUE(base::CreateDirectory(all_extensions)); | |
| 44 | |
| 45 // Install in empty directory. Should create parent directories as needed. | |
| 46 base::FilePath version_1 = extension_file_util::InstallExtension( | |
| 47 src, | |
| 48 extension_id, | |
| 49 version, | |
| 50 all_extensions); | |
| 51 ASSERT_EQ(version_1.value(), | |
| 52 all_extensions.AppendASCII(extension_id).AppendASCII("1.0_0") | |
| 53 .value()); | |
| 54 ASSERT_TRUE(base::DirectoryExists(version_1)); | |
| 55 | |
| 56 // Should have moved the source. | |
| 57 ASSERT_FALSE(base::DirectoryExists(src)); | |
| 58 | |
| 59 // Install again. Should create a new one with different name. | |
| 60 ASSERT_TRUE(base::CreateDirectory(src)); | |
| 61 base::FilePath version_2 = extension_file_util::InstallExtension( | |
| 62 src, | |
| 63 extension_id, | |
| 64 version, | |
| 65 all_extensions); | |
| 66 ASSERT_EQ(version_2.value(), | |
| 67 all_extensions.AppendASCII(extension_id).AppendASCII("1.0_1") | |
| 68 .value()); | |
| 69 ASSERT_TRUE(base::DirectoryExists(version_2)); | |
| 70 | |
| 71 // Should have moved the source. | |
| 72 ASSERT_FALSE(base::DirectoryExists(src)); | |
| 73 | |
| 74 // Install yet again. Should create a new one with a different name. | |
| 75 ASSERT_TRUE(base::CreateDirectory(src)); | |
| 76 base::FilePath version_3 = extension_file_util::InstallExtension( | |
| 77 src, | |
| 78 extension_id, | |
| 79 version, | |
| 80 all_extensions); | |
| 81 ASSERT_EQ(version_3.value(), | |
| 82 all_extensions.AppendASCII(extension_id).AppendASCII("1.0_2") | |
| 83 .value()); | |
| 84 ASSERT_TRUE(base::DirectoryExists(version_3)); | |
| 85 | |
| 86 // Uninstall. Should remove entire extension subtree. | |
| 87 extension_file_util::UninstallExtension(all_extensions, extension_id); | |
| 88 ASSERT_FALSE(base::DirectoryExists(version_1.DirName())); | |
| 89 ASSERT_FALSE(base::DirectoryExists(version_2.DirName())); | |
| 90 ASSERT_FALSE(base::DirectoryExists(version_3.DirName())); | |
| 91 ASSERT_TRUE(base::DirectoryExists(all_extensions)); | |
| 92 } | |
| 93 | |
| 94 TEST_F(ExtensionFileUtilTest, LoadExtensionWithValidLocales) { | |
| 95 base::FilePath install_dir; | 22 base::FilePath install_dir; |
| 96 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | 23 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); |
| 97 install_dir = install_dir.AppendASCII("extensions") | 24 install_dir = install_dir.AppendASCII("extensions") |
| 98 .AppendASCII("good") | 25 .AppendASCII("api_test") |
| 99 .AppendASCII("Extensions") | 26 .AppendASCII("browser_action") |
| 100 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") | 27 .AppendASCII("basics"); |
| 101 .AppendASCII("1.0.0.0"); | |
| 102 | 28 |
| 103 std::string error; | 29 std::string error; |
| 104 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | 30 scoped_refptr<Extension> extension(file_util::LoadExtension( |
| 105 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | 31 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); |
| 106 ASSERT_TRUE(extension.get() != NULL); | 32 ASSERT_TRUE(extension.get()); |
| 107 EXPECT_EQ("The first extension that I made.", extension->description()); | 33 |
| 34 // The extension contains one icon. | |
| 35 std::set<base::FilePath> paths = | |
| 36 extension_file_util::GetBrowserImagePaths(extension.get()); | |
| 37 ASSERT_EQ(1u, paths.size()); | |
| 38 EXPECT_EQ("icon.png", paths.begin()->BaseName().AsUTF8Unsafe()); | |
| 108 } | 39 } |
| 109 | 40 |
| 110 TEST_F(ExtensionFileUtilTest, LoadExtensionWithoutLocalesFolder) { | 41 } // namespace extensions |
| 111 base::FilePath install_dir; | |
| 112 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | |
| 113 install_dir = install_dir.AppendASCII("extensions") | |
| 114 .AppendASCII("good") | |
| 115 .AppendASCII("Extensions") | |
| 116 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") | |
| 117 .AppendASCII("1.0"); | |
| 118 | |
| 119 std::string error; | |
| 120 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 121 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 122 ASSERT_FALSE(extension.get() == NULL); | |
| 123 EXPECT_TRUE(error.empty()); | |
| 124 } | |
| 125 | |
| 126 TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesNoUnderscores) { | |
| 127 base::ScopedTempDir temp; | |
| 128 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 129 | |
| 130 base::FilePath src_path = temp.path().AppendASCII("some_dir"); | |
| 131 ASSERT_TRUE(base::CreateDirectory(src_path)); | |
| 132 | |
| 133 std::string data = "{ \"name\": { \"message\": \"foobar\" } }"; | |
| 134 ASSERT_TRUE(base::WriteFile(src_path.AppendASCII("some_file.txt"), | |
| 135 data.c_str(), data.length())); | |
| 136 std::string error; | |
| 137 EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(), | |
| 138 &error)); | |
| 139 } | |
| 140 | |
| 141 TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesOnlyReserved) { | |
| 142 base::ScopedTempDir temp; | |
| 143 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 144 | |
| 145 const base::FilePath::CharType* folders[] = | |
| 146 { extensions::kLocaleFolder, extensions::kPlatformSpecificFolder }; | |
| 147 | |
| 148 for (size_t i = 0; i < arraysize(folders); i++) { | |
| 149 base::FilePath src_path = temp.path().Append(folders[i]); | |
| 150 ASSERT_TRUE(base::CreateDirectory(src_path)); | |
| 151 } | |
| 152 | |
| 153 std::string error; | |
| 154 EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(), | |
| 155 &error)); | |
| 156 } | |
| 157 | |
| 158 TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesReservedAndIllegal) { | |
| 159 base::ScopedTempDir temp; | |
| 160 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 161 | |
| 162 base::FilePath src_path = temp.path().Append(extensions::kLocaleFolder); | |
| 163 ASSERT_TRUE(base::CreateDirectory(src_path)); | |
| 164 | |
| 165 src_path = temp.path().AppendASCII("_some_dir"); | |
| 166 ASSERT_TRUE(base::CreateDirectory(src_path)); | |
| 167 | |
| 168 std::string error; | |
| 169 EXPECT_FALSE(extension_file_util::CheckForIllegalFilenames(temp.path(), | |
| 170 &error)); | |
| 171 } | |
| 172 | |
| 173 TEST_F(ExtensionFileUtilTest, | |
| 174 LoadExtensionGivesHelpfullErrorOnMissingManifest) { | |
| 175 base::FilePath install_dir; | |
| 176 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | |
| 177 install_dir = install_dir.AppendASCII("extensions") | |
| 178 .AppendASCII("bad") | |
| 179 .AppendASCII("Extensions") | |
| 180 .AppendASCII("dddddddddddddddddddddddddddddddd") | |
| 181 .AppendASCII("1.0"); | |
| 182 | |
| 183 std::string error; | |
| 184 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 185 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 186 ASSERT_TRUE(extension.get() == NULL); | |
| 187 ASSERT_FALSE(error.empty()); | |
| 188 ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str()); | |
| 189 } | |
| 190 | |
| 191 TEST_F(ExtensionFileUtilTest, LoadExtensionGivesHelpfullErrorOnBadManifest) { | |
| 192 base::FilePath install_dir; | |
| 193 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | |
| 194 install_dir = install_dir.AppendASCII("extensions") | |
| 195 .AppendASCII("bad") | |
| 196 .AppendASCII("Extensions") | |
| 197 .AppendASCII("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") | |
| 198 .AppendASCII("1.0"); | |
| 199 | |
| 200 std::string error; | |
| 201 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 202 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 203 ASSERT_TRUE(extension.get() == NULL); | |
| 204 ASSERT_FALSE(error.empty()); | |
| 205 ASSERT_STREQ("Manifest is not valid JSON. " | |
| 206 "Line: 2, column: 16, Syntax error.", error.c_str()); | |
| 207 } | |
| 208 | |
| 209 TEST_F(ExtensionFileUtilTest, FailLoadingNonUTF8Scripts) { | |
| 210 base::FilePath install_dir; | |
| 211 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | |
| 212 install_dir = install_dir.AppendASCII("extensions") | |
| 213 .AppendASCII("bad") | |
| 214 .AppendASCII("bad_encoding"); | |
| 215 | |
| 216 std::string error; | |
| 217 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 218 install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 219 ASSERT_TRUE(extension.get() == NULL); | |
| 220 ASSERT_STREQ("Could not load file 'bad_encoding.js' for content script. " | |
| 221 "It isn't UTF-8 encoded.", | |
| 222 error.c_str()); | |
| 223 } | |
| 224 | |
| 225 static scoped_refptr<Extension> LoadExtensionManifest( | |
| 226 base::DictionaryValue* manifest, | |
| 227 const base::FilePath& manifest_dir, | |
| 228 Manifest::Location location, | |
| 229 int extra_flags, | |
| 230 std::string* error) { | |
| 231 scoped_refptr<Extension> extension = Extension::Create( | |
| 232 manifest_dir, location, *manifest, extra_flags, error); | |
| 233 return extension; | |
| 234 } | |
| 235 | |
| 236 static scoped_refptr<Extension> LoadExtensionManifest( | |
| 237 const std::string& manifest_value, | |
| 238 const base::FilePath& manifest_dir, | |
| 239 Manifest::Location location, | |
| 240 int extra_flags, | |
| 241 std::string* error) { | |
| 242 JSONStringValueSerializer serializer(manifest_value); | |
| 243 scoped_ptr<base::Value> result(serializer.Deserialize(NULL, error)); | |
| 244 if (!result.get()) | |
| 245 return NULL; | |
| 246 CHECK_EQ(base::Value::TYPE_DICTIONARY, result->GetType()); | |
| 247 return LoadExtensionManifest( | |
| 248 static_cast<base::DictionaryValue*>(result.get()), | |
| 249 manifest_dir, | |
| 250 location, | |
| 251 extra_flags, | |
| 252 error); | |
| 253 } | |
| 254 | |
| 255 TEST_F(ExtensionFileUtilTest, ValidateThemeUTF8) { | |
| 256 base::ScopedTempDir temp; | |
| 257 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 258 | |
| 259 // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them. | |
| 260 std::string non_ascii_file = "\xC3\xA0\xC3\xA8\xC3\xB2.png"; | |
| 261 base::FilePath non_ascii_path = | |
| 262 temp.path().Append(base::FilePath::FromUTF8Unsafe(non_ascii_file)); | |
| 263 base::WriteFile(non_ascii_path, "", 0); | |
| 264 | |
| 265 std::string kManifest = | |
| 266 base::StringPrintf( | |
| 267 "{ \"name\": \"Test\", \"version\": \"1.0\", " | |
| 268 " \"theme\": { \"images\": { \"theme_frame\": \"%s\" } }" | |
| 269 "}", non_ascii_file.c_str()); | |
| 270 std::string error; | |
| 271 scoped_refptr<Extension> extension = LoadExtensionManifest( | |
| 272 kManifest, temp.path(), Manifest::UNPACKED, 0, &error); | |
| 273 ASSERT_TRUE(extension.get()) << error; | |
| 274 | |
| 275 std::vector<extensions::InstallWarning> warnings; | |
| 276 EXPECT_TRUE(extension_file_util::ValidateExtension( | |
| 277 extension.get(), &error, &warnings)) << error; | |
| 278 EXPECT_EQ(0U, warnings.size()); | |
| 279 } | |
| 280 | |
| 281 TEST_F(ExtensionFileUtilTest, BackgroundScriptsMustExist) { | |
| 282 base::ScopedTempDir temp; | |
| 283 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 284 | |
| 285 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | |
| 286 value->SetString("name", "test"); | |
| 287 value->SetString("version", "1"); | |
| 288 value->SetInteger("manifest_version", 1); | |
| 289 | |
| 290 base::ListValue* scripts = new base::ListValue(); | |
| 291 scripts->Append(new base::StringValue("foo.js")); | |
| 292 value->Set("background.scripts", scripts); | |
| 293 | |
| 294 std::string error; | |
| 295 std::vector<extensions::InstallWarning> warnings; | |
| 296 scoped_refptr<Extension> extension = LoadExtensionManifest( | |
| 297 value.get(), temp.path(), Manifest::UNPACKED, 0, &error); | |
| 298 ASSERT_TRUE(extension.get()) << error; | |
| 299 | |
| 300 EXPECT_FALSE(extension_file_util::ValidateExtension( | |
| 301 extension.get(), &error, &warnings)); | |
| 302 EXPECT_EQ(l10n_util::GetStringFUTF8( | |
| 303 IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED, | |
| 304 base::ASCIIToUTF16("foo.js")), | |
| 305 error); | |
| 306 EXPECT_EQ(0U, warnings.size()); | |
| 307 | |
| 308 scripts->Clear(); | |
| 309 scripts->Append(new base::StringValue("http://google.com/foo.js")); | |
| 310 | |
| 311 extension = LoadExtensionManifest(value.get(), temp.path(), | |
| 312 Manifest::UNPACKED, 0, &error); | |
| 313 ASSERT_TRUE(extension.get()) << error; | |
| 314 | |
| 315 warnings.clear(); | |
| 316 EXPECT_FALSE(extension_file_util::ValidateExtension( | |
| 317 extension.get(), &error, &warnings)); | |
| 318 EXPECT_EQ(l10n_util::GetStringFUTF8( | |
| 319 IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED, | |
| 320 base::ASCIIToUTF16("http://google.com/foo.js")), | |
| 321 error); | |
| 322 EXPECT_EQ(0U, warnings.size()); | |
| 323 } | |
| 324 | |
| 325 // Private key, generated by Chrome specifically for this test, and | |
| 326 // never used elsewhere. | |
| 327 const char private_key[] = | |
| 328 "-----BEGIN PRIVATE KEY-----\n" | |
| 329 "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKt02SR0FYaYy6fpW\n" | |
| 330 "MAA+kU1BgK3d+OmmWfdr+JATIjhRkyeSF4lTd/71JQsyKqPzYkQPi3EeROWM+goTv\n" | |
| 331 "EhJqq07q63BolpsFmlV+S4ny+sBA2B4aWwRYXlBWikdrQSA0mJMzvEHc6nKzBgXik\n" | |
| 332 "QSVbyyBNAsxlDB9WaCxRVOpK3AgMBAAECgYBGvSPlrVtAOAQ2V8j9FqorKZA8SLPX\n" | |
| 333 "IeJC/yzU3RB2nPMjI17aMOvrUHxJUhzMeh4jwabVvSzzDtKFozPGupW3xaI8sQdi2\n" | |
| 334 "WWMTQIk/Q9HHDWoQ9qA6SwX2qWCc5SyjCKqVp78ye+000kqTJYjBsDgXeAlzKcx2B\n" | |
| 335 "4GAAeWonDdkQJBANNb8wrqNWFn7DqyQTfELzcRTRnqQ/r1pdeJo6obzbnwGnlqe3t\n" | |
| 336 "KhLjtJNIGrQg5iC0OVLWFuvPJs0t3z62A1ckCQQDPq2JZuwTwu5Pl4DJ0r9O1FdqN\n" | |
| 337 "JgqPZyMptokCDQ3khLLGakIu+TqB9YtrzI69rJMSG2Egb+6McaDX+dh3XmR/AkB9t\n" | |
| 338 "xJf6qDnmA2td/tMtTc0NOk8Qdg/fD8xbZ/YfYMnVoYYs9pQoilBaWRePDRNURMLYZ\n" | |
| 339 "vHAI0Llmw7tj7jv17pAkEAz44uXRpjRKtllUIvi5pUENAHwDz+HvdpGH68jpU3hmb\n" | |
| 340 "uOwrmnQYxaMReFV68Z2w9DcLZn07f7/R9Wn72z89CxwJAFsDoNaDes4h48bX7plct\n" | |
| 341 "s9ACjmTwcCigZjN2K7AGv7ntCLF3DnV5dK0dTHNaAdD3SbY3jl29Rk2CwiURSX6Ee\n" | |
| 342 "g==\n" | |
| 343 "-----END PRIVATE KEY-----\n"; | |
| 344 | |
| 345 TEST_F(ExtensionFileUtilTest, FindPrivateKeyFiles) { | |
| 346 base::ScopedTempDir temp; | |
| 347 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 348 | |
| 349 base::FilePath src_path = temp.path().AppendASCII("some_dir"); | |
| 350 ASSERT_TRUE(base::CreateDirectory(src_path)); | |
| 351 | |
| 352 ASSERT_TRUE(base::WriteFile(src_path.AppendASCII("a_key.pem"), | |
| 353 private_key, arraysize(private_key))); | |
| 354 ASSERT_TRUE(base::WriteFile(src_path.AppendASCII("second_key.pem"), | |
| 355 private_key, arraysize(private_key))); | |
| 356 // Shouldn't find a key with a different extension. | |
| 357 ASSERT_TRUE(base::WriteFile(src_path.AppendASCII("key.diff_ext"), | |
| 358 private_key, arraysize(private_key))); | |
| 359 // Shouldn't find a key that isn't parsable. | |
| 360 ASSERT_TRUE(base::WriteFile(src_path.AppendASCII("unparsable_key.pem"), | |
| 361 private_key, arraysize(private_key) - 30)); | |
| 362 std::vector<base::FilePath> private_keys = | |
| 363 extension_file_util::FindPrivateKeyFiles(temp.path()); | |
| 364 EXPECT_EQ(2U, private_keys.size()); | |
| 365 EXPECT_THAT(private_keys, | |
| 366 testing::Contains(src_path.AppendASCII("a_key.pem"))); | |
| 367 EXPECT_THAT(private_keys, | |
| 368 testing::Contains(src_path.AppendASCII("second_key.pem"))); | |
| 369 } | |
| 370 | |
| 371 TEST_F(ExtensionFileUtilTest, WarnOnPrivateKey) { | |
| 372 base::ScopedTempDir temp; | |
| 373 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 374 | |
| 375 base::FilePath ext_path = temp.path().AppendASCII("ext_root"); | |
| 376 ASSERT_TRUE(base::CreateDirectory(ext_path)); | |
| 377 | |
| 378 const char manifest[] = | |
| 379 "{\n" | |
| 380 " \"name\": \"Test Extension\",\n" | |
| 381 " \"version\": \"1.0\",\n" | |
| 382 " \"manifest_version\": 2,\n" | |
| 383 " \"description\": \"The first extension that I made.\"\n" | |
| 384 "}\n"; | |
| 385 ASSERT_TRUE(base::WriteFile(ext_path.AppendASCII("manifest.json"), | |
| 386 manifest, strlen(manifest))); | |
| 387 ASSERT_TRUE(base::WriteFile(ext_path.AppendASCII("a_key.pem"), | |
| 388 private_key, strlen(private_key))); | |
| 389 | |
| 390 std::string error; | |
| 391 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 392 ext_path, "the_id", Manifest::EXTERNAL_PREF, | |
| 393 Extension::NO_FLAGS, &error)); | |
| 394 ASSERT_TRUE(extension.get()) << error; | |
| 395 ASSERT_EQ(1u, extension->install_warnings().size()); | |
| 396 EXPECT_THAT( | |
| 397 extension->install_warnings(), | |
| 398 testing::ElementsAre( | |
| 399 testing::Field( | |
| 400 &extensions::InstallWarning::message, | |
| 401 testing::ContainsRegex( | |
| 402 "extension includes the key file.*ext_root.a_key.pem")))); | |
| 403 | |
| 404 // Turn the warning into an error with ERROR_ON_PRIVATE_KEY. | |
| 405 extension = extension_file_util::LoadExtension( | |
| 406 ext_path, "the_id", Manifest::EXTERNAL_PREF, | |
| 407 Extension::ERROR_ON_PRIVATE_KEY, &error); | |
| 408 EXPECT_FALSE(extension.get()); | |
| 409 EXPECT_THAT(error, | |
| 410 testing::ContainsRegex( | |
| 411 "extension includes the key file.*ext_root.a_key.pem")); | |
| 412 } | |
| 413 | |
| 414 TEST_F(ExtensionFileUtilTest, CheckZeroLengthImageFile) { | |
| 415 base::FilePath install_dir; | |
| 416 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); | |
| 417 | |
| 418 // Try to install an extension with a zero-length icon file. | |
| 419 base::FilePath ext_dir = install_dir.AppendASCII("extensions") | |
| 420 .AppendASCII("bad") | |
| 421 .AppendASCII("Extensions") | |
| 422 .AppendASCII("ffffffffffffffffffffffffffffffff"); | |
| 423 | |
| 424 std::string error; | |
| 425 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( | |
| 426 ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 427 EXPECT_TRUE(extension.get() == NULL); | |
| 428 EXPECT_STREQ("Could not load extension icon 'icon.png'.", error.c_str()); | |
| 429 | |
| 430 // Try to install an extension with a zero-length browser action icon file. | |
| 431 ext_dir = install_dir.AppendASCII("extensions") | |
| 432 .AppendASCII("bad") | |
| 433 .AppendASCII("Extensions") | |
| 434 .AppendASCII("gggggggggggggggggggggggggggggggg"); | |
| 435 | |
| 436 scoped_refptr<Extension> extension2(extension_file_util::LoadExtension( | |
| 437 ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 438 EXPECT_TRUE(extension2.get() == NULL); | |
| 439 EXPECT_STREQ("Could not load icon 'icon.png' for browser action.", | |
| 440 error.c_str()); | |
| 441 | |
| 442 // Try to install an extension with a zero-length page action icon file. | |
| 443 ext_dir = install_dir.AppendASCII("extensions") | |
| 444 .AppendASCII("bad") | |
| 445 .AppendASCII("Extensions") | |
| 446 .AppendASCII("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"); | |
| 447 | |
| 448 scoped_refptr<Extension> extension3(extension_file_util::LoadExtension( | |
| 449 ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error)); | |
| 450 EXPECT_TRUE(extension3.get() == NULL); | |
| 451 EXPECT_STREQ("Could not load icon 'icon.png' for page action.", | |
| 452 error.c_str()); | |
| 453 } | |
| 454 | |
| 455 // TODO(aa): More tests as motivation allows. Maybe steal some from | |
| 456 // ExtensionService? Many of them could probably be tested here without the | |
| 457 // MessageLoop shenanigans. | |
| OLD | NEW |