1 // Copyright (c) 2013 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 5 #include "base/files/file_util.h" 6 #include "base/format_macros.h" 7 #include "base/path_service.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/stringprintf.h" 10 #include "chrome/common/chrome_paths.h" 11 #include "chrome/common/extensions/command.h" 12 #include "chrome/common/extensions/extension_test_util.h" 13 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" 14 #include "chrome/common/url_constants.h" 15 #include "components/crx_file/id_util.h" 16 #include "extensions/common/extension.h" 17 #include "extensions/common/extension_resource.h" 18 #include "extensions/common/file_util.h" 19 #include "extensions/common/manifest.h" 20 #include "extensions/common/permissions/permissions_data.h" 21 #include "net/base/mime_sniffer.h" 22 #include "net/dns/mock_host_resolver.h" 23 #include "skia/ext/image_operations.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 #include "third_party/skia/include/core/SkBitmap.h" 26 #include "ui/gfx/codec/png_codec.h" 27 #include "url/gurl.h" 28 29 using extension_test_util::LoadManifest; 30 using extension_test_util::LoadManifestStrict; 31 using base::FilePath; 32 33 namespace extensions { 34 35 // We persist location values in the preferences, so this is a sanity test that 36 // someone doesn't accidentally change them. 37 TEST(ExtensionTest, LocationValuesTest) { 38 ASSERT_EQ(0, Manifest::INVALID_LOCATION); 39 ASSERT_EQ(1, Manifest::INTERNAL); 40 ASSERT_EQ(2, Manifest::EXTERNAL_PREF); 41 ASSERT_EQ(3, Manifest::EXTERNAL_REGISTRY); 42 ASSERT_EQ(4, Manifest::UNPACKED); 43 ASSERT_EQ(5, Manifest::COMPONENT); 44 ASSERT_EQ(6, Manifest::EXTERNAL_PREF_DOWNLOAD); 45 ASSERT_EQ(7, Manifest::EXTERNAL_POLICY_DOWNLOAD); 46 ASSERT_EQ(8, Manifest::COMMAND_LINE); 47 ASSERT_EQ(9, Manifest::EXTERNAL_POLICY); 48 } 49 50 TEST(ExtensionTest, LocationPriorityTest) { 51 for (int i = 0; i < Manifest::NUM_LOCATIONS; i++) { 52 Manifest::Location loc = static_cast<Manifest::Location>(i); 53 54 // INVALID is not a valid location. 55 if (loc == Manifest::INVALID_LOCATION) 56 continue; 57 58 // Comparing a location that has no rank will hit a CHECK. Do a 59 // compare with every valid location, to be sure each one is covered. 60 61 // Check that no install source can override a componenet extension. 62 ASSERT_EQ(Manifest::COMPONENT, 63 Manifest::GetHigherPriorityLocation(Manifest::COMPONENT, loc)); 64 ASSERT_EQ(Manifest::COMPONENT, 65 Manifest::GetHigherPriorityLocation(loc, Manifest::COMPONENT)); 66 67 // Check that any source can override a user install. This might change 68 // in the future, in which case this test should be updated. 69 ASSERT_EQ(loc, 70 Manifest::GetHigherPriorityLocation(Manifest::INTERNAL, loc)); 71 ASSERT_EQ(loc, 72 Manifest::GetHigherPriorityLocation(loc, Manifest::INTERNAL)); 73 } 74 75 // Check a few interesting cases that we know can happen: 76 ASSERT_EQ(Manifest::EXTERNAL_POLICY_DOWNLOAD, 77 Manifest::GetHigherPriorityLocation( 78 Manifest::EXTERNAL_POLICY_DOWNLOAD, 79 Manifest::EXTERNAL_PREF)); 80 81 ASSERT_EQ(Manifest::EXTERNAL_PREF, 82 Manifest::GetHigherPriorityLocation( 83 Manifest::INTERNAL, 84 Manifest::EXTERNAL_PREF)); 85 } 86 87 TEST(ExtensionTest, GetResourceURLAndPath) { 88 scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest", 89 "empty.json"); 90 EXPECT_TRUE(extension.get()); 91 92 EXPECT_EQ(extension->url().spec() + "bar/baz.js", 93 Extension::GetResourceURL(extension->url(), "bar/baz.js").spec()); 94 EXPECT_EQ(extension->url().spec() + "baz.js", 95 Extension::GetResourceURL(extension->url(), 96 "bar/../baz.js").spec()); 97 EXPECT_EQ(extension->url().spec() + "baz.js", 98 Extension::GetResourceURL(extension->url(), "../baz.js").spec()); 99 100 // Test that absolute-looking paths ("/"-prefixed) are pasted correctly. 101 EXPECT_EQ(extension->url().spec() + "test.html", 102 extension->GetResourceURL("/test.html").spec()); 103 } 104 105 TEST(ExtensionTest, GetResource) { 106 const FilePath valid_path_test_cases[] = { 107 FilePath(FILE_PATH_LITERAL("manifest.json")), 108 FilePath(FILE_PATH_LITERAL("a/b/c/manifest.json")), 109 FilePath(FILE_PATH_LITERAL("com/manifest.json")), 110 FilePath(FILE_PATH_LITERAL("lpt/manifest.json")), 111 }; 112 const FilePath invalid_path_test_cases[] = { 113 // Directory name 114 FilePath(FILE_PATH_LITERAL("src/")), 115 // Contains a drive letter specification. 116 FilePath(FILE_PATH_LITERAL("C:\\manifest.json")), 117 // Use backslash '\\' as separator. 118 FilePath(FILE_PATH_LITERAL("a\\b\\c\\manifest.json")), 119 // Reserved Characters with extension 120 FilePath(FILE_PATH_LITERAL("mani>fest.json")), 121 FilePath(FILE_PATH_LITERAL("mani<fest.json")), 122 FilePath(FILE_PATH_LITERAL("mani*fest.json")), 123 FilePath(FILE_PATH_LITERAL("mani:fest.json")), 124 FilePath(FILE_PATH_LITERAL("mani?fest.json")), 125 FilePath(FILE_PATH_LITERAL("mani|fest.json")), 126 // Reserved Characters without extension 127 FilePath(FILE_PATH_LITERAL("mani>fest")), 128 FilePath(FILE_PATH_LITERAL("mani<fest")), 129 FilePath(FILE_PATH_LITERAL("mani*fest")), 130 FilePath(FILE_PATH_LITERAL("mani:fest")), 131 FilePath(FILE_PATH_LITERAL("mani?fest")), 132 FilePath(FILE_PATH_LITERAL("mani|fest")), 133 // Reserved Names with extension. 134 FilePath(FILE_PATH_LITERAL("com1.json")), 135 FilePath(FILE_PATH_LITERAL("com9.json")), 136 FilePath(FILE_PATH_LITERAL("LPT1.json")), 137 FilePath(FILE_PATH_LITERAL("LPT9.json")), 138 FilePath(FILE_PATH_LITERAL("CON.json")), 139 FilePath(FILE_PATH_LITERAL("PRN.json")), 140 FilePath(FILE_PATH_LITERAL("AUX.json")), 141 FilePath(FILE_PATH_LITERAL("NUL.json")), 142 // Reserved Names without extension. 143 FilePath(FILE_PATH_LITERAL("com1")), 144 FilePath(FILE_PATH_LITERAL("com9")), 145 FilePath(FILE_PATH_LITERAL("LPT1")), 146 FilePath(FILE_PATH_LITERAL("LPT9")), 147 FilePath(FILE_PATH_LITERAL("CON")), 148 FilePath(FILE_PATH_LITERAL("PRN")), 149 FilePath(FILE_PATH_LITERAL("AUX")), 150 FilePath(FILE_PATH_LITERAL("NUL")), 151 // Reserved Names as directory. 152 FilePath(FILE_PATH_LITERAL("com1/manifest.json")), 153 FilePath(FILE_PATH_LITERAL("com9/manifest.json")), 154 FilePath(FILE_PATH_LITERAL("LPT1/manifest.json")), 155 FilePath(FILE_PATH_LITERAL("LPT9/manifest.json")), 156 FilePath(FILE_PATH_LITERAL("CON/manifest.json")), 157 FilePath(FILE_PATH_LITERAL("PRN/manifest.json")), 158 FilePath(FILE_PATH_LITERAL("AUX/manifest.json")), 159 FilePath(FILE_PATH_LITERAL("NUL/manifest.json")), 160 }; 161 162 scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest", 163 "empty.json"); 164 EXPECT_TRUE(extension.get()); 165 for (size_t i = 0; i < arraysize(valid_path_test_cases); ++i) 166 EXPECT_TRUE(!extension->GetResource(valid_path_test_cases[i]).empty()); 167 for (size_t i = 0; i < arraysize(invalid_path_test_cases); ++i) 168 EXPECT_TRUE(extension->GetResource(invalid_path_test_cases[i]).empty()); 169 } 170 171 TEST(ExtensionTest, GetAbsolutePathNoError) { 172 scoped_refptr<Extension> extension = LoadManifestStrict("absolute_path", 173 "absolute.json"); 174 EXPECT_TRUE(extension.get()); 175 std::string err; 176 std::vector<InstallWarning> warnings; 177 EXPECT_TRUE(file_util::ValidateExtension(extension.get(), &err, &warnings)); 178 EXPECT_EQ(0U, warnings.size()); 179 180 EXPECT_EQ(extension->path().AppendASCII("test.html").value(), 181 extension->GetResource("test.html").GetFilePath().value()); 182 EXPECT_EQ(extension->path().AppendASCII("test.js").value(), 183 extension->GetResource("test.js").GetFilePath().value()); 184 } 185 186 187 TEST(ExtensionTest, IdIsValid) { 188 EXPECT_TRUE(crx_file::id_util::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); 189 EXPECT_TRUE(crx_file::id_util::IdIsValid("pppppppppppppppppppppppppppppppp")); 190 EXPECT_TRUE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnop")); 191 EXPECT_TRUE(crx_file::id_util::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")); 192 EXPECT_FALSE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno")); 193 EXPECT_FALSE( 194 crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnopa")); 195 EXPECT_FALSE( 196 crx_file::id_util::IdIsValid("0123456789abcdef0123456789abcdef")); 197 EXPECT_FALSE( 198 crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnoq")); 199 EXPECT_FALSE( 200 crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno0")); 201 } 202 203 204 // This test ensures that the mimetype sniffing code stays in sync with the 205 // actual crx files that we test other parts of the system with. 206 TEST(ExtensionTest, MimeTypeSniffing) { 207 base::FilePath path; 208 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 209 path = path.AppendASCII("extensions").AppendASCII("good.crx"); 210 211 std::string data; 212 ASSERT_TRUE(base::ReadFileToString(path, &data)); 213 214 std::string result; 215 EXPECT_TRUE(net::SniffMimeType(data.c_str(), 216 data.size(), 217 GURL("http://www.example.com/foo.crx"), 218 std::string(), 219 &result)); 220 EXPECT_EQ(std::string(Extension::kMimeType), result); 221 222 data.clear(); 223 result.clear(); 224 path = path.DirName().AppendASCII("bad_magic.crx"); 225 ASSERT_TRUE(base::ReadFileToString(path, &data)); 226 EXPECT_TRUE(net::SniffMimeType(data.c_str(), 227 data.size(), 228 GURL("http://www.example.com/foo.crx"), 229 std::string(), 230 &result)); 231 EXPECT_EQ("application/octet-stream", result); 232 } 233 234 TEST(ExtensionTest, WantsFileAccess) { 235 scoped_refptr<Extension> extension; 236 GURL file_url("file:///etc/passwd"); 237 238 // Ignore the policy delegate for this test. 239 PermissionsData::SetPolicyDelegate(NULL); 240 241 // <all_urls> permission 242 extension = LoadManifest("permissions", "permissions_all_urls.json"); 243 EXPECT_TRUE(extension->wants_file_access()); 244 EXPECT_FALSE(extension->permissions_data()->CanAccessPage( 245 extension.get(), file_url, file_url, -1, -1, NULL)); 246 extension = LoadManifest( 247 "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS); 248 EXPECT_TRUE(extension->wants_file_access()); 249 EXPECT_TRUE(extension->permissions_data()->CanAccessPage( 250 extension.get(), file_url, file_url, -1, -1, NULL)); 251 252 // file:///* permission 253 extension = LoadManifest("permissions", "permissions_file_scheme.json"); 254 EXPECT_TRUE(extension->wants_file_access()); 255 EXPECT_FALSE(extension->permissions_data()->CanAccessPage( 256 extension.get(), file_url, file_url, -1, -1, NULL)); 257 extension = LoadManifest("permissions", 258 "permissions_file_scheme.json", 259 Extension::ALLOW_FILE_ACCESS); 260 EXPECT_TRUE(extension->wants_file_access()); 261 EXPECT_TRUE(extension->permissions_data()->CanAccessPage( 262 extension.get(), file_url, file_url, -1, -1, NULL)); 263 264 // http://* permission 265 extension = LoadManifest("permissions", "permissions_http_scheme.json"); 266 EXPECT_FALSE(extension->wants_file_access()); 267 EXPECT_FALSE(extension->permissions_data()->CanAccessPage( 268 extension.get(), file_url, file_url, -1, -1, NULL)); 269 extension = LoadManifest("permissions", 270 "permissions_http_scheme.json", 271 Extension::ALLOW_FILE_ACCESS); 272 EXPECT_FALSE(extension->wants_file_access()); 273 EXPECT_FALSE(extension->permissions_data()->CanAccessPage( 274 extension.get(), file_url, file_url, -1, -1, NULL)); 275 276 // <all_urls> content script match 277 extension = LoadManifest("permissions", "content_script_all_urls.json"); 278 EXPECT_TRUE(extension->wants_file_access()); 279 EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage( 280 extension.get(), file_url, file_url, -1, -1, NULL)); 281 extension = LoadManifest("permissions", "content_script_all_urls.json", 282 Extension::ALLOW_FILE_ACCESS); 283 EXPECT_TRUE(extension->wants_file_access()); 284 EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage( 285 extension.get(), file_url, file_url, -1, -1, NULL)); 286 287 // file:///* content script match 288 extension = LoadManifest("permissions", "content_script_file_scheme.json"); 289 EXPECT_TRUE(extension->wants_file_access()); 290 EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage( 291 extension.get(), file_url, file_url, -1, -1, NULL)); 292 extension = LoadManifest("permissions", "content_script_file_scheme.json", 293 Extension::ALLOW_FILE_ACCESS); 294 EXPECT_TRUE(extension->wants_file_access()); 295 EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage( 296 extension.get(), file_url, file_url, -1, -1, NULL)); 297 298 // http://* content script match 299 extension = LoadManifest("permissions", "content_script_http_scheme.json"); 300 EXPECT_FALSE(extension->wants_file_access()); 301 EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage( 302 extension.get(), file_url, file_url, -1, -1, NULL)); 303 extension = LoadManifest("permissions", "content_script_http_scheme.json", 304 Extension::ALLOW_FILE_ACCESS); 305 EXPECT_FALSE(extension->wants_file_access()); 306 EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage( 307 extension.get(), file_url, file_url, -1, -1, NULL)); 308 } 309 310 TEST(ExtensionTest, ExtraFlags) { 311 scoped_refptr<Extension> extension; 312 extension = LoadManifest("app", "manifest.json", Extension::FROM_WEBSTORE); 313 EXPECT_TRUE(extension->from_webstore()); 314 315 extension = LoadManifest("app", "manifest.json", Extension::FROM_BOOKMARK); 316 EXPECT_TRUE(extension->from_bookmark()); 317 318 extension = LoadManifest("app", "manifest.json", Extension::NO_FLAGS); 319 EXPECT_FALSE(extension->from_bookmark()); 320 EXPECT_FALSE(extension->from_webstore()); 321 } 322 323 } // namespace extensions 324