[go: nahoru, domu]

blob: 330478c1c6efe7e48b5eb9d41a078f589f5a391a [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/extensions/extension.h"
#include "base/format_macros.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/string_util.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_reporter.h"
#include "chrome/common/json_value_serializer.h"
#include "net/base/mime_sniffer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace keys = extension_manifest_keys;
namespace values = extension_manifest_values;
namespace errors = extension_manifest_errors;
class ExtensionTest : public testing::Test {
};
// TODO(mad): http://crbug.com/26214
TEST(ExtensionTest, DISABLED_InitFromValueInvalid) {
#if defined(OS_WIN)
FilePath path(FILE_PATH_LITERAL("c:\\foo"));
#elif defined(OS_POSIX)
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
Extension extension(path);
std::string error;
ExtensionErrorReporter::Init(false);
// Start with a valid extension manifest
FilePath extensions_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
extensions_path = extensions_path.AppendASCII("extensions")
.AppendASCII("good")
.AppendASCII("Extensions")
.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
.AppendASCII("1.0.0.0")
.AppendASCII(Extension::kManifestFilename);
JSONFileValueSerializer serializer(extensions_path);
scoped_ptr<DictionaryValue> valid_value(
static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
EXPECT_EQ("", error);
ASSERT_TRUE(valid_value.get());
ASSERT_TRUE(extension.InitFromValue(*valid_value, true, &error));
ASSERT_EQ("", error);
EXPECT_EQ("en_US", extension.default_locale());
scoped_ptr<DictionaryValue> input_value;
// Test missing and invalid versions
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->Remove(keys::kVersion, NULL);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidVersion, error);
input_value->SetInteger(keys::kVersion, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidVersion, error);
// Test missing and invalid names
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->Remove(keys::kName, NULL);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidName, error);
input_value->SetInteger(keys::kName, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidName, error);
// Test invalid description
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->SetInteger(keys::kDescription, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidDescription, error);
// Test invalid icons
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->SetInteger(keys::kIcons, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidIcons, error);
// Test invalid icon paths
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
DictionaryValue* icons = NULL;
input_value->GetDictionary(keys::kIcons, &icons);
ASSERT_FALSE(NULL == icons);
icons->SetInteger(ASCIIToWide(IntToString(128)), 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath));
// Test invalid user scripts list
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->SetInteger(keys::kContentScripts, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidContentScriptsList, error);
// Test invalid user script item
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
ListValue* content_scripts = NULL;
input_value->GetList(keys::kContentScripts, &content_scripts);
ASSERT_FALSE(NULL == content_scripts);
content_scripts->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidContentScript));
// Test missing and invalid matches array
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->GetList(keys::kContentScripts, &content_scripts);
DictionaryValue* user_script = NULL;
content_scripts->GetDictionary(0, &user_script);
user_script->Remove(keys::kMatches, NULL);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
user_script->Set(keys::kMatches, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
ListValue* matches = new ListValue;
user_script->Set(keys::kMatches, matches);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatchCount));
// Test invalid match element
matches->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch));
// Test missing and invalid files array
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->GetList(keys::kContentScripts, &content_scripts);
content_scripts->GetDictionary(0, &user_script);
user_script->Remove(keys::kJs, NULL);
user_script->Remove(keys::kCss, NULL);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
user_script->Set(keys::kJs, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidJsList));
user_script->Set(keys::kCss, new ListValue);
user_script->Set(keys::kJs, new ListValue);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
user_script->Remove(keys::kCss, NULL);
ListValue* files = new ListValue;
user_script->Set(keys::kJs, files);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
// Test invalid file element
files->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidJs));
user_script->Remove(keys::kJs, NULL);
// Test the css element
user_script->Set(keys::kCss, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidCssList));
// Test invalid file element
ListValue* css_files = new ListValue;
user_script->Set(keys::kCss, css_files);
css_files->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidCss));
// Test missing and invalid permissions array
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
EXPECT_TRUE(extension.InitFromValue(*input_value, true, &error));
ListValue* permissions = NULL;
input_value->GetList(keys::kPermissions, &permissions);
ASSERT_FALSE(NULL == permissions);
permissions = new ListValue;
input_value->Set(keys::kPermissions, permissions);
EXPECT_TRUE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(0u, ExtensionErrorReporter::GetInstance()->GetErrors()->size());
input_value->Set(keys::kPermissions, Value::CreateIntegerValue(9));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissions));
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->GetList(keys::kPermissions, &permissions);
permissions->Set(0, Value::CreateIntegerValue(24));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission));
permissions->Set(0, Value::CreateStringValue("www.google.com"));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission));
// Test permissions scheme.
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->GetList(keys::kPermissions, &permissions);
permissions->Set(0, Value::CreateStringValue("file:///C:/foo.txt"));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissionScheme));
// Test invalid privacy blacklists list.
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->SetInteger(keys::kPrivacyBlacklists, 42);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_EQ(errors::kInvalidPrivacyBlacklists, error);
// Test invalid privacy blacklists list item.
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
ListValue* privacy_blacklists = NULL;
input_value->GetList(keys::kPrivacyBlacklists, &privacy_blacklists);
ASSERT_FALSE(NULL == privacy_blacklists);
privacy_blacklists->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPrivacyBlacklistsPath));
// Test invalid UI surface count (both page action and browser action).
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
DictionaryValue* action = new DictionaryValue;
action->SetString(keys::kPageActionId, "MyExtensionActionId");
action->SetString(keys::kName, "MyExtensionActionName");
ListValue* action_list = new ListValue;
action_list->Append(action->DeepCopy());
input_value->Set(keys::kPageActions, action_list);
input_value->Set(keys::kBrowserAction, action);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_STREQ(error.c_str(), errors::kOneUISurfaceOnly);
// Test invalid options page url.
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->Set(keys::kOptionsPage, Value::CreateNullValue());
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage));
// Test invalid/empty default locale.
input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
input_value->Set(keys::kDefaultLocale, Value::CreateIntegerValue(5));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
input_value->Set(keys::kDefaultLocale, Value::CreateStringValue(""));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
}
TEST(ExtensionTest, InitFromValueValid) {
#if defined(OS_WIN)
FilePath path(FILE_PATH_LITERAL("C:\\foo"));
#elif defined(OS_POSIX)
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
Extension extension(path);
std::string error;
DictionaryValue input_value;
// Test minimal extension
input_value.SetString(keys::kVersion, "1.0.0.0");
input_value.SetString(keys::kName, "my extension");
EXPECT_TRUE(extension.InitFromValue(input_value, false, &error));
EXPECT_EQ("", error);
EXPECT_TRUE(Extension::IdIsValid(extension.id()));
EXPECT_EQ("1.0.0.0", extension.VersionString());
EXPECT_EQ("my extension", extension.name());
EXPECT_EQ(extension.id(), extension.url().host());
EXPECT_EQ(path.value(), extension.path().value());
// Test with an options page.
input_value.SetString(keys::kOptionsPage, "options.html");
EXPECT_TRUE(extension.InitFromValue(input_value, false, &error));
EXPECT_EQ("", error);
EXPECT_EQ("chrome-extension", extension.options_url().scheme());
EXPECT_EQ("/options.html", extension.options_url().path());
}
TEST(ExtensionTest, GetResourceURLAndPath) {
#if defined(OS_WIN)
FilePath path(FILE_PATH_LITERAL("C:\\foo"));
#elif defined(OS_POSIX)
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
Extension extension(path);
DictionaryValue input_value;
input_value.SetString(keys::kVersion, "1.0.0.0");
input_value.SetString(keys::kName, "my extension");
EXPECT_TRUE(extension.InitFromValue(input_value, false, NULL));
EXPECT_EQ(extension.url().spec() + "bar/baz.js",
Extension::GetResourceURL(extension.url(), "bar/baz.js").spec());
EXPECT_EQ(extension.url().spec() + "baz.js",
Extension::GetResourceURL(extension.url(), "bar/../baz.js").spec());
EXPECT_EQ(extension.url().spec() + "baz.js",
Extension::GetResourceURL(extension.url(), "../baz.js").spec());
}
TEST(ExtensionTest, LoadPageActionHelper) {
#if defined(OS_WIN)
FilePath path(StringPrintf(L"c:\\extension"));
#else
FilePath path(StringPrintf("/extension"));
#endif
Extension extension(path);
std::string error_msg;
scoped_ptr<ExtensionAction> action;
DictionaryValue input;
// First try with an empty dictionary.
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(action != NULL);
ASSERT_STREQ("", error_msg.c_str());
error_msg = "";
// Now setup some values to use in the action.
const std::string id("MyExtensionActionId");
const std::string name("MyExtensionActionName");
std::string img1("image1.png");
std::string img2("image2.png");
// Add the dictionary for the contextual action.
input.SetString(keys::kPageActionId, id);
input.SetString(keys::kName, name);
ListValue* icons = new ListValue;
icons->Set(0, Value::CreateStringValue(img1));
icons->Set(1, Value::CreateStringValue(img2));
input.Set(keys::kPageActionIcons, icons);
// Parse and read back the values from the object.
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(NULL != action.get());
ASSERT_STREQ("", error_msg.c_str());
ASSERT_STREQ(id.c_str(), action->id().c_str());
// No title, so fall back to name.
ASSERT_STREQ(name.c_str(), action->GetTitle(1).c_str());
ASSERT_EQ(2u, action->icon_paths()->size());
ASSERT_STREQ(img1.c_str(), action->icon_paths()->at(0).c_str());
ASSERT_STREQ(img2.c_str(), action->icon_paths()->at(1).c_str());
// Explicitly set the same type and parse again.
input.SetString(keys::kType, values::kPageActionTypeTab);
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(NULL != action.get());
ASSERT_STREQ("", error_msg.c_str());
// Make a deep copy of the input and remove one key at a time and see if we
// get the right error.
scoped_ptr<DictionaryValue> copy;
// First remove id key.
copy.reset(static_cast<DictionaryValue*>(input.DeepCopy()));
copy->Remove(keys::kPageActionId, NULL);
action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
ASSERT_TRUE(NULL != action.get());
ASSERT_STREQ("", error_msg.c_str());
error_msg = "";
// Then remove the name key. It's optional, so no error.
copy.reset(static_cast<DictionaryValue*>(input.DeepCopy()));
copy->Remove(keys::kName, NULL);
action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
ASSERT_TRUE(NULL != action.get());
ASSERT_STREQ("", action->GetTitle(1).c_str());
ASSERT_STREQ("", error_msg.c_str());
error_msg = "";
// Then remove the icon paths key.
copy.reset(static_cast<DictionaryValue*>(input.DeepCopy()));
copy->Remove(keys::kPageActionIcons, NULL);
action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg));
ASSERT_TRUE(NULL != action.get());
error_msg = "";
// Now test that we can parse the new format for page actions.
// Now setup some values to use in the page action.
const std::string kTitle("MyExtensionActionTitle");
const std::string kIcon("image1.png");
// Add the dictionary for the contextual action.
input.Clear();
input.SetString(keys::kPageActionDefaultTitle, kTitle);
input.SetString(keys::kPageActionDefaultIcon, kIcon);
// Parse and read back the values from the object.
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(action.get());
ASSERT_STREQ("", error_msg.c_str());
ASSERT_EQ(kTitle, action->GetTitle(1));
ASSERT_EQ(0u, action->icon_paths()->size());
// Invalid title should give an error even with a valid name.
input.Clear();
input.SetInteger(keys::kPageActionDefaultTitle, 42);
input.SetString(keys::kName, name);
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(NULL == action.get());
ASSERT_STREQ(errors::kInvalidPageActionDefaultTitle, error_msg.c_str());
error_msg = "";
// Invalid name should give an error only with no title.
input.SetString(keys::kPageActionDefaultTitle, kTitle);
input.SetInteger(keys::kName, 123);
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(NULL != action.get());
ASSERT_EQ(kTitle, action->GetTitle(1));
ASSERT_STREQ("", error_msg.c_str());
error_msg = "";
input.Remove(keys::kPageActionDefaultTitle, NULL);
action.reset(extension.LoadExtensionActionHelper(&input, &error_msg));
ASSERT_TRUE(NULL == action.get());
ASSERT_STREQ(errors::kInvalidPageActionName, error_msg.c_str());
error_msg = "";
}
TEST(ExtensionTest, IdIsValid) {
EXPECT_TRUE(Extension::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
EXPECT_TRUE(Extension::IdIsValid("pppppppppppppppppppppppppppppppp"));
EXPECT_TRUE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnop"));
EXPECT_TRUE(Extension::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"));
EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno"));
EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnopa"));
EXPECT_FALSE(Extension::IdIsValid("0123456789abcdef0123456789abcdef"));
EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnoq"));
EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno0"));
}
TEST(ExtensionTest, GenerateID) {
const uint8 public_key_info[] = {
0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b,
0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08,
0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04,
0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a,
0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30,
0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17,
0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89,
0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85,
0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14,
0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18,
0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6,
0x0f, 0x02, 0x03, 0x01, 0x00, 0x01
};
std::string extension_id;
EXPECT_TRUE(
Extension::GenerateId(
std::string(reinterpret_cast<const char*>(&public_key_info[0]),
arraysize(public_key_info)),
&extension_id));
EXPECT_EQ("melddjfinppjdikinhbgehiennejpfhp", extension_id);
}
TEST(ExtensionTest, UpdateUrls) {
// Test several valid update urls
std::vector<std::string> valid;
valid.push_back("http://test.com");
valid.push_back("http://test.com/");
valid.push_back("http://test.com/update");
valid.push_back("http://test.com/update?check=true");
for (size_t i = 0; i < valid.size(); i++) {
GURL url(valid[i]);
EXPECT_TRUE(url.is_valid());
DictionaryValue input_value;
#if defined(OS_WIN)
// (Why %Iu below? This is the single file in the whole code base that
// might make use of a WidePRIuS; let's not encourage any more.)
FilePath path(StringPrintf(L"c:\\extension%Iu", i));
#else
FilePath path(StringPrintf("/extension%" PRIuS, i));
#endif
Extension extension(path);
std::string error;
input_value.SetString(keys::kVersion, "1.0");
input_value.SetString(keys::kName, "Test");
input_value.SetString(keys::kUpdateURL, url.spec());
EXPECT_TRUE(extension.InitFromValue(input_value, false, &error));
}
// Test some invalid update urls
std::vector<std::string> invalid;
invalid.push_back("");
invalid.push_back("test.com");
valid.push_back("http://test.com/update#whatever");
for (size_t i = 0; i < invalid.size(); i++) {
DictionaryValue input_value;
#if defined(OS_WIN)
// (Why %Iu below? This is the single file in the whole code base that
// might make use of a WidePRIuS; let's not encourage any more.)
FilePath path(StringPrintf(L"c:\\extension%Iu", i));
#else
FilePath path(StringPrintf("/extension%" PRIuS, i));
#endif
Extension extension(path);
std::string error;
input_value.SetString(keys::kVersion, "1.0");
input_value.SetString(keys::kName, "Test");
input_value.SetString(keys::kUpdateURL, invalid[i]);
EXPECT_FALSE(extension.InitFromValue(input_value, false, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidUpdateURL));
}
}
// This test ensures that the mimetype sniffing code stays in sync with the
// actual crx files that we test other parts of the system with.
TEST(ExtensionTest, MimeTypeSniffing) {
FilePath path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
path = path.AppendASCII("extensions").AppendASCII("good.crx");
std::string data;
ASSERT_TRUE(file_util::ReadFileToString(path, &data));
std::string result;
EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(),
GURL("http://www.example.com/foo.crx"), "", &result));
EXPECT_EQ(std::string(Extension::kMimeType), result);
data.clear();
result.clear();
path = path.DirName().AppendASCII("bad_magic.crx");
ASSERT_TRUE(file_util::ReadFileToString(path, &data));
EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(),
GURL("http://www.example.com/foo.crx"), "", &result));
EXPECT_EQ("application/octet-stream", result);
}
static Extension* LoadManifest(const std::string& dir,
const std::string& test_file) {
FilePath path;
PathService::Get(chrome::DIR_TEST_DATA, &path);
path = path.AppendASCII("extensions")
.AppendASCII(dir)
.AppendASCII(test_file);
JSONFileValueSerializer serializer(path);
scoped_ptr<Value> result(serializer.Deserialize(NULL));
if (!result.get())
return NULL;
std::string error;
scoped_ptr<Extension> extension(new Extension(path.DirName()));
extension->InitFromValue(*static_cast<DictionaryValue*>(result.get()),
false, &error);
return extension.release();
}
TEST(ExtensionTest, EffectiveHostPermissions) {
scoped_ptr<Extension> extension;
std::set<std::string> hosts;
extension.reset(LoadManifest("effective_host_permissions", "empty.json"));
EXPECT_EQ(0u, extension->GetEffectiveHostPermissions().size());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions", "one_host.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(1u, hosts.size());
EXPECT_TRUE(hosts.find("www.google.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"one_host_wildcard.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(1u, hosts.size());
EXPECT_TRUE(hosts.find("google.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"two_hosts.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(2u, hosts.size());
EXPECT_TRUE(hosts.find("www.google.com") != hosts.end());
EXPECT_TRUE(hosts.find("www.reddit.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"duplicate_host.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(1u, hosts.size());
EXPECT_TRUE(hosts.find("google.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"https_not_considered.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(1u, hosts.size());
EXPECT_TRUE(hosts.find("google.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"two_content_scripts.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(3u, hosts.size());
EXPECT_TRUE(hosts.find("google.com") != hosts.end());
EXPECT_TRUE(hosts.find("www.reddit.com") != hosts.end());
EXPECT_TRUE(hosts.find("news.ycombinator.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"duplicate_content_script.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(2u, hosts.size());
EXPECT_TRUE(hosts.find("google.com") != hosts.end());
EXPECT_TRUE(hosts.find("www.reddit.com") != hosts.end());
EXPECT_FALSE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"all_hosts.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(1u, hosts.size());
EXPECT_TRUE(hosts.find("") != hosts.end());
EXPECT_TRUE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"all_hosts2.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(2u, hosts.size());
EXPECT_TRUE(hosts.find("") != hosts.end());
EXPECT_TRUE(hosts.find("www.google.com") != hosts.end());
EXPECT_TRUE(extension->HasAccessToAllHosts());
extension.reset(LoadManifest("effective_host_permissions",
"all_hosts3.json"));
hosts = extension->GetEffectiveHostPermissions();
EXPECT_EQ(2u, hosts.size());
EXPECT_TRUE(hosts.find("") != hosts.end());
EXPECT_TRUE(hosts.find("www.google.com") != hosts.end());
EXPECT_TRUE(extension->HasAccessToAllHosts());
}
TEST(ExtensionTest, IsPrivilegeIncrease) {
const struct {
const char* base_name;
bool expect_success;
} kTests[] = {
{ "allhosts1", false }, // all -> all
{ "allhosts2", false }, // all -> one
{ "allhosts3", true }, // one -> all
{ "hosts1", false }, // http://a,http://b -> http://a,http://b
{ "hosts2", false }, // http://a,http://b -> https://a,http://*.b
{ "hosts3", false }, // http://a,http://b -> http://a
{ "hosts4", true }, // http://a -> http://a,http://b
{ "permissions1", false }, // tabs -> tabs
{ "permissions2", false }, // tabs -> tabs,bookmarks
{ "permissions3", true }, // http://a -> http://a,tabs
{ "permissions4", false }, // plugin -> plugin,tabs
{ "plugin1", false }, // plugin -> plugin
{ "plugin2", false }, // plugin -> none
{ "plugin3", true } // none -> plugin
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
scoped_ptr<Extension> old_extension(
LoadManifest("allow_silent_upgrade",
std::string(kTests[i].base_name) + "_old.json"));
scoped_ptr<Extension> new_extension(
LoadManifest("allow_silent_upgrade",
std::string(kTests[i].base_name) + "_new.json"));
EXPECT_EQ(kTests[i].expect_success,
Extension::IsPrivilegeIncrease(old_extension.get(),
new_extension.get()))
<< kTests[i].base_name;
}
}