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
29using extension_test_util::LoadManifest;
30using extension_test_util::LoadManifestStrict;
31using base::FilePath;
32
33namespace extensions {
34
35// We persist location values in the preferences, so this is a sanity test that
36// someone doesn't accidentally change them.
37TEST(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
50TEST(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
87TEST(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
105TEST(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
171TEST(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
187TEST(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.
206TEST(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
234TEST(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
310TEST(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