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 <stddef.h>
6 
7 #include "base/files/file_util.h"
8 #include "base/format_macros.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "build/build_config.h"
15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/common/extensions/command.h"
17 #include "chrome/common/extensions/extension_test_util.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "components/crx_file/id_util.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_builder.h"
23 #include "extensions/common/extension_resource.h"
24 #include "extensions/common/file_util.h"
25 #include "extensions/common/manifest.h"
26 #include "extensions/common/manifest_handlers/content_scripts_handler.h"
27 #include "extensions/common/permissions/permissions_data.h"
28 #include "extensions/common/value_builder.h"
29 #include "extensions/test/test_extension_dir.h"
30 #include "net/base/mime_sniffer.h"
31 #include "net/dns/mock_host_resolver.h"
32 #include "skia/ext/image_operations.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/gfx/codec/png_codec.h"
37 #include "url/gurl.h"
38 
39 using extension_test_util::LoadManifest;
40 using extension_test_util::LoadManifestStrict;
41 using base::FilePath;
42 
43 namespace extensions {
44 
45 // We persist location values in the preferences, so this is a sanity test that
46 // someone doesn't accidentally change them.
TEST(ExtensionTest,LocationValuesTest)47 TEST(ExtensionTest, LocationValuesTest) {
48   ASSERT_EQ(0, Manifest::INVALID_LOCATION);
49   ASSERT_EQ(1, Manifest::INTERNAL);
50   ASSERT_EQ(2, Manifest::EXTERNAL_PREF);
51   ASSERT_EQ(3, Manifest::EXTERNAL_REGISTRY);
52   ASSERT_EQ(4, Manifest::UNPACKED);
53   ASSERT_EQ(5, Manifest::COMPONENT);
54   ASSERT_EQ(6, Manifest::EXTERNAL_PREF_DOWNLOAD);
55   ASSERT_EQ(7, Manifest::EXTERNAL_POLICY_DOWNLOAD);
56   ASSERT_EQ(8, Manifest::COMMAND_LINE);
57   ASSERT_EQ(9, Manifest::EXTERNAL_POLICY);
58 }
59 
TEST(ExtensionTest,LocationPriorityTest)60 TEST(ExtensionTest, LocationPriorityTest) {
61   for (int i = 0; i < Manifest::NUM_LOCATIONS; i++) {
62     Manifest::Location loc = static_cast<Manifest::Location>(i);
63 
64     // INVALID is not a valid location.
65     if (loc == Manifest::INVALID_LOCATION)
66       continue;
67 
68     // Comparing a location that has no rank will hit a CHECK. Do a
69     // compare with every valid location, to be sure each one is covered.
70 
71     // Check that no install source can override a componenet extension.
72     ASSERT_EQ(Manifest::COMPONENT,
73               Manifest::GetHigherPriorityLocation(Manifest::COMPONENT, loc));
74     ASSERT_EQ(Manifest::COMPONENT,
75               Manifest::GetHigherPriorityLocation(loc, Manifest::COMPONENT));
76 
77     // Check that any source can override a user install. This might change
78     // in the future, in which case this test should be updated.
79     ASSERT_EQ(loc,
80               Manifest::GetHigherPriorityLocation(Manifest::INTERNAL, loc));
81     ASSERT_EQ(loc,
82               Manifest::GetHigherPriorityLocation(loc, Manifest::INTERNAL));
83   }
84 
85   // Check a few interesting cases that we know can happen:
86   ASSERT_EQ(Manifest::EXTERNAL_POLICY_DOWNLOAD,
87             Manifest::GetHigherPriorityLocation(
88                 Manifest::EXTERNAL_POLICY_DOWNLOAD,
89                 Manifest::EXTERNAL_PREF));
90 
91   ASSERT_EQ(Manifest::EXTERNAL_PREF,
92             Manifest::GetHigherPriorityLocation(
93                 Manifest::INTERNAL,
94                 Manifest::EXTERNAL_PREF));
95 }
96 
TEST(ExtensionTest,EnsureNewLinesInExtensionNameAreCollapsed)97 TEST(ExtensionTest, EnsureNewLinesInExtensionNameAreCollapsed) {
98   DictionaryBuilder manifest;
99   std::string unsanitized_name = "Test\n\n\n\n\n\n\n\n\n\n\n\nNew lines\u0085";
100   manifest.Set("name", unsanitized_name)
101       .Set("manifest_version", 2)
102       .Set("description", "some description");
103   scoped_refptr<const Extension> extension =
104       ExtensionBuilder()
105           .SetManifest(manifest.Build())
106           .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
107           .Build();
108   ASSERT_TRUE(extension.get());
109   EXPECT_EQ("TestNew lines", extension->name());
110   // Ensure that non-localized name is not sanitized.
111   EXPECT_EQ(unsanitized_name, extension->non_localized_name());
112 }
113 
TEST(ExtensionTest,EnsureWhitespacesInExtensionNameAreCollapsed)114 TEST(ExtensionTest, EnsureWhitespacesInExtensionNameAreCollapsed) {
115   DictionaryBuilder manifest;
116   std::string unsanitized_name = "Test                        Whitespace";
117   manifest.Set("name", unsanitized_name)
118       .Set("manifest_version", 2)
119       .Set("description", "some description");
120   scoped_refptr<const Extension> extension =
121       ExtensionBuilder()
122           .SetManifest(manifest.Build())
123           .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
124           .Build();
125   ASSERT_TRUE(extension.get());
126   EXPECT_EQ("Test Whitespace", extension->name());
127   // Ensure that non-localized name is not sanitized.
128   EXPECT_EQ(unsanitized_name, extension->non_localized_name());
129 }
130 
131 // TODO(crbug.com/794252): Disallow empty extension names from being locally
132 // loaded.
TEST(ExtensionTest,EmptyName)133 TEST(ExtensionTest, EmptyName) {
134   DictionaryBuilder manifest1;
135   manifest1.Set("name", "")
136       .Set("manifest_version", 2)
137       .Set("description", "some description");
138   scoped_refptr<const Extension> extension =
139       ExtensionBuilder()
140           .SetManifest(manifest1.Build())
141           .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
142           .Build();
143   ASSERT_TRUE(extension.get());
144   EXPECT_EQ("", extension->name());
145 
146   DictionaryBuilder manifest2;
147   manifest2.Set("name", " ")
148       .Set("manifest_version", 2)
149       .Set("description", "some description");
150   extension =
151       ExtensionBuilder()
152           .SetManifest(manifest2.Build())
153           .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
154           .Build();
155   ASSERT_TRUE(extension.get());
156   EXPECT_EQ("", extension->name());
157 }
158 
TEST(ExtensionTest,RTLNameInLTRLocale)159 TEST(ExtensionTest, RTLNameInLTRLocale) {
160   // Test the case when a directional override is the first character.
161   auto run_rtl_test = [](const wchar_t* name, const wchar_t* expected) {
162     SCOPED_TRACE(
163         base::StringPrintf("Name: %ls, Expected: %ls", name, expected));
164     DictionaryBuilder manifest;
165     manifest.Set("name", base::WideToUTF8(name))
166         .Set("manifest_version", 2)
167         .Set("description", "some description")
168         .Set("version",
169              "0.1");  // <NOTE> Moved this here to avoid the MergeManifest call.
170     scoped_refptr<const Extension> extension =
171         ExtensionBuilder().SetManifest(manifest.Build()).Build();
172     ASSERT_TRUE(extension);
173     const int kResourceId = IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE;
174     const base::string16 expected_utf16 = base::WideToUTF16(expected);
175     EXPECT_EQ(l10n_util::GetStringFUTF16(kResourceId, expected_utf16),
176               l10n_util::GetStringFUTF16(kResourceId,
177                                          base::UTF8ToUTF16(extension->name())));
178     EXPECT_EQ(base::WideToUTF8(expected), extension->name());
179   };
180 
181   run_rtl_test(L"\x202emoc.elgoog", L"\x202emoc.elgoog\x202c");
182   run_rtl_test(L"\x202egoogle\x202e.com/\x202eguest",
183                L"\x202egoogle\x202e.com/\x202eguest\x202c\x202c\x202c");
184   run_rtl_test(L"google\x202e.com", L"google\x202e.com\x202c");
185 
186   run_rtl_test(L"كبير Google التطبيق",
187 #if !defined(OS_WIN)
188                L"\x200e\x202bكبير Google التطبيق\x202c\x200e");
189 #else
190                // On Windows for an LTR locale, no changes to the string are
191                // made.
192                L"كبير Google التطبيق");
193 #endif  // !OS_WIN
194 }
195 
TEST(ExtensionTest,GetResourceURLAndPath)196 TEST(ExtensionTest, GetResourceURLAndPath) {
197   scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest",
198       "empty.json");
199   EXPECT_TRUE(extension.get());
200 
201   EXPECT_EQ(extension->url().spec() + "bar/baz.js",
202             Extension::GetResourceURL(extension->url(), "bar/baz.js").spec());
203   EXPECT_EQ(extension->url().spec() + "baz.js",
204             Extension::GetResourceURL(extension->url(),
205                                       "bar/../baz.js").spec());
206   EXPECT_EQ(extension->url().spec() + "baz.js",
207             Extension::GetResourceURL(extension->url(), "../baz.js").spec());
208 
209   // Test that absolute-looking paths ("/"-prefixed) are pasted correctly.
210   EXPECT_EQ(extension->url().spec() + "test.html",
211             extension->GetResourceURL("/test.html").spec());
212 }
213 
TEST(ExtensionTest,GetResource)214 TEST(ExtensionTest, GetResource) {
215   const FilePath valid_path_test_cases[] = {
216     FilePath(FILE_PATH_LITERAL("manifest.json")),
217     FilePath(FILE_PATH_LITERAL("a/b/c/manifest.json")),
218     FilePath(FILE_PATH_LITERAL("com/manifest.json")),
219     FilePath(FILE_PATH_LITERAL("lpt/manifest.json")),
220   };
221   const FilePath invalid_path_test_cases[] = {
222     // Directory name
223     FilePath(FILE_PATH_LITERAL("src/")),
224     // Contains a drive letter specification.
225     FilePath(FILE_PATH_LITERAL("C:\\manifest.json")),
226     // Use backslash '\\' as separator.
227     FilePath(FILE_PATH_LITERAL("a\\b\\c\\manifest.json")),
228     // Reserved Characters with extension
229     FilePath(FILE_PATH_LITERAL("mani>fest.json")),
230     FilePath(FILE_PATH_LITERAL("mani<fest.json")),
231     FilePath(FILE_PATH_LITERAL("mani*fest.json")),
232     FilePath(FILE_PATH_LITERAL("mani:fest.json")),
233     FilePath(FILE_PATH_LITERAL("mani?fest.json")),
234     FilePath(FILE_PATH_LITERAL("mani|fest.json")),
235     // Reserved Characters without extension
236     FilePath(FILE_PATH_LITERAL("mani>fest")),
237     FilePath(FILE_PATH_LITERAL("mani<fest")),
238     FilePath(FILE_PATH_LITERAL("mani*fest")),
239     FilePath(FILE_PATH_LITERAL("mani:fest")),
240     FilePath(FILE_PATH_LITERAL("mani?fest")),
241     FilePath(FILE_PATH_LITERAL("mani|fest")),
242     // Reserved Names with extension.
243     FilePath(FILE_PATH_LITERAL("com1.json")),
244     FilePath(FILE_PATH_LITERAL("com9.json")),
245     FilePath(FILE_PATH_LITERAL("LPT1.json")),
246     FilePath(FILE_PATH_LITERAL("LPT9.json")),
247     FilePath(FILE_PATH_LITERAL("CON.json")),
248     FilePath(FILE_PATH_LITERAL("PRN.json")),
249     FilePath(FILE_PATH_LITERAL("AUX.json")),
250     FilePath(FILE_PATH_LITERAL("NUL.json")),
251     // Reserved Names without extension.
252     FilePath(FILE_PATH_LITERAL("com1")),
253     FilePath(FILE_PATH_LITERAL("com9")),
254     FilePath(FILE_PATH_LITERAL("LPT1")),
255     FilePath(FILE_PATH_LITERAL("LPT9")),
256     FilePath(FILE_PATH_LITERAL("CON")),
257     FilePath(FILE_PATH_LITERAL("PRN")),
258     FilePath(FILE_PATH_LITERAL("AUX")),
259     FilePath(FILE_PATH_LITERAL("NUL")),
260     // Reserved Names as directory.
261     FilePath(FILE_PATH_LITERAL("com1/manifest.json")),
262     FilePath(FILE_PATH_LITERAL("com9/manifest.json")),
263     FilePath(FILE_PATH_LITERAL("LPT1/manifest.json")),
264     FilePath(FILE_PATH_LITERAL("LPT9/manifest.json")),
265     FilePath(FILE_PATH_LITERAL("CON/manifest.json")),
266     FilePath(FILE_PATH_LITERAL("PRN/manifest.json")),
267     FilePath(FILE_PATH_LITERAL("AUX/manifest.json")),
268     FilePath(FILE_PATH_LITERAL("NUL/manifest.json")),
269   };
270 
271   scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest",
272       "empty.json");
273   EXPECT_TRUE(extension.get());
274   for (size_t i = 0; i < base::size(valid_path_test_cases); ++i)
275     EXPECT_TRUE(!extension->GetResource(valid_path_test_cases[i]).empty());
276   for (size_t i = 0; i < base::size(invalid_path_test_cases); ++i)
277     EXPECT_TRUE(extension->GetResource(invalid_path_test_cases[i]).empty());
278 }
279 
TEST(ExtensionTest,GetAbsolutePathNoError)280 TEST(ExtensionTest, GetAbsolutePathNoError) {
281   scoped_refptr<Extension> extension = LoadManifestStrict("absolute_path",
282       "absolute.json");
283   EXPECT_TRUE(extension.get());
284   std::string err;
285   std::vector<InstallWarning> warnings;
286   EXPECT_TRUE(file_util::ValidateExtension(extension.get(), &err, &warnings));
287   EXPECT_EQ(0U, warnings.size());
288 
289   EXPECT_EQ(extension->path().AppendASCII("test.html").value(),
290             extension->GetResource("test.html").GetFilePath().value());
291   EXPECT_EQ(extension->path().AppendASCII("test.js").value(),
292             extension->GetResource("test.js").GetFilePath().value());
293 }
294 
295 
TEST(ExtensionTest,IdIsValid)296 TEST(ExtensionTest, IdIsValid) {
297   EXPECT_TRUE(crx_file::id_util::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
298   EXPECT_TRUE(crx_file::id_util::IdIsValid("pppppppppppppppppppppppppppppppp"));
299   EXPECT_TRUE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnop"));
300   EXPECT_TRUE(crx_file::id_util::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"));
301   EXPECT_FALSE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno"));
302   EXPECT_FALSE(
303       crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnopa"));
304   EXPECT_FALSE(
305       crx_file::id_util::IdIsValid("0123456789abcdef0123456789abcdef"));
306   EXPECT_FALSE(
307       crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnoq"));
308   EXPECT_FALSE(
309       crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno0"));
310 }
311 
312 // This test ensures that the mimetype sniffing code stays in sync with the
313 // actual crx files that we test other parts of the system with.
TEST(ExtensionTest,MimeTypeSniffing)314 TEST(ExtensionTest, MimeTypeSniffing) {
315   auto get_mime_type_from_crx = [](const base::FilePath& file_path) {
316     SCOPED_TRACE(file_path.AsUTF8Unsafe());
317 
318     std::string data;
319     EXPECT_TRUE(base::ReadFileToString(file_path, &data));
320 
321     std::string result;
322     EXPECT_TRUE(net::SniffMimeType(
323         data, GURL("http://www.example.com/foo.crx"), std::string(),
324         net::ForceSniffFileUrlsForHtml::kDisabled, &result));
325 
326     return result;
327   };
328 
329   base::FilePath dir_path;
330   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &dir_path));
331   dir_path = dir_path.AppendASCII("extensions");
332 
333   // First, test an extension packed a long time ago (but in this galaxy).
334   // Specifically, this package is using the crx2 format, whereas modern chrome
335   // uses crx3.
336   EXPECT_EQ(
337       Extension::kMimeType,
338       get_mime_type_from_crx(dir_path.AppendASCII("legacy_crx_package.crx")));
339 
340   // Then, an extension whose crx has a bad magic number (it should be Cr24).
341   EXPECT_EQ("application/octet-stream",
342             get_mime_type_from_crx(dir_path.AppendASCII("bad_magic.crx")));
343 
344   // Finally, an extension that we pack right. This. Instant.
345   // This verifies that the modern extensions Chrome packs are always
346   // recognized as the extension mime type.
347   // Regression test for https://crbug.com/831284.
348   TestExtensionDir test_dir;
349   test_dir.WriteManifest(R"(
350       {
351         "name": "New extension",
352         "version": "0.2",
353         "manifest_version": 2
354       })");
355   EXPECT_EQ(Extension::kMimeType, get_mime_type_from_crx(test_dir.Pack()));
356 }
357 
TEST(ExtensionTest,WantsFileAccess)358 TEST(ExtensionTest, WantsFileAccess) {
359   scoped_refptr<Extension> extension;
360   GURL file_url("file:///etc/passwd");
361 
362   // Ignore the policy delegate for this test.
363   PermissionsData::SetPolicyDelegate(NULL);
364 
365   // <all_urls> permission
366   extension = LoadManifest("permissions", "permissions_all_urls.json");
367   EXPECT_TRUE(extension->wants_file_access());
368   EXPECT_FALSE(
369       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
370   extension = LoadManifest(
371       "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS);
372   EXPECT_TRUE(extension->wants_file_access());
373   EXPECT_TRUE(
374       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
375 
376   // file:///* permission
377   extension = LoadManifest("permissions", "permissions_file_scheme.json");
378   EXPECT_TRUE(extension->wants_file_access());
379   EXPECT_FALSE(
380       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
381   extension = LoadManifest("permissions",
382                            "permissions_file_scheme.json",
383                            Extension::ALLOW_FILE_ACCESS);
384   EXPECT_TRUE(extension->wants_file_access());
385   EXPECT_TRUE(
386       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
387 
388   // http://* permission
389   extension = LoadManifest("permissions", "permissions_http_scheme.json");
390   EXPECT_FALSE(extension->wants_file_access());
391   EXPECT_FALSE(
392       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
393   extension = LoadManifest("permissions",
394                            "permissions_http_scheme.json",
395                            Extension::ALLOW_FILE_ACCESS);
396   EXPECT_FALSE(extension->wants_file_access());
397   EXPECT_FALSE(
398       extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
399 
400   // <all_urls> content script match
401   extension = LoadManifest("permissions", "content_script_all_urls.json");
402   EXPECT_TRUE(extension->wants_file_access());
403   EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
404       file_url, -1, nullptr));
405   extension = LoadManifest("permissions", "content_script_all_urls.json",
406       Extension::ALLOW_FILE_ACCESS);
407   EXPECT_TRUE(extension->wants_file_access());
408   EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage(
409       file_url, -1, nullptr));
410 
411   // file:///* content script match
412   extension = LoadManifest("permissions", "content_script_file_scheme.json");
413   EXPECT_TRUE(extension->wants_file_access());
414   EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
415       file_url, -1, nullptr));
416   extension = LoadManifest("permissions", "content_script_file_scheme.json",
417       Extension::ALLOW_FILE_ACCESS);
418   EXPECT_TRUE(extension->wants_file_access());
419   EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage(
420       file_url, -1, nullptr));
421 
422   // http://* content script match
423   extension = LoadManifest("permissions", "content_script_http_scheme.json");
424   EXPECT_FALSE(extension->wants_file_access());
425   EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
426       file_url, -1, nullptr));
427   extension = LoadManifest("permissions", "content_script_http_scheme.json",
428       Extension::ALLOW_FILE_ACCESS);
429   EXPECT_FALSE(extension->wants_file_access());
430   EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
431       file_url, -1, nullptr));
432 }
433 
TEST(ExtensionTest,ExtraFlags)434 TEST(ExtensionTest, ExtraFlags) {
435   scoped_refptr<Extension> extension;
436   extension = LoadManifest("app", "manifest.json", Extension::FROM_WEBSTORE);
437   EXPECT_TRUE(extension->from_webstore());
438 
439   extension = LoadManifest("app", "manifest.json", Extension::FROM_BOOKMARK);
440   EXPECT_TRUE(extension->from_bookmark());
441 
442   extension = LoadManifest("app", "manifest.json", Extension::NO_FLAGS);
443   EXPECT_FALSE(extension->from_bookmark());
444   EXPECT_FALSE(extension->from_webstore());
445 }
446 
447 }  // namespace extensions
448