1 // Copyright (c) 2011 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/extension.h"
6
7 #if defined(TOOLKIT_GTK)
8 #include <gtk/gtk.h>
9 #endif
10
11 #include "base/format_macros.h"
12 #include "base/file_path.h"
13 #include "base/file_util.h"
14 #include "base/i18n/rtl.h"
15 #include "base/path_service.h"
16 #include "base/string_number_conversions.h"
17 #include "base/string_util.h"
18 #include "base/utf_string_conversions.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/extensions/extension_action.h"
21 #include "chrome/common/extensions/extension_constants.h"
22 #include "chrome/common/extensions/extension_error_utils.h"
23 #include "chrome/common/extensions/extension_resource.h"
24 #include "chrome/common/url_constants.h"
25 #include "content/common/json_value_serializer.h"
26 #include "googleurl/src/gurl.h"
27 #include "net/base/mime_sniffer.h"
28 #include "skia/ext/image_operations.h"
29 #include "chrome/test/ui_test_utils.h"
30 #include "net/base/mock_host_resolver.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/skia/include/core/SkBitmap.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/gfx/codec/png_codec.h"
35
36 namespace keys = extension_manifest_keys;
37 namespace values = extension_manifest_values;
38 namespace errors = extension_manifest_errors;
39
40 namespace {
41
CompareLists(const std::vector<std::string> & expected,const std::vector<std::string> & actual)42 void CompareLists(const std::vector<std::string>& expected,
43 const std::vector<std::string>& actual) {
44 ASSERT_EQ(expected.size(), actual.size());
45
46 for (size_t i = 0; i < expected.size(); ++i) {
47 EXPECT_EQ(expected[i], actual[i]);
48 }
49 }
50
AddPattern(ExtensionExtent * extent,const std::string & pattern)51 static void AddPattern(ExtensionExtent* extent, const std::string& pattern) {
52 int schemes = URLPattern::SCHEME_ALL;
53 extent->AddPattern(URLPattern(schemes, pattern));
54 }
55
56 }
57
58 class ExtensionTest : public testing::Test {
59 };
60
61 // We persist location values in the preferences, so this is a sanity test that
62 // someone doesn't accidentally change them.
TEST(ExtensionTest,LocationValuesTest)63 TEST(ExtensionTest, LocationValuesTest) {
64 ASSERT_EQ(0, Extension::INVALID);
65 ASSERT_EQ(1, Extension::INTERNAL);
66 ASSERT_EQ(2, Extension::EXTERNAL_PREF);
67 ASSERT_EQ(3, Extension::EXTERNAL_REGISTRY);
68 ASSERT_EQ(4, Extension::LOAD);
69 ASSERT_EQ(5, Extension::COMPONENT);
70 ASSERT_EQ(6, Extension::EXTERNAL_PREF_DOWNLOAD);
71 ASSERT_EQ(7, Extension::EXTERNAL_POLICY_DOWNLOAD);
72 }
73
TEST(ExtensionTest,LocationPriorityTest)74 TEST(ExtensionTest, LocationPriorityTest) {
75 for (int i = 0; i < Extension::NUM_LOCATIONS; i++) {
76 Extension::Location loc = static_cast<Extension::Location>(i);
77
78 // INVALID is not a valid location.
79 if (loc == Extension::INVALID)
80 continue;
81
82 // Comparing a location that has no rank will hit a CHECK. Do a
83 // compare with every valid location, to be sure each one is covered.
84
85 // Check that no install source can override a componenet extension.
86 ASSERT_EQ(Extension::COMPONENT,
87 Extension::GetHigherPriorityLocation(Extension::COMPONENT, loc));
88 ASSERT_EQ(Extension::COMPONENT,
89 Extension::GetHigherPriorityLocation(loc, Extension::COMPONENT));
90
91 // Check that any source can override a user install. This might change
92 // in the future, in which case this test should be updated.
93 ASSERT_EQ(loc,
94 Extension::GetHigherPriorityLocation(Extension::INTERNAL, loc));
95 ASSERT_EQ(loc,
96 Extension::GetHigherPriorityLocation(loc, Extension::INTERNAL));
97 }
98
99 // Check a few interesting cases that we know can happen:
100 ASSERT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD,
101 Extension::GetHigherPriorityLocation(
102 Extension::EXTERNAL_POLICY_DOWNLOAD,
103 Extension::EXTERNAL_PREF));
104
105 ASSERT_EQ(Extension::EXTERNAL_PREF,
106 Extension::GetHigherPriorityLocation(
107 Extension::INTERNAL,
108 Extension::EXTERNAL_PREF));
109 }
110
111
112 // Please don't put any more manifest tests here!!
113 // Move them to extension_manifest_unittest.cc instead and make them use the
114 // more data-driven style there instead.
115 // Bug: http://crbug.com/38462
116
117
TEST(ExtensionTest,InitFromValueInvalid)118 TEST(ExtensionTest, InitFromValueInvalid) {
119 #if defined(OS_WIN)
120 FilePath path(FILE_PATH_LITERAL("c:\\foo"));
121 #elif defined(OS_POSIX)
122 FilePath path(FILE_PATH_LITERAL("/foo"));
123 #endif
124 scoped_refptr<Extension> extension_ptr(new Extension(path,
125 Extension::INVALID));
126 Extension& extension = *extension_ptr;
127 int error_code = 0;
128 std::string error;
129
130 // Start with a valid extension manifest
131 FilePath extensions_path;
132 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
133 extensions_path = extensions_path.AppendASCII("extensions")
134 .AppendASCII("good")
135 .AppendASCII("Extensions")
136 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
137 .AppendASCII("1.0.0.0")
138 .Append(Extension::kManifestFilename);
139
140 JSONFileValueSerializer serializer(extensions_path);
141 scoped_ptr<DictionaryValue> valid_value(
142 static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
143 &error)));
144 EXPECT_EQ("", error);
145 EXPECT_EQ(0, error_code);
146 ASSERT_TRUE(valid_value.get());
147 ASSERT_TRUE(extension.InitFromValue(*valid_value, Extension::REQUIRE_KEY,
148 &error));
149 ASSERT_EQ("", error);
150 EXPECT_EQ("en_US", extension.default_locale());
151
152 scoped_ptr<DictionaryValue> input_value;
153
154 // Test missing and invalid versions
155 input_value.reset(valid_value->DeepCopy());
156 input_value->Remove(keys::kVersion, NULL);
157 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
158 &error));
159 EXPECT_EQ(errors::kInvalidVersion, error);
160
161 input_value->SetInteger(keys::kVersion, 42);
162 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
163 &error));
164 EXPECT_EQ(errors::kInvalidVersion, error);
165
166 // Test missing and invalid names.
167 input_value.reset(valid_value->DeepCopy());
168 input_value->Remove(keys::kName, NULL);
169 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
170 &error));
171 EXPECT_EQ(errors::kInvalidName, error);
172
173 input_value->SetInteger(keys::kName, 42);
174 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
175 &error));
176 EXPECT_EQ(errors::kInvalidName, error);
177
178 // Test invalid description
179 input_value.reset(valid_value->DeepCopy());
180 input_value->SetInteger(keys::kDescription, 42);
181 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
182 &error));
183 EXPECT_EQ(errors::kInvalidDescription, error);
184
185 // Test invalid icons
186 input_value.reset(valid_value->DeepCopy());
187 input_value->SetInteger(keys::kIcons, 42);
188 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
189 &error));
190 EXPECT_EQ(errors::kInvalidIcons, error);
191
192 // Test invalid icon paths
193 input_value.reset(valid_value->DeepCopy());
194 DictionaryValue* icons = NULL;
195 input_value->GetDictionary(keys::kIcons, &icons);
196 ASSERT_FALSE(NULL == icons);
197 icons->SetInteger(base::IntToString(128), 42);
198 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
199 &error));
200 EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath));
201
202 // Test invalid user scripts list
203 input_value.reset(valid_value->DeepCopy());
204 input_value->SetInteger(keys::kContentScripts, 42);
205 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
206 &error));
207 EXPECT_EQ(errors::kInvalidContentScriptsList, error);
208
209 // Test invalid user script item
210 input_value.reset(valid_value->DeepCopy());
211 ListValue* content_scripts = NULL;
212 input_value->GetList(keys::kContentScripts, &content_scripts);
213 ASSERT_FALSE(NULL == content_scripts);
214 content_scripts->Set(0, Value::CreateIntegerValue(42));
215 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
216 &error));
217 EXPECT_TRUE(MatchPattern(error, errors::kInvalidContentScript));
218
219 // Test missing and invalid matches array
220 input_value.reset(valid_value->DeepCopy());
221 input_value->GetList(keys::kContentScripts, &content_scripts);
222 DictionaryValue* user_script = NULL;
223 content_scripts->GetDictionary(0, &user_script);
224 user_script->Remove(keys::kMatches, NULL);
225 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
226 &error));
227 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
228
229 user_script->Set(keys::kMatches, Value::CreateIntegerValue(42));
230 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
231 &error));
232 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
233
234 ListValue* matches = new ListValue;
235 user_script->Set(keys::kMatches, matches);
236 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
237 &error));
238 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatchCount));
239
240 // Test invalid match element
241 matches->Set(0, Value::CreateIntegerValue(42));
242 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
243 &error));
244 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch));
245
246 matches->Set(0, Value::CreateStringValue("chrome://*/*"));
247 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
248 &error));
249 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch));
250
251 // Test missing and invalid files array
252 input_value.reset(valid_value->DeepCopy());
253 input_value->GetList(keys::kContentScripts, &content_scripts);
254 content_scripts->GetDictionary(0, &user_script);
255 user_script->Remove(keys::kJs, NULL);
256 user_script->Remove(keys::kCss, NULL);
257 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
258 &error));
259 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
260
261 user_script->Set(keys::kJs, Value::CreateIntegerValue(42));
262 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
263 &error));
264 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJsList));
265
266 user_script->Set(keys::kCss, new ListValue);
267 user_script->Set(keys::kJs, new ListValue);
268 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
269 &error));
270 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
271 user_script->Remove(keys::kCss, NULL);
272
273 ListValue* files = new ListValue;
274 user_script->Set(keys::kJs, files);
275 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
276 &error));
277 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
278
279 // Test invalid file element
280 files->Set(0, Value::CreateIntegerValue(42));
281 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
282 &error));
283 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJs));
284
285 user_script->Remove(keys::kJs, NULL);
286 // Test the css element
287 user_script->Set(keys::kCss, Value::CreateIntegerValue(42));
288 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
289 &error));
290 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCssList));
291
292 // Test invalid file element
293 ListValue* css_files = new ListValue;
294 user_script->Set(keys::kCss, css_files);
295 css_files->Set(0, Value::CreateIntegerValue(42));
296 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
297 &error));
298 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCss));
299
300 // Test missing and invalid permissions array
301 input_value.reset(valid_value->DeepCopy());
302 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
303 &error));
304
305 ListValue* permissions = NULL;
306 input_value->GetList(keys::kPermissions, &permissions);
307 ASSERT_FALSE(NULL == permissions);
308
309 permissions = new ListValue;
310 input_value->Set(keys::kPermissions, permissions);
311 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
312 &error));
313
314 input_value->Set(keys::kPermissions, Value::CreateIntegerValue(9));
315 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
316 &error));
317 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissions));
318
319 input_value.reset(valid_value->DeepCopy());
320 input_value->GetList(keys::kPermissions, &permissions);
321 permissions->Set(0, Value::CreateIntegerValue(24));
322 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
323 &error));
324 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission));
325
326 // We allow unknown API permissions, so this will be valid until we better
327 // distinguish between API and host permissions.
328 permissions->Set(0, Value::CreateStringValue("www.google.com"));
329 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
330 &error));
331
332 // Multiple page actions are not allowed.
333 input_value.reset(valid_value->DeepCopy());
334 DictionaryValue* action = new DictionaryValue;
335 action->SetString(keys::kPageActionId, "MyExtensionActionId");
336 action->SetString(keys::kName, "MyExtensionActionName");
337 ListValue* action_list = new ListValue;
338 action_list->Append(action->DeepCopy());
339 action_list->Append(action);
340 input_value->Set(keys::kPageActions, action_list);
341 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
342 &error));
343 EXPECT_STREQ(errors::kInvalidPageActionsListSize, error.c_str());
344
345 // Test invalid options page url.
346 input_value.reset(valid_value->DeepCopy());
347 input_value->Set(keys::kOptionsPage, Value::CreateNullValue());
348 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
349 &error));
350 EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage));
351
352 // Test invalid/empty default locale.
353 input_value.reset(valid_value->DeepCopy());
354 input_value->Set(keys::kDefaultLocale, Value::CreateIntegerValue(5));
355 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
356 &error));
357 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
358
359 input_value->Set(keys::kDefaultLocale, Value::CreateStringValue(""));
360 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
361 &error));
362 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
363
364 // Test invalid minimum_chrome_version.
365 input_value.reset(valid_value->DeepCopy());
366 input_value->Set(keys::kMinimumChromeVersion, Value::CreateIntegerValue(42));
367 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
368 &error));
369 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMinimumChromeVersion));
370
371 #if !defined(OS_MACOSX)
372 // TODO(aa): The version isn't stamped into the unit test binary on mac.
373 input_value->Set(keys::kMinimumChromeVersion,
374 Value::CreateStringValue("88.8"));
375 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
376 &error));
377 EXPECT_TRUE(MatchPattern(error, errors::kChromeVersionTooLow));
378 #endif
379 }
380
TEST(ExtensionTest,InitFromValueValid)381 TEST(ExtensionTest, InitFromValueValid) {
382 #if defined(OS_WIN)
383 FilePath path(FILE_PATH_LITERAL("C:\\foo"));
384 #elif defined(OS_POSIX)
385 FilePath path(FILE_PATH_LITERAL("/foo"));
386 #endif
387 scoped_refptr<Extension> extension_ptr(new Extension(path,
388 Extension::INVALID));
389 Extension& extension = *extension_ptr;
390 std::string error;
391 DictionaryValue input_value;
392
393 // Test minimal extension
394 input_value.SetString(keys::kVersion, "1.0.0.0");
395 input_value.SetString(keys::kName, "my extension");
396
397 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
398 &error));
399 EXPECT_EQ("", error);
400 EXPECT_TRUE(Extension::IdIsValid(extension.id()));
401 EXPECT_EQ("1.0.0.0", extension.VersionString());
402 EXPECT_EQ("my extension", extension.name());
403 EXPECT_EQ(extension.id(), extension.url().host());
404 EXPECT_EQ(path.value(), extension.path().value());
405
406 // Test permissions scheme.
407 ListValue* permissions = new ListValue;
408 permissions->Set(0, Value::CreateStringValue("file:///C:/foo.txt"));
409 input_value.Set(keys::kPermissions, permissions);
410
411 // We allow unknown API permissions, so this will be valid until we better
412 // distinguish between API and host permissions.
413 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
414 &error));
415 input_value.Remove(keys::kPermissions, NULL);
416
417 // Test with an options page.
418 input_value.SetString(keys::kOptionsPage, "options.html");
419 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
420 &error));
421 EXPECT_EQ("", error);
422 EXPECT_EQ("chrome-extension", extension.options_url().scheme());
423 EXPECT_EQ("/options.html", extension.options_url().path());
424
425 // Test that an empty list of page actions does not stop a browser action
426 // from being loaded.
427 ListValue* empty_list = new ListValue;
428 input_value.Set(keys::kPageActions, empty_list);
429 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
430 &error));
431 EXPECT_EQ("", error);
432
433 #if !defined(OS_MACOSX)
434 // TODO(aa): The version isn't stamped into the unit test binary on mac.
435 // Test with a minimum_chrome_version.
436 input_value.SetString(keys::kMinimumChromeVersion, "1.0");
437 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
438 &error));
439 EXPECT_EQ("", error);
440 // The minimum chrome version is not stored in the Extension object.
441 #endif
442 }
443
TEST(ExtensionTest,InitFromValueValidNameInRTL)444 TEST(ExtensionTest, InitFromValueValidNameInRTL) {
445 #if defined(TOOLKIT_GTK)
446 GtkTextDirection gtk_dir = gtk_widget_get_default_direction();
447 gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
448 #else
449 std::string locale = l10n_util::GetApplicationLocale("");
450 base::i18n::SetICUDefaultLocale("he");
451 #endif
452
453 #if defined(OS_WIN)
454 FilePath path(FILE_PATH_LITERAL("C:\\foo"));
455 #elif defined(OS_POSIX)
456 FilePath path(FILE_PATH_LITERAL("/foo"));
457 #endif
458 scoped_refptr<Extension> extension_ptr(new Extension(path,
459 Extension::INVALID));
460 Extension& extension = *extension_ptr;
461 std::string error;
462 DictionaryValue input_value;
463
464 input_value.SetString(keys::kVersion, "1.0.0.0");
465 // No strong RTL characters in name.
466 std::wstring name(L"Dictionary (by Google)");
467 input_value.SetString(keys::kName, WideToUTF16Hack(name));
468 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
469 &error));
470 EXPECT_EQ("", error);
471 std::wstring localized_name(name);
472 base::i18n::AdjustStringForLocaleDirection(&localized_name);
473 EXPECT_EQ(localized_name, UTF8ToWide(extension.name()));
474
475 // Strong RTL characters in name.
476 name = L"Dictionary (\x05D1\x05D2"L" Google)";
477 input_value.SetString(keys::kName, WideToUTF16Hack(name));
478 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
479 &error));
480 EXPECT_EQ("", error);
481 localized_name = name;
482 base::i18n::AdjustStringForLocaleDirection(&localized_name);
483 EXPECT_EQ(localized_name, UTF8ToWide(extension.name()));
484
485 // Reset locale.
486 #if defined(TOOLKIT_GTK)
487 gtk_widget_set_default_direction(gtk_dir);
488 #else
489 base::i18n::SetICUDefaultLocale(locale);
490 #endif
491 }
492
TEST(ExtensionTest,GetResourceURLAndPath)493 TEST(ExtensionTest, GetResourceURLAndPath) {
494 #if defined(OS_WIN)
495 FilePath path(FILE_PATH_LITERAL("C:\\foo"));
496 #elif defined(OS_POSIX)
497 FilePath path(FILE_PATH_LITERAL("/foo"));
498 #endif
499 DictionaryValue input_value;
500 input_value.SetString(keys::kVersion, "1.0.0.0");
501 input_value.SetString(keys::kName, "my extension");
502 scoped_refptr<Extension> extension(Extension::Create(path,
503 Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS, NULL));
504 EXPECT_TRUE(extension.get());
505
506 EXPECT_EQ(extension->url().spec() + "bar/baz.js",
507 Extension::GetResourceURL(extension->url(), "bar/baz.js").spec());
508 EXPECT_EQ(extension->url().spec() + "baz.js",
509 Extension::GetResourceURL(extension->url(),
510 "bar/../baz.js").spec());
511 EXPECT_EQ(extension->url().spec() + "baz.js",
512 Extension::GetResourceURL(extension->url(), "../baz.js").spec());
513 }
514
TEST(ExtensionTest,LoadPageActionHelper)515 TEST(ExtensionTest, LoadPageActionHelper) {
516 #if defined(OS_WIN)
517 FilePath path(base::StringPrintf(L"c:\\extension"));
518 #else
519 FilePath path(base::StringPrintf("/extension"));
520 #endif
521 scoped_refptr<Extension> extension_ptr(new Extension(path,
522 Extension::INVALID));
523 Extension& extension = *extension_ptr;
524 std::string error_msg;
525 scoped_ptr<ExtensionAction> action;
526 DictionaryValue input;
527
528 // First try with an empty dictionary.
529 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
530 ASSERT_TRUE(action != NULL);
531 ASSERT_TRUE(error_msg.empty());
532
533 // Now setup some values to use in the action.
534 const std::string id("MyExtensionActionId");
535 const std::string name("MyExtensionActionName");
536 std::string img1("image1.png");
537 std::string img2("image2.png");
538
539 // Add the dictionary for the contextual action.
540 input.SetString(keys::kPageActionId, id);
541 input.SetString(keys::kName, name);
542 ListValue* icons = new ListValue;
543 icons->Set(0, Value::CreateStringValue(img1));
544 icons->Set(1, Value::CreateStringValue(img2));
545 input.Set(keys::kPageActionIcons, icons);
546
547 // Parse and read back the values from the object.
548 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
549 ASSERT_TRUE(NULL != action.get());
550 ASSERT_TRUE(error_msg.empty());
551 ASSERT_EQ(id, action->id());
552 // No title, so fall back to name.
553 ASSERT_EQ(name, action->GetTitle(1));
554 ASSERT_EQ(2u, action->icon_paths()->size());
555 ASSERT_EQ(img1, (*action->icon_paths())[0]);
556 ASSERT_EQ(img2, (*action->icon_paths())[1]);
557
558 // Explicitly set the same type and parse again.
559 input.SetString(keys::kType, values::kPageActionTypeTab);
560 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
561 ASSERT_TRUE(NULL != action.get());
562 ASSERT_TRUE(error_msg.empty());
563
564 // Make a deep copy of the input and remove one key at a time and see if we
565 // get the right error.
566 scoped_ptr<DictionaryValue> copy;
567
568 // First remove id key.
569 copy.reset(input.DeepCopy());
570 copy->Remove(keys::kPageActionId, NULL);
571 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
572 ASSERT_TRUE(NULL != action.get());
573
574 // Then remove the name key. It's optional, so no error.
575 copy.reset(input.DeepCopy());
576 copy->Remove(keys::kName, NULL);
577 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
578 ASSERT_TRUE(NULL != action.get());
579 ASSERT_TRUE(action->GetTitle(1).empty());
580 ASSERT_TRUE(error_msg.empty());
581
582 // Then remove the icon paths key.
583 copy.reset(input.DeepCopy());
584 copy->Remove(keys::kPageActionIcons, NULL);
585 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
586 ASSERT_TRUE(NULL != action.get());
587 error_msg = "";
588
589 // Now test that we can parse the new format for page actions.
590
591 // Now setup some values to use in the page action.
592 const std::string kTitle("MyExtensionActionTitle");
593 const std::string kIcon("image1.png");
594 const std::string kPopupHtmlFile("a_popup.html");
595
596 // Add the dictionary for the contextual action.
597 input.Clear();
598 input.SetString(keys::kPageActionDefaultTitle, kTitle);
599 input.SetString(keys::kPageActionDefaultIcon, kIcon);
600
601 // Parse and read back the values from the object.
602 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
603 ASSERT_TRUE(action.get());
604 ASSERT_TRUE(error_msg.empty());
605 ASSERT_EQ(kTitle, action->GetTitle(1));
606 ASSERT_EQ(0u, action->icon_paths()->size());
607
608 // Invalid title should give an error even with a valid name.
609 input.Clear();
610 input.SetInteger(keys::kPageActionDefaultTitle, 42);
611 input.SetString(keys::kName, name);
612 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
613 ASSERT_TRUE(NULL == action.get());
614 ASSERT_STREQ(errors::kInvalidPageActionDefaultTitle, error_msg.c_str());
615 error_msg = "";
616
617 // Invalid name should give an error only with no title.
618 input.SetString(keys::kPageActionDefaultTitle, kTitle);
619 input.SetInteger(keys::kName, 123);
620 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
621 ASSERT_TRUE(NULL != action.get());
622 ASSERT_EQ(kTitle, action->GetTitle(1));
623 ASSERT_TRUE(error_msg.empty());
624
625 input.Remove(keys::kPageActionDefaultTitle, NULL);
626 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
627 ASSERT_TRUE(NULL == action.get());
628 ASSERT_STREQ(errors::kInvalidPageActionName, error_msg.c_str());
629 error_msg = "";
630
631 // Test that keys "popup" and "default_popup" both work, but can not
632 // be used at the same time.
633 input.Clear();
634 input.SetString(keys::kPageActionDefaultTitle, kTitle);
635 input.SetString(keys::kPageActionDefaultIcon, kIcon);
636
637 // LoadExtensionActionHelper expects the extension member |extension_url|
638 // to be set.
639 extension.extension_url_ =
640 GURL(std::string(chrome::kExtensionScheme) +
641 chrome::kStandardSchemeSeparator +
642 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/");
643
644 // Add key "popup", expect success.
645 input.SetString(keys::kPageActionPopup, kPopupHtmlFile);
646 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
647 ASSERT_TRUE(NULL != action.get());
648 ASSERT_TRUE(error_msg.empty());
649 ASSERT_STREQ(
650 extension.url().Resolve(kPopupHtmlFile).spec().c_str(),
651 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str());
652
653 // Add key "default_popup", expect failure.
654 input.SetString(keys::kPageActionDefaultPopup, kPopupHtmlFile);
655 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
656 ASSERT_TRUE(NULL == action.get());
657 ASSERT_STREQ(
658 ExtensionErrorUtils::FormatErrorMessage(
659 errors::kInvalidPageActionOldAndNewKeys,
660 keys::kPageActionDefaultPopup,
661 keys::kPageActionPopup).c_str(),
662 error_msg.c_str());
663 error_msg = "";
664
665 // Remove key "popup", expect success.
666 input.Remove(keys::kPageActionPopup, NULL);
667 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
668 ASSERT_TRUE(NULL != action.get());
669 ASSERT_TRUE(error_msg.empty());
670 ASSERT_STREQ(
671 extension.url().Resolve(kPopupHtmlFile).spec().c_str(),
672 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str());
673
674 // Setting default_popup to "" is the same as having no popup.
675 input.Remove(keys::kPageActionDefaultPopup, NULL);
676 input.SetString(keys::kPageActionDefaultPopup, "");
677 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
678 ASSERT_TRUE(NULL != action.get());
679 ASSERT_TRUE(error_msg.empty());
680 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId));
681 ASSERT_STREQ(
682 "",
683 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str());
684
685 // Setting popup to "" is the same as having no popup.
686 input.Remove(keys::kPageActionDefaultPopup, NULL);
687 input.SetString(keys::kPageActionPopup, "");
688 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
689 ASSERT_TRUE(NULL != action.get());
690 ASSERT_TRUE(error_msg.empty());
691 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId));
692 ASSERT_STREQ(
693 "",
694 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str());
695 }
696
TEST(ExtensionTest,IdIsValid)697 TEST(ExtensionTest, IdIsValid) {
698 EXPECT_TRUE(Extension::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
699 EXPECT_TRUE(Extension::IdIsValid("pppppppppppppppppppppppppppppppp"));
700 EXPECT_TRUE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnop"));
701 EXPECT_TRUE(Extension::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"));
702 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno"));
703 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnopa"));
704 EXPECT_FALSE(Extension::IdIsValid("0123456789abcdef0123456789abcdef"));
705 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnoq"));
706 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno0"));
707 }
708
TEST(ExtensionTest,GenerateID)709 TEST(ExtensionTest, GenerateID) {
710 const uint8 public_key_info[] = {
711 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
712 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
713 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b,
714 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08,
715 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04,
716 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a,
717 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30,
718 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17,
719 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89,
720 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85,
721 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14,
722 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18,
723 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6,
724 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01
725 };
726
727 std::string extension_id;
728 EXPECT_TRUE(
729 Extension::GenerateId(
730 std::string(reinterpret_cast<const char*>(&public_key_info[0]),
731 arraysize(public_key_info)),
732 &extension_id));
733 EXPECT_EQ("melddjfinppjdikinhbgehiennejpfhp", extension_id);
734 }
735
TEST(ExtensionTest,UpdateUrls)736 TEST(ExtensionTest, UpdateUrls) {
737 // Test several valid update urls
738 std::vector<std::string> valid;
739 valid.push_back("http://test.com");
740 valid.push_back("http://test.com/");
741 valid.push_back("http://test.com/update");
742 valid.push_back("http://test.com/update?check=true");
743 for (size_t i = 0; i < valid.size(); i++) {
744 GURL url(valid[i]);
745 EXPECT_TRUE(url.is_valid());
746
747 DictionaryValue input_value;
748 #if defined(OS_WIN)
749 // (Why %Iu below? This is the single file in the whole code base that
750 // might make use of a WidePRIuS; let's not encourage any more.)
751 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i));
752 #else
753 FilePath path(base::StringPrintf("/extension%" PRIuS, i));
754 #endif
755 std::string error;
756
757 input_value.SetString(keys::kVersion, "1.0");
758 input_value.SetString(keys::kName, "Test");
759 input_value.SetString(keys::kUpdateURL, url.spec());
760
761 scoped_refptr<Extension> extension(Extension::Create(
762 path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS,
763 &error));
764 EXPECT_TRUE(extension.get()) << error;
765 }
766
767 // Test some invalid update urls
768 std::vector<std::string> invalid;
769 invalid.push_back("");
770 invalid.push_back("test.com");
771 valid.push_back("http://test.com/update#whatever");
772 for (size_t i = 0; i < invalid.size(); i++) {
773 DictionaryValue input_value;
774 #if defined(OS_WIN)
775 // (Why %Iu below? This is the single file in the whole code base that
776 // might make use of a WidePRIuS; let's not encourage any more.)
777 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i));
778 #else
779 FilePath path(base::StringPrintf("/extension%" PRIuS, i));
780 #endif
781 std::string error;
782 input_value.SetString(keys::kVersion, "1.0");
783 input_value.SetString(keys::kName, "Test");
784 input_value.SetString(keys::kUpdateURL, invalid[i]);
785
786 scoped_refptr<Extension> extension(Extension::Create(
787 path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS,
788 &error));
789 EXPECT_FALSE(extension.get());
790 EXPECT_TRUE(MatchPattern(error, errors::kInvalidUpdateURL));
791 }
792 }
793
794 // This test ensures that the mimetype sniffing code stays in sync with the
795 // actual crx files that we test other parts of the system with.
TEST(ExtensionTest,MimeTypeSniffing)796 TEST(ExtensionTest, MimeTypeSniffing) {
797 FilePath path;
798 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
799 path = path.AppendASCII("extensions").AppendASCII("good.crx");
800
801 std::string data;
802 ASSERT_TRUE(file_util::ReadFileToString(path, &data));
803
804 std::string result;
805 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(),
806 GURL("http://www.example.com/foo.crx"), "", &result));
807 EXPECT_EQ(std::string(Extension::kMimeType), result);
808
809 data.clear();
810 result.clear();
811 path = path.DirName().AppendASCII("bad_magic.crx");
812 ASSERT_TRUE(file_util::ReadFileToString(path, &data));
813 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(),
814 GURL("http://www.example.com/foo.crx"), "", &result));
815 EXPECT_EQ("application/octet-stream", result);
816 }
817
LoadManifest(const std::string & dir,const std::string & test_file,int extra_flags)818 static scoped_refptr<Extension> LoadManifest(const std::string& dir,
819 const std::string& test_file,
820 int extra_flags) {
821 FilePath path;
822 PathService::Get(chrome::DIR_TEST_DATA, &path);
823 path = path.AppendASCII("extensions")
824 .AppendASCII(dir)
825 .AppendASCII(test_file);
826
827 JSONFileValueSerializer serializer(path);
828 std::string error;
829 scoped_ptr<Value> result(serializer.Deserialize(NULL, &error));
830 if (!result.get()) {
831 EXPECT_EQ("", error);
832 return NULL;
833 }
834
835 scoped_refptr<Extension> extension = Extension::Create(
836 path.DirName(), Extension::INVALID,
837 *static_cast<DictionaryValue*>(result.get()),
838 Extension::STRICT_ERROR_CHECKS | extra_flags, &error);
839 EXPECT_TRUE(extension) << error;
840 return extension;
841 }
842
LoadManifest(const std::string & dir,const std::string & test_file)843 static scoped_refptr<Extension> LoadManifest(const std::string& dir,
844 const std::string& test_file) {
845 return LoadManifest(dir, test_file, Extension::NO_FLAGS);
846 }
847
TEST(ExtensionTest,EffectiveHostPermissions)848 TEST(ExtensionTest, EffectiveHostPermissions) {
849 scoped_refptr<Extension> extension;
850 ExtensionExtent hosts;
851
852 extension = LoadManifest("effective_host_permissions", "empty.json");
853 EXPECT_EQ(0u, extension->GetEffectiveHostPermissions().patterns().size());
854 EXPECT_FALSE(hosts.ContainsURL(GURL("http://www.google.com")));
855 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
856
857 extension = LoadManifest("effective_host_permissions", "one_host.json");
858 hosts = extension->GetEffectiveHostPermissions();
859 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com")));
860 EXPECT_FALSE(hosts.ContainsURL(GURL("https://www.google.com")));
861 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
862
863 extension = LoadManifest("effective_host_permissions",
864 "one_host_wildcard.json");
865 hosts = extension->GetEffectiveHostPermissions();
866 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com")));
867 EXPECT_TRUE(hosts.ContainsURL(GURL("http://foo.google.com")));
868 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
869
870 extension = LoadManifest("effective_host_permissions", "two_hosts.json");
871 hosts = extension->GetEffectiveHostPermissions();
872 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com")));
873 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com")));
874 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
875
876 extension = LoadManifest("effective_host_permissions",
877 "https_not_considered.json");
878 hosts = extension->GetEffectiveHostPermissions();
879 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com")));
880 EXPECT_TRUE(hosts.ContainsURL(GURL("https://google.com")));
881 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
882
883 extension = LoadManifest("effective_host_permissions",
884 "two_content_scripts.json");
885 hosts = extension->GetEffectiveHostPermissions();
886 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com")));
887 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com")));
888 EXPECT_TRUE(hosts.ContainsURL(GURL("http://news.ycombinator.com")));
889 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
890
891 extension = LoadManifest("effective_host_permissions", "all_hosts.json");
892 hosts = extension->GetEffectiveHostPermissions();
893 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/")));
894 EXPECT_FALSE(hosts.ContainsURL(GURL("https://test/")));
895 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com")));
896 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
897
898 extension = LoadManifest("effective_host_permissions", "all_hosts2.json");
899 hosts = extension->GetEffectiveHostPermissions();
900 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/")));
901 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com")));
902 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
903
904 extension = LoadManifest("effective_host_permissions", "all_hosts3.json");
905 hosts = extension->GetEffectiveHostPermissions();
906 EXPECT_FALSE(hosts.ContainsURL(GURL("http://test/")));
907 EXPECT_TRUE(hosts.ContainsURL(GURL("https://test/")));
908 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com")));
909 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
910 }
911
TEST(ExtensionTest,IsPrivilegeIncrease)912 TEST(ExtensionTest, IsPrivilegeIncrease) {
913 const struct {
914 const char* base_name;
915 // Increase these sizes if you have more than 10.
916 const char* granted_apis[10];
917 const char* granted_hosts[10];
918 bool full_access;
919 bool expect_increase;
920 } kTests[] = {
921 { "allhosts1", {NULL}, {"http://*/", NULL}, false,
922 false }, // all -> all
923 { "allhosts2", {NULL}, {"http://*/", NULL}, false,
924 false }, // all -> one
925 { "allhosts3", {NULL}, {NULL}, false, true }, // one -> all
926 { "hosts1", {NULL},
927 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
928 false }, // http://a,http://b -> http://a,http://b
929 { "hosts2", {NULL},
930 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
931 true }, // http://a,http://b -> https://a,http://*.b
932 { "hosts3", {NULL},
933 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
934 false }, // http://a,http://b -> http://a
935 { "hosts4", {NULL},
936 {"http://www.google.com/", NULL}, false,
937 true }, // http://a -> http://a,http://b
938 { "hosts5", {"tabs", "notifications", NULL},
939 {"http://*.example.com/", "http://*.example.com/*",
940 "http://*.example.co.uk/*", "http://*.example.com.au/*",
941 NULL}, false,
942 false }, // http://a,b,c -> http://a,b,c + https://a,b,c
943 { "hosts6", {"tabs", "notifications", NULL},
944 {"http://*.example.com/", "http://*.example.com/*", NULL}, false,
945 false }, // http://a.com -> http://a.com + http://a.co.uk
946 { "permissions1", {"tabs", NULL},
947 {NULL}, false, false }, // tabs -> tabs
948 { "permissions2", {"tabs", NULL},
949 {NULL}, false, true }, // tabs -> tabs,bookmarks
950 { "permissions3", {NULL},
951 {"http://*/*", NULL},
952 false, true }, // http://a -> http://a,tabs
953 { "permissions5", {"bookmarks", NULL},
954 {NULL}, false, true }, // bookmarks -> bookmarks,history
955 #if !defined(OS_CHROMEOS) // plugins aren't allowed in ChromeOS
956 { "permissions4", {NULL},
957 {NULL}, true, false }, // plugin -> plugin,tabs
958 { "plugin1", {NULL},
959 {NULL}, true, false }, // plugin -> plugin
960 { "plugin2", {NULL},
961 {NULL}, true, false }, // plugin -> none
962 { "plugin3", {NULL},
963 {NULL}, false, true }, // none -> plugin
964 #endif
965 { "storage", {NULL},
966 {NULL}, false, false }, // none -> storage
967 { "notifications", {NULL},
968 {NULL}, false, false } // none -> notifications
969 };
970
971 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
972 scoped_refptr<Extension> old_extension(
973 LoadManifest("allow_silent_upgrade",
974 std::string(kTests[i].base_name) + "_old.json"));
975 scoped_refptr<Extension> new_extension(
976 LoadManifest("allow_silent_upgrade",
977 std::string(kTests[i].base_name) + "_new.json"));
978
979 std::set<std::string> granted_apis;
980 for (size_t j = 0; kTests[i].granted_apis[j] != NULL; ++j)
981 granted_apis.insert(kTests[i].granted_apis[j]);
982
983 ExtensionExtent granted_hosts;
984 for (size_t j = 0; kTests[i].granted_hosts[j] != NULL; ++j)
985 AddPattern(&granted_hosts, kTests[i].granted_hosts[j]);
986
987 EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json";
988 if (!new_extension.get())
989 continue;
990
991 EXPECT_EQ(kTests[i].expect_increase,
992 Extension::IsPrivilegeIncrease(kTests[i].full_access,
993 granted_apis,
994 granted_hosts,
995 new_extension.get()))
996 << kTests[i].base_name;
997 }
998 }
999
TEST(ExtensionTest,PermissionMessages)1000 TEST(ExtensionTest, PermissionMessages) {
1001 // Ensure that all permissions that needs to show install UI actually have
1002 // strings associated with them.
1003
1004 std::set<std::string> skip;
1005
1006 // These are considered "nuisance" or "trivial" permissions that don't need
1007 // a prompt.
1008 skip.insert(Extension::kContextMenusPermission);
1009 skip.insert(Extension::kIdlePermission);
1010 skip.insert(Extension::kNotificationPermission);
1011 skip.insert(Extension::kUnlimitedStoragePermission);
1012 skip.insert(Extension::kContentSettingsPermission);
1013
1014 // TODO(erikkay) add a string for this permission.
1015 skip.insert(Extension::kBackgroundPermission);
1016
1017 // The cookie permission does nothing unless you have associated host
1018 // permissions.
1019 skip.insert(Extension::kCookiePermission);
1020
1021 // The proxy permission is warned as part of host permission checks.
1022 skip.insert(Extension::kProxyPermission);
1023
1024 // This permission requires explicit user action (context menu handler)
1025 // so we won't prompt for it for now.
1026 skip.insert(Extension::kFileBrowserHandlerPermission);
1027
1028 // If you've turned on the experimental command-line flag, we don't need
1029 // to warn you further.
1030 skip.insert(Extension::kExperimentalPermission);
1031
1032 // These are only usable by component extensions.
1033 skip.insert(Extension::kWebstorePrivatePermission);
1034 skip.insert(Extension::kFileBrowserPrivatePermission);
1035 skip.insert(Extension::kChromeosInfoPrivatePermissions);
1036
1037 const Extension::PermissionMessage::MessageId ID_NONE =
1038 Extension::PermissionMessage::ID_NONE;
1039
1040 for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
1041 Extension::Permission permission = Extension::kPermissions[i];
1042 if (skip.count(permission.name)) {
1043 EXPECT_EQ(ID_NONE, permission.message_id)
1044 << "unexpected message_id for " << permission.name;
1045 } else {
1046 EXPECT_NE(ID_NONE, permission.message_id)
1047 << "missing message_id for " << permission.name;
1048 }
1049 }
1050 }
1051
1052 // Returns a copy of |source| resized to |size| x |size|.
ResizedCopy(const SkBitmap & source,int size)1053 static SkBitmap ResizedCopy(const SkBitmap& source, int size) {
1054 return skia::ImageOperations::Resize(source,
1055 skia::ImageOperations::RESIZE_LANCZOS3,
1056 size,
1057 size);
1058 }
1059
SizeEquals(const SkBitmap & bitmap,const gfx::Size & size)1060 static bool SizeEquals(const SkBitmap& bitmap, const gfx::Size& size) {
1061 return bitmap.width() == size.width() && bitmap.height() == size.height();
1062 }
1063
TEST(ExtensionTest,ImageCaching)1064 TEST(ExtensionTest, ImageCaching) {
1065 FilePath path;
1066 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
1067 path = path.AppendASCII("extensions");
1068
1069 // Initialize the Extension.
1070 std::string errors;
1071 DictionaryValue values;
1072 values.SetString(keys::kName, "test");
1073 values.SetString(keys::kVersion, "0.1");
1074 scoped_refptr<Extension> extension(Extension::Create(
1075 path, Extension::INVALID, values, Extension::STRICT_ERROR_CHECKS,
1076 &errors));
1077 ASSERT_TRUE(extension.get());
1078
1079 // Create an ExtensionResource pointing at an icon.
1080 FilePath icon_relative_path(FILE_PATH_LITERAL("icon3.png"));
1081 ExtensionResource resource(extension->id(),
1082 extension->path(),
1083 icon_relative_path);
1084
1085 // Read in the icon file.
1086 FilePath icon_absolute_path = extension->path().Append(icon_relative_path);
1087 std::string raw_png;
1088 ASSERT_TRUE(file_util::ReadFileToString(icon_absolute_path, &raw_png));
1089 SkBitmap image;
1090 ASSERT_TRUE(gfx::PNGCodec::Decode(
1091 reinterpret_cast<const unsigned char*>(raw_png.data()),
1092 raw_png.length(),
1093 &image));
1094
1095 // Make sure the icon file is the size we expect.
1096 gfx::Size original_size(66, 66);
1097 ASSERT_EQ(image.width(), original_size.width());
1098 ASSERT_EQ(image.height(), original_size.height());
1099
1100 // Create two resized versions at size 16x16 and 24x24.
1101 SkBitmap image16 = ResizedCopy(image, 16);
1102 SkBitmap image24 = ResizedCopy(image, 24);
1103
1104 gfx::Size size16(16, 16);
1105 gfx::Size size24(24, 24);
1106
1107 // Cache the 16x16 copy.
1108 EXPECT_FALSE(extension->HasCachedImage(resource, size16));
1109 extension->SetCachedImage(resource, image16, original_size);
1110 EXPECT_TRUE(extension->HasCachedImage(resource, size16));
1111 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size16), size16));
1112 EXPECT_FALSE(extension->HasCachedImage(resource, size24));
1113 EXPECT_FALSE(extension->HasCachedImage(resource, original_size));
1114
1115 // Cache the 24x24 copy.
1116 extension->SetCachedImage(resource, image24, original_size);
1117 EXPECT_TRUE(extension->HasCachedImage(resource, size24));
1118 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size24), size24));
1119 EXPECT_FALSE(extension->HasCachedImage(resource, original_size));
1120
1121 // Cache the original, and verify that it gets returned when we ask for a
1122 // max_size that is larger than the original.
1123 gfx::Size size128(128, 128);
1124 EXPECT_TRUE(image.width() < size128.width() &&
1125 image.height() < size128.height());
1126 extension->SetCachedImage(resource, image, original_size);
1127 EXPECT_TRUE(extension->HasCachedImage(resource, original_size));
1128 EXPECT_TRUE(extension->HasCachedImage(resource, size128));
1129 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, original_size),
1130 original_size));
1131 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size128),
1132 original_size));
1133 EXPECT_EQ(extension->GetCachedImage(resource, original_size).getPixels(),
1134 extension->GetCachedImage(resource, size128).getPixels());
1135 }
1136
1137 // Tests that the old permission name "unlimited_storage" still works for
1138 // backwards compatibility (we renamed it to "unlimitedStorage").
TEST(ExtensionTest,OldUnlimitedStoragePermission)1139 TEST(ExtensionTest, OldUnlimitedStoragePermission) {
1140 ScopedTempDir directory;
1141 ASSERT_TRUE(directory.CreateUniqueTempDir());
1142 FilePath extension_path = directory.path();
1143 DictionaryValue dictionary;
1144
1145 // The two required keys.
1146 dictionary.SetString(extension_manifest_keys::kName, "test");
1147 dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
1148
1149 // Create a permissions list containing "unlimited_storage" and add it.
1150 ListValue* permissions = new ListValue();
1151 const char* old_unlimited = "unlimited_storage";
1152 EXPECT_STREQ(old_unlimited, Extension::kOldUnlimitedStoragePermission);
1153 permissions->Append(Value::CreateStringValue(old_unlimited));
1154 dictionary.Set(extension_manifest_keys::kPermissions, permissions);
1155
1156 // Initialize the extension and make sure the permission for unlimited storage
1157 // is present.
1158 std::string errors;
1159 scoped_refptr<Extension> extension(Extension::Create(
1160 extension_path, Extension::INVALID, dictionary,
1161 Extension::STRICT_ERROR_CHECKS, &errors));
1162 EXPECT_TRUE(extension.get());
1163 EXPECT_TRUE(extension->HasApiPermission(
1164 Extension::kUnlimitedStoragePermission));
1165 }
1166
1167 // This tests the API permissions with an empty manifest (one that just
1168 // specifies a name and a version and nothing else).
TEST(ExtensionTest,ApiPermissions)1169 TEST(ExtensionTest, ApiPermissions) {
1170 const struct {
1171 const char* permission_name;
1172 bool expect_success;
1173 } kTests[] = {
1174 // Negative test.
1175 { "non_existing_permission", false },
1176 // Test default module/package permission.
1177 { "browserAction", true },
1178 { "browserActions", true },
1179 { "devtools", true },
1180 { "extension", true },
1181 { "i18n", true },
1182 { "pageAction", true },
1183 { "pageActions", true },
1184 { "test", true },
1185 // Some negative tests.
1186 { "bookmarks", false },
1187 { "cookies", false },
1188 { "history", false },
1189 { "tabs.onUpdated", false },
1190 // Make sure we find the module name after stripping '.' and '/'.
1191 { "browserAction/abcd/onClick", true },
1192 { "browserAction.abcd.onClick", true },
1193 // Test Tabs functions.
1194 { "tabs.create", true},
1195 { "tabs.update", true},
1196 { "tabs.getSelected", false},
1197 };
1198
1199 scoped_refptr<Extension> extension;
1200 extension = LoadManifest("empty_manifest", "empty.json");
1201
1202 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
1203 EXPECT_EQ(kTests[i].expect_success,
1204 extension->HasApiPermission(kTests[i].permission_name))
1205 << "Permission being tested: " << kTests[i].permission_name;
1206 }
1207 }
1208
TEST(ExtensionTest,GetHostPermissionMessages_ManyHosts)1209 TEST(ExtensionTest, GetHostPermissionMessages_ManyHosts) {
1210 scoped_refptr<Extension> extension;
1211 extension = LoadManifest("permissions", "many-hosts.json");
1212 std::vector<string16> warnings = extension->GetPermissionMessageStrings();
1213 ASSERT_EQ(1u, warnings.size());
1214 EXPECT_EQ("Your data on www.google.com and encrypted.google.com",
1215 UTF16ToUTF8(warnings[0]));
1216 }
1217
TEST(ExtensionTest,GetPermissionMessages_Plugins)1218 TEST(ExtensionTest, GetPermissionMessages_Plugins) {
1219 scoped_refptr<Extension> extension;
1220 extension = LoadManifest("permissions", "plugins.json");
1221 std::vector<string16> warnings = extension->GetPermissionMessageStrings();
1222 // We don't parse the plugins key on Chrome OS, so it should not ask for any
1223 // permissions.
1224 #if defined(OS_CHROMEOS)
1225 ASSERT_EQ(0u, warnings.size());
1226 #else
1227 ASSERT_EQ(1u, warnings.size());
1228 EXPECT_EQ("All data on your computer and the websites you visit",
1229 UTF16ToUTF8(warnings[0]));
1230 #endif
1231 }
1232
TEST(ExtensionTest,WantsFileAccess)1233 TEST(ExtensionTest, WantsFileAccess) {
1234 scoped_refptr<Extension> extension;
1235 GURL file_url("file:///etc/passwd");
1236
1237 // <all_urls> permission
1238 extension = LoadManifest("permissions", "permissions_all_urls.json");
1239 EXPECT_TRUE(extension->wants_file_access());
1240 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1241 extension = LoadManifest(
1242 "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS);
1243 EXPECT_TRUE(extension->wants_file_access());
1244 EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1245
1246 // file:///* permission
1247 extension = LoadManifest("permissions", "permissions_file_scheme.json");
1248 EXPECT_TRUE(extension->wants_file_access());
1249 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1250 extension = LoadManifest("permissions", "permissions_file_scheme.json",
1251 Extension::ALLOW_FILE_ACCESS);
1252 EXPECT_TRUE(extension->wants_file_access());
1253 EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1254
1255 // http://* permission
1256 extension = LoadManifest("permissions", "permissions_http_scheme.json");
1257 EXPECT_FALSE(extension->wants_file_access());
1258 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1259 extension = LoadManifest("permissions", "permissions_http_scheme.json",
1260 Extension::ALLOW_FILE_ACCESS);
1261 EXPECT_FALSE(extension->wants_file_access());
1262 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
1263
1264 // <all_urls> content script match
1265 extension = LoadManifest("permissions", "content_script_all_urls.json");
1266 EXPECT_TRUE(extension->wants_file_access());
1267 EXPECT_FALSE(extension->CanExecuteScriptOnPage(
1268 file_url, &extension->content_scripts()[0], NULL));
1269 extension = LoadManifest("permissions", "content_script_all_urls.json",
1270 Extension::ALLOW_FILE_ACCESS);
1271 EXPECT_TRUE(extension->wants_file_access());
1272 EXPECT_TRUE(extension->CanExecuteScriptOnPage(
1273 file_url, &extension->content_scripts()[0], NULL));
1274
1275 // file:///* content script match
1276 extension = LoadManifest("permissions", "content_script_file_scheme.json");
1277 EXPECT_TRUE(extension->wants_file_access());
1278 EXPECT_FALSE(extension->CanExecuteScriptOnPage(
1279 file_url, &extension->content_scripts()[0], NULL));
1280 extension = LoadManifest("permissions", "content_script_file_scheme.json",
1281 Extension::ALLOW_FILE_ACCESS);
1282 EXPECT_TRUE(extension->wants_file_access());
1283 EXPECT_TRUE(extension->CanExecuteScriptOnPage(
1284 file_url, &extension->content_scripts()[0], NULL));
1285
1286 // http://* content script match
1287 extension = LoadManifest("permissions", "content_script_http_scheme.json");
1288 EXPECT_FALSE(extension->wants_file_access());
1289 EXPECT_FALSE(extension->CanExecuteScriptOnPage(
1290 file_url, &extension->content_scripts()[0], NULL));
1291 extension = LoadManifest("permissions", "content_script_http_scheme.json",
1292 Extension::ALLOW_FILE_ACCESS);
1293 EXPECT_FALSE(extension->wants_file_access());
1294 EXPECT_FALSE(extension->CanExecuteScriptOnPage(
1295 file_url, &extension->content_scripts()[0], NULL));
1296 }
1297
1298 // Base class for testing the CanExecuteScriptOnPage and CanCaptureVisiblePage
1299 // methods of Extension for extensions with various permissions.
1300 class ExtensionScriptAndCaptureVisibleTest : public testing::Test {
1301 public:
ExtensionScriptAndCaptureVisibleTest()1302 ExtensionScriptAndCaptureVisibleTest() {
1303 PathService::Get(chrome::DIR_TEST_DATA, &dirpath_);
1304 }
1305
MakeExtension(const std::string & permissions,Extension::Location location)1306 scoped_refptr<Extension> MakeExtension(const std::string& permissions,
1307 Extension::Location location) {
1308 // Replace single-quotes with double-quotes in permissions, since JSON
1309 // mandates double-quotes.
1310 std::string munged_permissions = permissions;
1311 ReplaceSubstringsAfterOffset(&munged_permissions, 0, "'", "\"");
1312
1313 DictionaryValue dictionary;
1314 dictionary.SetString(keys::kName, "permission test");
1315 dictionary.SetString(keys::kVersion, "1");
1316 std::string error;
1317 JSONStringValueSerializer serializer(munged_permissions);
1318 scoped_ptr<Value> permission_value(serializer.Deserialize(NULL, &error));
1319 EXPECT_EQ("", error);
1320 if (!permission_value.get())
1321 return NULL;
1322 EXPECT_TRUE(permission_value->IsType(Value::TYPE_LIST));
1323 dictionary.Set(keys::kPermissions, permission_value.release());
1324
1325 FilePath dirpath;
1326 PathService::Get(chrome::DIR_TEST_DATA, &dirpath);
1327 dirpath = dirpath.AppendASCII("extensions").AppendASCII("permissions");
1328
1329 scoped_refptr<Extension> extension = Extension::Create(
1330 dirpath,
1331 location,
1332 dictionary,
1333 Extension::STRICT_ERROR_CHECKS,
1334 &error);
1335 if (!extension)
1336 VLOG(1) << error;
1337 return extension;
1338 }
1339
Allowed(const Extension * extension,const GURL & url)1340 bool Allowed(const Extension* extension, const GURL& url) {
1341 return (extension->CanExecuteScriptOnPage(url, NULL, NULL) &&
1342 extension->CanCaptureVisiblePage(url, NULL));
1343 }
1344
CaptureOnly(const Extension * extension,const GURL & url)1345 bool CaptureOnly(const Extension* extension, const GURL& url) {
1346 return !extension->CanExecuteScriptOnPage(url, NULL, NULL) &&
1347 extension->CanCaptureVisiblePage(url, NULL);
1348 }
1349
Blocked(const Extension * extension,const GURL & url)1350 bool Blocked(const Extension* extension, const GURL& url) {
1351 return !(extension->CanExecuteScriptOnPage(url, NULL, NULL) ||
1352 extension->CanCaptureVisiblePage(url, NULL));
1353 }
1354
1355 protected:
1356 FilePath dirpath_;
1357 };
1358
TEST_F(ExtensionScriptAndCaptureVisibleTest,Permissions)1359 TEST_F(ExtensionScriptAndCaptureVisibleTest, Permissions) {
1360 scoped_refptr<Extension> extension;
1361 // URLs that are "safe" to provide scripting and capture visible tab access
1362 // to if the permissions allow it.
1363 GURL http_url("http://www.google.com");
1364 GURL https_url("https://www.google.com");
1365 GURL file_url("file:///foo/bar");
1366
1367 // We should allow host permission but not scripting permission for favicon
1368 // urls.
1369 GURL favicon_url("chrome://favicon/http://www.google.com");
1370
1371 std::string dummy_id =
1372 Extension::GenerateIdForPath(FilePath(FILE_PATH_LITERAL("whatever")));
1373
1374 // URLs that regular extensions should never get access to.
1375 GURL extension_url("chrome-extension://" + dummy_id);
1376 GURL settings_url("chrome://settings");
1377 GURL about_url("about:flags");
1378
1379 // Test <all_urls> for regular extensions.
1380 extension = MakeExtension("['tabs','<all_urls>']", Extension::INTERNAL);
1381 EXPECT_TRUE(Allowed(extension, http_url));
1382 EXPECT_TRUE(Allowed(extension, https_url));
1383 EXPECT_TRUE(Blocked(extension, file_url));
1384 EXPECT_TRUE(Blocked(extension, settings_url));
1385 EXPECT_TRUE(CaptureOnly(extension, favicon_url));
1386 EXPECT_TRUE(Blocked(extension, about_url));
1387 EXPECT_TRUE(Blocked(extension, extension_url));
1388
1389 EXPECT_FALSE(extension->HasHostPermission(settings_url));
1390 EXPECT_FALSE(extension->HasHostPermission(about_url));
1391 EXPECT_TRUE(extension->HasHostPermission(favicon_url));
1392
1393 // Test * for scheme, which implies just the http/https schemes.
1394 extension = MakeExtension("['tabs','*://*/']", Extension::INTERNAL);
1395 EXPECT_TRUE(Allowed(extension, http_url));
1396 EXPECT_TRUE(Allowed(extension, https_url));
1397 EXPECT_TRUE(Blocked(extension, settings_url));
1398 EXPECT_TRUE(Blocked(extension, about_url));
1399 EXPECT_TRUE(Blocked(extension, file_url));
1400 EXPECT_TRUE(Blocked(extension, favicon_url));
1401 extension = MakeExtension("['tabs','*://settings/*']", Extension::INTERNAL);
1402 EXPECT_TRUE(Blocked(extension, settings_url));
1403
1404 // Having chrome://*/ should not work for regular extensions. Note that
1405 // for favicon access, we require the explicit pattern chrome://favicon/*.
1406 extension = MakeExtension("['tabs','chrome://*/']",
1407 Extension::INTERNAL);
1408 EXPECT_TRUE(extension == NULL);
1409
1410 // Having chrome://favicon/* should not give you chrome://*
1411 extension = MakeExtension("['tabs','chrome://favicon/*']",
1412 Extension::INTERNAL);
1413 EXPECT_TRUE(Blocked(extension, settings_url));
1414 EXPECT_TRUE(CaptureOnly(extension, favicon_url));
1415 EXPECT_TRUE(Blocked(extension, about_url));
1416 EXPECT_TRUE(extension->HasHostPermission(favicon_url));
1417
1418 // Having http://favicon should not give you chrome://favicon
1419 extension = MakeExtension("['tabs', 'http://favicon/']", Extension::INTERNAL);
1420 EXPECT_TRUE(Blocked(extension, settings_url));
1421 EXPECT_TRUE(Blocked(extension, favicon_url));
1422
1423 // Component extensions with <all_urls> should get everything.
1424 extension = MakeExtension("['tabs','<all_urls>']", Extension::COMPONENT);
1425 EXPECT_TRUE(Allowed(extension, http_url));
1426 EXPECT_TRUE(Allowed(extension, https_url));
1427 EXPECT_TRUE(Allowed(extension, settings_url));
1428 EXPECT_TRUE(Allowed(extension, about_url));
1429 EXPECT_TRUE(Allowed(extension, favicon_url));
1430 EXPECT_TRUE(extension->HasHostPermission(favicon_url));
1431
1432 // Component extensions should only get access to what they ask for.
1433 extension = MakeExtension("['tabs', 'http://www.google.com/']",
1434 Extension::COMPONENT);
1435 EXPECT_TRUE(Allowed(extension, http_url));
1436 EXPECT_TRUE(Blocked(extension, https_url));
1437 EXPECT_TRUE(Blocked(extension, file_url));
1438 EXPECT_TRUE(Blocked(extension, settings_url));
1439 EXPECT_TRUE(Blocked(extension, favicon_url));
1440 EXPECT_TRUE(Blocked(extension, about_url));
1441 EXPECT_TRUE(Blocked(extension, extension_url));
1442 EXPECT_FALSE(extension->HasHostPermission(settings_url));
1443 }
1444
1445
TEST(ExtensionTest,GetDistinctHostsForDisplay)1446 TEST(ExtensionTest, GetDistinctHostsForDisplay) {
1447 std::vector<std::string> expected;
1448 expected.push_back("www.foo.com");
1449 expected.push_back("www.bar.com");
1450 expected.push_back("www.baz.com");
1451 URLPatternList actual;
1452
1453 {
1454 SCOPED_TRACE("no dupes");
1455
1456 // Simple list with no dupes.
1457 actual.push_back(
1458 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1459 actual.push_back(
1460 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path"));
1461 actual.push_back(
1462 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
1463 CompareLists(expected,
1464 Extension::GetDistinctHostsForDisplay(actual));
1465 }
1466
1467 {
1468 SCOPED_TRACE("two dupes");
1469
1470 // Add some dupes.
1471 actual.push_back(
1472 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1473 actual.push_back(
1474 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
1475 CompareLists(expected,
1476 Extension::GetDistinctHostsForDisplay(actual));
1477 }
1478
1479 {
1480 SCOPED_TRACE("schemes differ");
1481
1482 // Add a pattern that differs only by scheme. This should be filtered out.
1483 actual.push_back(
1484 URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path"));
1485 CompareLists(expected,
1486 Extension::GetDistinctHostsForDisplay(actual));
1487 }
1488
1489 {
1490 SCOPED_TRACE("paths differ");
1491
1492 // Add some dupes by path.
1493 actual.push_back(
1494 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath"));
1495 CompareLists(expected,
1496 Extension::GetDistinctHostsForDisplay(actual));
1497 }
1498
1499 {
1500 SCOPED_TRACE("subdomains differ");
1501
1502 // We don't do anything special for subdomains.
1503 actual.push_back(
1504 URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path"));
1505 actual.push_back(
1506 URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path"));
1507
1508 expected.push_back("monkey.www.bar.com");
1509 expected.push_back("bar.com");
1510
1511 CompareLists(expected,
1512 Extension::GetDistinctHostsForDisplay(actual));
1513 }
1514
1515 {
1516 SCOPED_TRACE("RCDs differ");
1517
1518 // Now test for RCD uniquing.
1519 actual.push_back(
1520 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1521 actual.push_back(
1522 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1523 actual.push_back(
1524 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path"));
1525 actual.push_back(
1526 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path"));
1527 actual.push_back(
1528 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1529 actual.push_back(
1530 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path"));
1531
1532 // This is an unknown RCD, which shouldn't be uniqued out.
1533 actual.push_back(
1534 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
1535 // But it should only occur once.
1536 actual.push_back(
1537 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
1538
1539 expected.push_back("www.foo.xyzzy");
1540
1541 CompareLists(expected,
1542 Extension::GetDistinctHostsForDisplay(actual));
1543 }
1544
1545 {
1546 SCOPED_TRACE("wildcards");
1547
1548 actual.push_back(
1549 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
1550
1551 expected.push_back("*.google.com");
1552
1553 CompareLists(expected,
1554 Extension::GetDistinctHostsForDisplay(actual));
1555 }
1556 }
1557
TEST(ExtensionTest,GetDistinctHostsForDisplay_ComIsBestRcd)1558 TEST(ExtensionTest, GetDistinctHostsForDisplay_ComIsBestRcd) {
1559 URLPatternList actual;
1560 actual.push_back(
1561 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1562 actual.push_back(
1563 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1564 actual.push_back(
1565 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1566 actual.push_back(
1567 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1568 actual.push_back(
1569 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1570 actual.push_back(
1571 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1572
1573 std::vector<std::string> expected;
1574 expected.push_back("www.foo.com");
1575
1576 CompareLists(expected,
1577 Extension::GetDistinctHostsForDisplay(actual));
1578 }
1579
TEST(ExtensionTest,GetDistinctHostsForDisplay_NetIs2ndBestRcd)1580 TEST(ExtensionTest, GetDistinctHostsForDisplay_NetIs2ndBestRcd) {
1581 URLPatternList actual;
1582 actual.push_back(
1583 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1584 actual.push_back(
1585 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1586 actual.push_back(
1587 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1588 actual.push_back(
1589 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1590 actual.push_back(
1591 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1592 // No http://www.foo.com/path
1593
1594 std::vector<std::string> expected;
1595 expected.push_back("www.foo.net");
1596
1597 CompareLists(expected,
1598 Extension::GetDistinctHostsForDisplay(actual));
1599 }
1600
TEST(ExtensionTest,GetDistinctHostsForDisplay_OrgIs3rdBestRcd)1601 TEST(ExtensionTest, GetDistinctHostsForDisplay_OrgIs3rdBestRcd) {
1602 URLPatternList actual;
1603 actual.push_back(
1604 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1605 actual.push_back(
1606 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1607 actual.push_back(
1608 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1609 // No http://www.foo.net/path
1610 actual.push_back(
1611 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1612 // No http://www.foo.com/path
1613
1614 std::vector<std::string> expected;
1615 expected.push_back("www.foo.org");
1616
1617 CompareLists(expected,
1618 Extension::GetDistinctHostsForDisplay(actual));
1619 }
1620
TEST(ExtensionTest,GetDistinctHostsForDisplay_FirstInListIs4thBestRcd)1621 TEST(ExtensionTest, GetDistinctHostsForDisplay_FirstInListIs4thBestRcd) {
1622 URLPatternList actual;
1623 actual.push_back(
1624 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1625 // No http://www.foo.org/path
1626 actual.push_back(
1627 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1628 // No http://www.foo.net/path
1629 actual.push_back(
1630 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1631 // No http://www.foo.com/path
1632
1633 std::vector<std::string> expected;
1634 expected.push_back("www.foo.ca");
1635
1636 CompareLists(expected,
1637 Extension::GetDistinctHostsForDisplay(actual));
1638 }
1639
TEST(ExtensionTest,IsElevatedHostList)1640 TEST(ExtensionTest, IsElevatedHostList) {
1641 URLPatternList list1;
1642 URLPatternList list2;
1643
1644 list1.push_back(
1645 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
1646 list1.push_back(
1647 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1648
1649 // Test that the host order does not matter.
1650 list2.push_back(
1651 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1652 list2.push_back(
1653 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
1654
1655 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
1656 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
1657
1658 // Test that paths are ignored.
1659 list2.clear();
1660 list2.push_back(
1661 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
1662 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
1663 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
1664
1665 // Test that RCDs are ignored.
1666 list2.clear();
1667 list2.push_back(
1668 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
1669 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
1670 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
1671
1672 // Test that subdomain wildcards are handled properly.
1673 list2.clear();
1674 list2.push_back(
1675 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
1676 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
1677 //TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
1678 //EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
1679
1680 // Test that different domains count as different hosts.
1681 list2.clear();
1682 list2.push_back(
1683 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1684 list2.push_back(
1685 URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
1686 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
1687 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
1688
1689 // Test that different subdomains count as different hosts.
1690 list2.clear();
1691 list2.push_back(
1692 URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
1693 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
1694 EXPECT_TRUE(Extension::IsElevatedHostList(list2, list1));
1695 }
1696
TEST(ExtensionTest,GenerateId)1697 TEST(ExtensionTest, GenerateId) {
1698 std::string result;
1699 EXPECT_TRUE(Extension::GenerateId("", &result));
1700
1701 EXPECT_TRUE(Extension::GenerateId("test", &result));
1702 EXPECT_EQ(result, "jpignaibiiemhngfjkcpokkamffknabf");
1703
1704 EXPECT_TRUE(Extension::GenerateId("_", &result));
1705 EXPECT_EQ(result, "ncocknphbhhlhkikpnnlmbcnbgdempcd");
1706
1707 EXPECT_TRUE(Extension::GenerateId(
1708 "this_string_is_longer_than_a_single_sha256_hash_digest", &result));
1709 EXPECT_EQ(result, "jimneklojkjdibfkgiiophfhjhbdgcfi");
1710 }
1711