1561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// Use of this source code is governed by a BSD-style license that can be
3561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// found in the LICENSE file.
4561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
5561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include <algorithm>
6561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
7561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/files/file_util.h"
8561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/files/scoped_temp_dir.h"
9561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/path_service.h"
10561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "components/crx_file/id_util.h"
11561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "extensions/common/constants.h"
12561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "extensions/common/extension_paths.h"
13561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "extensions/common/extension_resource.h"
14561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "testing/gtest/include/gtest/gtest.h"
15561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "ui/base/l10n/l10n_util.h"
16561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
17561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesnamespace extensions {
18561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan KamathTEST(ExtensionResourceTest, CreateEmptyResource) {
208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath  ExtensionResource resource;
21561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
22561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_TRUE(resource.extension_root().empty());
23561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_TRUE(resource.relative_path().empty());
24561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_TRUE(resource.GetFilePath().empty());
25561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
26561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
27561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesconst base::FilePath::StringType ToLower(
28561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes    const base::FilePath::StringType& in_str) {
29561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  base::FilePath::StringType str(in_str);
30561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  std::transform(str.begin(), str.end(), str.begin(), tolower);
31561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  return str;
32561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
33561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
34561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesTEST(ExtensionResourceTest, CreateWithMissingResourceOnDisk) {
35561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  base::FilePath root_path;
36561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &root_path));
37561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  base::FilePath relative_path;
38561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  relative_path = relative_path.AppendASCII("cira.js");
39561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  std::string extension_id = crx_file::id_util::GenerateId("test");
40561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  ExtensionResource resource(extension_id, root_path, relative_path);
41561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
42561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  // The path doesn't exist on disk, we will be returned an empty path.
43561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_EQ(root_path.value(), resource.extension_root().value());
44561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_EQ(relative_path.value(), resource.relative_path().value());
45561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  EXPECT_TRUE(resource.GetFilePath().empty());
46561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}
47561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
48561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesTEST(ExtensionResourceTest, ResourcesOutsideOfPath) {
49  base::ScopedTempDir temp;
50  ASSERT_TRUE(temp.CreateUniqueTempDir());
51
52  base::FilePath inner_dir = temp.path().AppendASCII("directory");
53  ASSERT_TRUE(base::CreateDirectory(inner_dir));
54  base::FilePath sub_dir = inner_dir.AppendASCII("subdir");
55  ASSERT_TRUE(base::CreateDirectory(sub_dir));
56  base::FilePath inner_file = inner_dir.AppendASCII("inner");
57  base::FilePath outer_file = temp.path().AppendASCII("outer");
58  ASSERT_TRUE(base::WriteFile(outer_file, "X", 1));
59  ASSERT_TRUE(base::WriteFile(inner_file, "X", 1));
60  std::string extension_id = crx_file::id_util::GenerateId("test");
61
62#if defined(OS_POSIX)
63  base::FilePath symlink_file = inner_dir.AppendASCII("symlink");
64  base::CreateSymbolicLink(
65      base::FilePath().AppendASCII("..").AppendASCII("outer"),
66      symlink_file);
67#endif
68
69  // A non-packing extension should be able to access the file within the
70  // directory.
71  ExtensionResource r1(extension_id, inner_dir,
72                       base::FilePath().AppendASCII("inner"));
73  EXPECT_FALSE(r1.GetFilePath().empty());
74
75  // ... but not a relative path that walks out of |inner_dir|.
76  ExtensionResource r2(extension_id, inner_dir,
77                       base::FilePath().AppendASCII("..").AppendASCII("outer"));
78  EXPECT_TRUE(r2.GetFilePath().empty());
79
80  // A packing extension should also be able to access the file within the
81  // directory.
82  ExtensionResource r3(extension_id, inner_dir,
83                       base::FilePath().AppendASCII("inner"));
84  r3.set_follow_symlinks_anywhere();
85  EXPECT_FALSE(r3.GetFilePath().empty());
86
87  // ... but, again, not a relative path that walks out of |inner_dir|.
88  ExtensionResource r4(extension_id, inner_dir,
89                       base::FilePath().AppendASCII("..").AppendASCII("outer"));
90  r4.set_follow_symlinks_anywhere();
91  EXPECT_TRUE(r4.GetFilePath().empty());
92
93  // ... and not even when clever current-directory syntax is present. Note
94  // that the path for this test case can't start with the current directory
95  // component due to quirks in FilePath::Append(), and the path must exist.
96  ExtensionResource r4a(
97      extension_id, inner_dir,
98      base::FilePath().AppendASCII("subdir").AppendASCII(".").AppendASCII("..").
99      AppendASCII("..").AppendASCII("outer"));
100  r4a.set_follow_symlinks_anywhere();
101  EXPECT_TRUE(r4a.GetFilePath().empty());
102
103#if defined(OS_POSIX)
104  // The non-packing extension should also not be able to access a resource that
105  // symlinks out of the directory.
106  ExtensionResource r5(extension_id, inner_dir,
107                       base::FilePath().AppendASCII("symlink"));
108  EXPECT_TRUE(r5.GetFilePath().empty());
109
110  // ... but a packing extension can.
111  ExtensionResource r6(extension_id, inner_dir,
112                       base::FilePath().AppendASCII("symlink"));
113  r6.set_follow_symlinks_anywhere();
114  EXPECT_FALSE(r6.GetFilePath().empty());
115#endif
116}
117
118TEST(ExtensionResourceTest, CreateWithAllResourcesOnDisk) {
119  base::ScopedTempDir temp;
120  ASSERT_TRUE(temp.CreateUniqueTempDir());
121
122  // Create resource in the extension root.
123  const char* filename = "res.ico";
124  base::FilePath root_resource = temp.path().AppendASCII(filename);
125  std::string data = "some foo";
126  ASSERT_TRUE(base::WriteFile(root_resource, data.c_str(), data.length()));
127
128  // Create l10n resources (for current locale and its parents).
129  base::FilePath l10n_path =
130      temp.path().Append(kLocaleFolder);
131  ASSERT_TRUE(base::CreateDirectory(l10n_path));
132
133  std::vector<std::string> locales;
134  l10n_util::GetParentLocales(l10n_util::GetApplicationLocale(std::string()),
135                              &locales);
136  ASSERT_FALSE(locales.empty());
137  for (size_t i = 0; i < locales.size(); i++) {
138    base::FilePath make_path;
139    make_path = l10n_path.AppendASCII(locales[i]);
140    ASSERT_TRUE(base::CreateDirectory(make_path));
141    ASSERT_TRUE(base::WriteFile(make_path.AppendASCII(filename),
142        data.c_str(), data.length()));
143  }
144
145  base::FilePath path;
146  std::string extension_id = crx_file::id_util::GenerateId("test");
147  ExtensionResource resource(extension_id, temp.path(),
148                             base::FilePath().AppendASCII(filename));
149  base::FilePath resolved_path = resource.GetFilePath();
150
151  base::FilePath expected_path;
152  // Expect default path only, since fallback logic is disabled.
153  // See http://crbug.com/27359.
154  expected_path = base::MakeAbsoluteFilePath(root_resource);
155  ASSERT_FALSE(expected_path.empty());
156
157  EXPECT_EQ(ToLower(expected_path.value()), ToLower(resolved_path.value()));
158  EXPECT_EQ(ToLower(temp.path().value()),
159            ToLower(resource.extension_root().value()));
160  EXPECT_EQ(ToLower(base::FilePath().AppendASCII(filename).value()),
161            ToLower(resource.relative_path().value()));
162}
163
164}  // namespace extensions
165