1 // Copyright (c) 2012 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 <algorithm>
8
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/path_service.h"
12 #include "build/build_config.h"
13 #include "components/crx_file/id_util.h"
14 #include "extensions/common/constants.h"
15 #include "extensions/common/extension_paths.h"
16 #include "extensions/common/extension_resource.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/base/l10n/l10n_util.h"
19
20 namespace extensions {
21
TEST(ExtensionResourceTest,CreateEmptyResource)22 TEST(ExtensionResourceTest, CreateEmptyResource) {
23 ExtensionResource resource;
24
25 EXPECT_TRUE(resource.extension_root().empty());
26 EXPECT_TRUE(resource.relative_path().empty());
27 EXPECT_TRUE(resource.GetFilePath().empty());
28 }
29
ToLower(const base::FilePath::StringType & in_str)30 const base::FilePath::StringType ToLower(
31 const base::FilePath::StringType& in_str) {
32 base::FilePath::StringType str(in_str);
33 std::transform(str.begin(), str.end(), str.begin(), tolower);
34 return str;
35 }
36
TEST(ExtensionResourceTest,CreateWithMissingResourceOnDisk)37 TEST(ExtensionResourceTest, CreateWithMissingResourceOnDisk) {
38 base::FilePath root_path;
39 ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &root_path));
40 base::FilePath relative_path;
41 relative_path = relative_path.AppendASCII("cira.js");
42 std::string extension_id = crx_file::id_util::GenerateId("test");
43 ExtensionResource resource(extension_id, root_path, relative_path);
44
45 // The path doesn't exist on disk, we will be returned an empty path.
46 EXPECT_EQ(root_path.value(), resource.extension_root().value());
47 EXPECT_EQ(relative_path.value(), resource.relative_path().value());
48 EXPECT_TRUE(resource.GetFilePath().empty());
49 }
50
TEST(ExtensionResourceTest,ResourcesOutsideOfPath)51 TEST(ExtensionResourceTest, ResourcesOutsideOfPath) {
52 base::ScopedTempDir temp;
53 ASSERT_TRUE(temp.CreateUniqueTempDir());
54
55 base::FilePath inner_dir = temp.GetPath().AppendASCII("directory");
56 ASSERT_TRUE(base::CreateDirectory(inner_dir));
57 base::FilePath sub_dir = inner_dir.AppendASCII("subdir");
58 ASSERT_TRUE(base::CreateDirectory(sub_dir));
59 base::FilePath inner_file = inner_dir.AppendASCII("inner");
60 base::FilePath outer_file = temp.GetPath().AppendASCII("outer");
61 ASSERT_EQ(1, base::WriteFile(outer_file, "X", 1));
62 ASSERT_EQ(1, base::WriteFile(inner_file, "X", 1));
63 std::string extension_id = crx_file::id_util::GenerateId("test");
64
65 #if defined(OS_POSIX)
66 base::FilePath symlink_file = inner_dir.AppendASCII("symlink");
67 base::CreateSymbolicLink(
68 base::FilePath().AppendASCII("..").AppendASCII("outer"),
69 symlink_file);
70 #endif
71
72 // A non-packing extension should be able to access the file within the
73 // directory.
74 ExtensionResource r1(extension_id, inner_dir,
75 base::FilePath().AppendASCII("inner"));
76 EXPECT_FALSE(r1.GetFilePath().empty());
77
78 // ... but not a relative path that walks out of |inner_dir|.
79 ExtensionResource r2(extension_id, inner_dir,
80 base::FilePath().AppendASCII("..").AppendASCII("outer"));
81 EXPECT_TRUE(r2.GetFilePath().empty());
82
83 // A packing extension should also be able to access the file within the
84 // directory.
85 ExtensionResource r3(extension_id, inner_dir,
86 base::FilePath().AppendASCII("inner"));
87 r3.set_follow_symlinks_anywhere();
88 EXPECT_FALSE(r3.GetFilePath().empty());
89
90 // ... but, again, not a relative path that walks out of |inner_dir|.
91 ExtensionResource r4(extension_id, inner_dir,
92 base::FilePath().AppendASCII("..").AppendASCII("outer"));
93 r4.set_follow_symlinks_anywhere();
94 EXPECT_TRUE(r4.GetFilePath().empty());
95
96 // ... and not even when clever current-directory syntax is present. Note
97 // that the path for this test case can't start with the current directory
98 // component due to quirks in FilePath::Append(), and the path must exist.
99 ExtensionResource r4a(
100 extension_id, inner_dir,
101 base::FilePath().AppendASCII("subdir").AppendASCII(".").AppendASCII("..").
102 AppendASCII("..").AppendASCII("outer"));
103 r4a.set_follow_symlinks_anywhere();
104 EXPECT_TRUE(r4a.GetFilePath().empty());
105
106 #if defined(OS_POSIX)
107 // The non-packing extension should also not be able to access a resource that
108 // symlinks out of the directory.
109 ExtensionResource r5(extension_id, inner_dir,
110 base::FilePath().AppendASCII("symlink"));
111 EXPECT_TRUE(r5.GetFilePath().empty());
112
113 // ... but a packing extension can.
114 ExtensionResource r6(extension_id, inner_dir,
115 base::FilePath().AppendASCII("symlink"));
116 r6.set_follow_symlinks_anywhere();
117 EXPECT_FALSE(r6.GetFilePath().empty());
118 #endif
119 }
120
TEST(ExtensionResourceTest,CreateWithAllResourcesOnDisk)121 TEST(ExtensionResourceTest, CreateWithAllResourcesOnDisk) {
122 base::ScopedTempDir temp;
123 ASSERT_TRUE(temp.CreateUniqueTempDir());
124
125 // Create resource in the extension root.
126 const char* filename = "res.ico";
127 base::FilePath root_resource = temp.GetPath().AppendASCII(filename);
128 std::string data = "some foo";
129 ASSERT_EQ(static_cast<int>(data.length()),
130 base::WriteFile(root_resource, data.c_str(), data.length()));
131
132 // Create l10n resources (for current locale and its parents).
133 base::FilePath l10n_path = temp.GetPath().Append(kLocaleFolder);
134 ASSERT_TRUE(base::CreateDirectory(l10n_path));
135
136 std::vector<std::string> locales;
137 l10n_util::GetParentLocales(l10n_util::GetApplicationLocale(std::string()),
138 &locales);
139 ASSERT_FALSE(locales.empty());
140 for (size_t i = 0; i < locales.size(); i++) {
141 base::FilePath make_path;
142 make_path = l10n_path.AppendASCII(locales[i]);
143 ASSERT_TRUE(base::CreateDirectory(make_path));
144 ASSERT_EQ(static_cast<int>(data.length()),
145 base::WriteFile(make_path.AppendASCII(filename), data.c_str(),
146 data.length()));
147 }
148
149 base::FilePath path;
150 std::string extension_id = crx_file::id_util::GenerateId("test");
151 ExtensionResource resource(extension_id, temp.GetPath(),
152 base::FilePath().AppendASCII(filename));
153 const base::FilePath& resolved_path = resource.GetFilePath();
154
155 base::FilePath expected_path;
156 // Expect default path only, since fallback logic is disabled.
157 // See http://crbug.com/27359.
158 expected_path = base::MakeAbsoluteFilePath(root_resource);
159 ASSERT_FALSE(expected_path.empty());
160
161 EXPECT_EQ(ToLower(expected_path.value()), ToLower(resolved_path.value()));
162 EXPECT_EQ(ToLower(temp.GetPath().value()),
163 ToLower(resource.extension_root().value()));
164 EXPECT_EQ(ToLower(base::FilePath().AppendASCII(filename).value()),
165 ToLower(resource.relative_path().value()));
166 }
167
168 } // namespace extensions
169