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