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