1 // Copyright 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 "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
6
7 #include <memory>
8
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "components/version_info/version_info.h"
14 #include "extensions/common/error_utils.h"
15 #include "extensions/common/extension.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/manifest_url_handlers.h"
18 #include "extensions/common/value_builder.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace {
22
23 const char kManifest[] =
24 "{"
25 " \"version\" : \"1.0.0.0\","
26 " \"manifest_version\" : 2,"
27 " \"name\" : \"Test\","
28 " \"chrome_settings_overrides\" : {"
29 " \"homepage\" : \"http://www.homepage.com\","
30 " \"search_provider\" : {"
31 " \"name\" : \"first\","
32 " \"keyword\" : \"firstkey\","
33 " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\","
34 " \"favicon_url\" : \"http://www.foo.com/favicon.ico\","
35 " \"suggest_url\" : \"http://www.foo.com/s?q={searchTerms}\","
36 " \"encoding\" : \"UTF-8\","
37 " \"is_default\" : true"
38 " },"
39 " \"startup_pages\" : [\"http://www.startup.com\"]"
40 " }"
41 "}";
42
43 const char kPrepopulatedManifest[] =
44 "{"
45 " \"version\" : \"1.0.0.0\","
46 " \"manifest_version\" : 2,"
47 " \"name\" : \"Test\","
48 " \"chrome_settings_overrides\" : {"
49 " \"search_provider\" : {"
50 " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\","
51 " \"prepopulated_id\" : 3,"
52 " \"is_default\" : true"
53 " }"
54 " }"
55 "}";
56
57 const char kBrokenManifestEmpty[] = R"(
58 {
59 "version" : "1.0.0.0",
60 "manifest_version" : 2,
61 "name" : "Test",
62 "chrome_settings_overrides" : {}
63 })";
64
65 const char kBrokenManifestHomepage[] = R"(
66 {
67 "version" : "1.0.0.0",
68 "manifest_version" : 2,
69 "name" : "Test",
70 "chrome_settings_overrides" : {
71 "homepage" : "{invalid}"
72 }
73 })";
74
75 const char kBrokenManifestStartupPages[] = R"(
76 {
77 "version" : "1.0.0.0",
78 "manifest_version" : 2,
79 "name" : "Test",
80 "chrome_settings_overrides" : {
81 "startup_pages" : ["{invalid}"]
82 }
83 })";
84
85 const char kManifestBrokenHomepageButCorrectStartupPages[] = R"(
86 {
87 "version" : "1.0.0.0",
88 "manifest_version" : 2,
89 "name" : "Test",
90 "chrome_settings_overrides" : {
91 "homepage" : "{invalid}",
92 "startup_pages" : ["http://www.startup.com"]
93 }
94 })";
95
96 const char kManifestBrokenStartupPagesButCorrectHomepage[] = R"(
97 {
98 "version" : "1.0.0.0",
99 "manifest_version" : 2,
100 "name" : "Test",
101 "chrome_settings_overrides" : {
102 "homepage": "http://www.homepage.com",
103 "startup_pages" : ["{invalid}"]
104 }
105 })";
106
107 using extensions::DictionaryBuilder;
108 using extensions::Extension;
109 using extensions::Manifest;
110 using extensions::SettingsOverrides;
111 using extensions::api::manifest_types::ChromeSettingsOverrides;
112 namespace manifest_keys = extensions::manifest_keys;
113
CreateExtension(const base::DictionaryValue & manifest,std::string * error)114 scoped_refptr<Extension> CreateExtension(const base::DictionaryValue& manifest,
115 std::string* error) {
116 scoped_refptr<Extension> extension = Extension::Create(
117 base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
118 Manifest::INVALID_LOCATION, manifest, Extension::NO_FLAGS, error);
119 return extension;
120 }
121
CreateExtension(base::StringPiece manifest,std::string * error)122 scoped_refptr<Extension> CreateExtension(base::StringPiece manifest,
123 std::string* error) {
124 JSONStringValueDeserializer json(manifest);
125 std::unique_ptr<base::Value> root(json.Deserialize(nullptr, error));
126 if (!root) {
127 ADD_FAILURE() << "Could not deserialize manifest";
128 return nullptr;
129 }
130 if (!root->is_dict()) {
131 ADD_FAILURE() << "Manifest isn't a Dictionary";
132 return nullptr;
133 }
134 return CreateExtension(*static_cast<base::DictionaryValue*>(root.get()),
135 error);
136 }
137
CreateExtensionWithSearchProvider(std::unique_ptr<base::DictionaryValue> search_provider,std::string * error)138 scoped_refptr<Extension> CreateExtensionWithSearchProvider(
139 std::unique_ptr<base::DictionaryValue> search_provider,
140 std::string* error) {
141 DictionaryBuilder manifest;
142 manifest.Set("name", "name")
143 .Set("manifest_version", 2)
144 .Set("version", "0.1")
145 .Set("description", "desc")
146 .Set("chrome_settings_overrides",
147 DictionaryBuilder()
148 .Set("search_provider", std::move(search_provider))
149 .Build());
150 return CreateExtension(*manifest.Build(), error);
151 }
152
TEST(OverrideSettingsTest,ParseManifest)153 TEST(OverrideSettingsTest, ParseManifest) {
154 std::string error;
155 scoped_refptr<Extension> extension = CreateExtension(kManifest, &error);
156 ASSERT_TRUE(extension.get());
157 #if defined(OS_WIN) || defined(OS_MAC)
158 ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
159
160 SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
161 extension->GetManifestData(manifest_keys::kSettingsOverride));
162 ASSERT_TRUE(settings_override);
163 ASSERT_TRUE(settings_override->search_engine);
164 EXPECT_TRUE(settings_override->search_engine->is_default);
165 const ChromeSettingsOverrides::SearchProvider* search_engine =
166 settings_override->search_engine.get();
167 EXPECT_EQ("first", *search_engine->name);
168 EXPECT_EQ("firstkey", *search_engine->keyword);
169 EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", search_engine->search_url);
170 EXPECT_EQ("http://www.foo.com/favicon.ico", *search_engine->favicon_url);
171 EXPECT_EQ("http://www.foo.com/s?q={searchTerms}",
172 *search_engine->suggest_url);
173 EXPECT_EQ("UTF-8", *search_engine->encoding);
174
175 EXPECT_EQ(std::vector<GURL>(1, GURL("http://www.startup.com")),
176 settings_override->startup_pages);
177
178 ASSERT_TRUE(settings_override->homepage);
179 EXPECT_EQ(GURL("http://www.homepage.com"), *settings_override->homepage);
180 #else
181 EXPECT_FALSE(
182 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
183 #endif
184 }
185
TEST(OverrideSettingsTest,ParsePrepopulatedId)186 TEST(OverrideSettingsTest, ParsePrepopulatedId) {
187 std::string error;
188 scoped_refptr<Extension> extension =
189 CreateExtension(kPrepopulatedManifest, &error);
190 ASSERT_TRUE(extension.get());
191 #if defined(OS_WIN) || defined(OS_MAC)
192 ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
193
194 SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
195 extension->GetManifestData(manifest_keys::kSettingsOverride));
196 ASSERT_TRUE(settings_override);
197 ASSERT_TRUE(settings_override->search_engine);
198 EXPECT_TRUE(settings_override->search_engine->is_default);
199 const ChromeSettingsOverrides::SearchProvider* search_engine =
200 settings_override->search_engine.get();
201 ASSERT_TRUE(search_engine->prepopulated_id);
202 EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", search_engine->search_url);
203 EXPECT_EQ(3, *search_engine->prepopulated_id);
204 #else
205 EXPECT_FALSE(
206 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
207 #endif
208 }
209
TEST(OverrideSettingsTest,ParseManifestBrokenHomepageButCorrectStartupPages)210 TEST(OverrideSettingsTest, ParseManifestBrokenHomepageButCorrectStartupPages) {
211 std::string error;
212 scoped_refptr<Extension> extension =
213 CreateExtension(kManifestBrokenHomepageButCorrectStartupPages, &error);
214 ASSERT_TRUE(extension.get());
215 #if defined(OS_WIN) || defined(OS_MAC)
216 ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
217
218 SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
219 extension->GetManifestData(manifest_keys::kSettingsOverride));
220 ASSERT_TRUE(settings_override);
221 EXPECT_EQ(std::vector<GURL>(1, GURL("http://www.startup.com")),
222 settings_override->startup_pages);
223 #else
224 EXPECT_FALSE(
225 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
226 #endif
227 }
228
TEST(OverrideSettingsTest,ParseManifestBrokenStartupPagesButCorrectHomepage)229 TEST(OverrideSettingsTest, ParseManifestBrokenStartupPagesButCorrectHomepage) {
230 std::string error;
231 scoped_refptr<Extension> extension =
232 CreateExtension(kManifestBrokenStartupPagesButCorrectHomepage, &error);
233 ASSERT_TRUE(extension.get());
234 #if defined(OS_WIN) || defined(OS_MAC)
235 ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
236 SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
237 extension->GetManifestData(manifest_keys::kSettingsOverride));
238 ASSERT_TRUE(settings_override);
239 EXPECT_TRUE(settings_override->startup_pages.empty());
240 EXPECT_EQ(GURL("http://www.homepage.com"), *settings_override->homepage);
241 #else
242 EXPECT_FALSE(
243 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
244 #endif
245 }
246
TEST(OverrideSettingsTest,ParseBrokenManifestEmptySettingsOverride)247 TEST(OverrideSettingsTest, ParseBrokenManifestEmptySettingsOverride) {
248 std::string error;
249 scoped_refptr<Extension> extension =
250 CreateExtension(kBrokenManifestEmpty, &error);
251 #if defined(OS_WIN) || defined(OS_MAC)
252 EXPECT_FALSE(extension.get());
253 EXPECT_EQ(
254 extensions::ErrorUtils::FormatErrorMessage(
255 extensions::manifest_errors::kInvalidEmptyDictionary,
256 extensions::manifest_keys::kSettingsOverride),
257 error);
258 #else
259 ASSERT_TRUE(extension.get());
260 EXPECT_FALSE(
261 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
262 #endif
263 }
264
TEST(OverrideSettingsTest,ParseBrokenManifestHomepage)265 TEST(OverrideSettingsTest, ParseBrokenManifestHomepage) {
266 std::string error;
267 scoped_refptr<Extension> extension =
268 CreateExtension(kBrokenManifestHomepage, &error);
269 #if defined(OS_WIN) || defined(OS_MAC)
270 EXPECT_FALSE(extension.get());
271 EXPECT_EQ(extensions::ErrorUtils::FormatErrorMessage(
272 extensions::manifest_errors::kInvalidHomepageOverrideURL,
273 "{invalid}"),
274 error);
275 #else
276 ASSERT_TRUE(extension.get());
277 EXPECT_FALSE(
278 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
279 #endif
280 }
281
TEST(OverrideSettingsTest,ParseBrokenManifestStartupPages)282 TEST(OverrideSettingsTest, ParseBrokenManifestStartupPages) {
283 std::string error;
284 scoped_refptr<Extension> extension =
285 CreateExtension(kBrokenManifestStartupPages, &error);
286 #if defined(OS_WIN) || defined(OS_MAC)
287 EXPECT_FALSE(extension.get());
288 EXPECT_EQ(
289 extensions::ErrorUtils::FormatErrorMessage(
290 extensions::manifest_errors::kInvalidStartupOverrideURL, "{invalid}"),
291 error);
292 #else
293 ASSERT_TRUE(extension.get());
294 EXPECT_FALSE(
295 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
296 #endif
297 }
298
TEST(OverrideSettingsTest,SearchProviderMissingKeys)299 TEST(OverrideSettingsTest, SearchProviderMissingKeys) {
300 struct KeyValue {
301 const char* key;
302 const char* value;
303 } kMandatorySearchProviderKeyValues[] = {
304 {"name", "first"},
305 {"keyword", "firstkey"},
306 {"encoding", "UTF-8"},
307 {"favicon_url", "http://www.foo.com/favicon.ico"},
308 };
309
310 DictionaryBuilder search_provider;
311 search_provider.Set("search_url", "http://www.foo.com/s?q={searchTerms}")
312 .Set("is_default", true);
313 for (const KeyValue& kv : kMandatorySearchProviderKeyValues)
314 search_provider.Set(kv.key, kv.value);
315 std::unique_ptr<base::DictionaryValue> search_provider_with_all_keys_dict =
316 search_provider.Build();
317
318 // Missing all keys from |kMandatorySearchProviderValues|.
319 for (const KeyValue& kv : kMandatorySearchProviderKeyValues) {
320 SCOPED_TRACE(testing::Message()
321 << "key = " << kv.key << " value = " << kv.value);
322 // Build a search provider entry with |kv.key| missing:
323 std::unique_ptr<base::DictionaryValue> provider_with_missing_key =
324 base::DictionaryValue::From(base::Value::ToUniquePtrValue(
325 search_provider_with_all_keys_dict->Clone()));
326 ASSERT_TRUE(provider_with_missing_key->RemovePath(kv.key));
327
328 std::string error;
329 scoped_refptr<Extension> extension = CreateExtensionWithSearchProvider(
330 std::move(provider_with_missing_key), &error);
331 #if defined(OS_WIN) || defined(OS_MAC)
332 EXPECT_FALSE(extension.get());
333 EXPECT_EQ(extensions::ErrorUtils::FormatErrorMessage(
334 extensions::manifest_errors::kInvalidSearchEngineMissingKeys,
335 kv.key),
336 error);
337 #else
338 ASSERT_TRUE(extension.get());
339 EXPECT_FALSE(
340 extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
341 #endif
342 }
343 }
344
345 } // namespace
346