blob: b85b28f266b2995b25aaf118a9f71d39b42fa781 [file] [log] [blame]
// Copyright 2013 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/manifest_handlers/settings_overrides_handler.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/permissions/settings_override_permission.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/manifest_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/permissions_info.h"
#include "grit/generated_resources.h"
#include "ipc/ipc_message.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
using extensions::api::manifest_types::ChromeSettingsOverrides;
namespace extensions {
namespace {
const char* kWwwPrefix = "www.";
scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
scoped_ptr<GURL> manifest_url(new GURL(url));
if (!manifest_url->is_valid() ||
!manifest_url->SchemeIsHTTPOrHTTPS())
return scoped_ptr<GURL>();
return manifest_url.Pass();
}
scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
base::string16* error) {
if (!overrides.homepage)
return scoped_ptr<GURL>();
scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
if (!manifest_url) {
*error = extensions::ErrorUtils::FormatErrorMessageUTF16(
manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
}
return manifest_url.Pass();
}
std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
base::string16* error) {
std::vector<GURL> urls;
if (!overrides.startup_pages)
return urls;
for (std::vector<std::string>::const_iterator i =
overrides.startup_pages->begin(); i != overrides.startup_pages->end();
++i) {
scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
if (!manifest_url) {
*error = extensions::ErrorUtils::FormatErrorMessageUTF16(
manifest_errors::kInvalidStartupOverrideURL, *i);
} else {
urls.push_back(GURL());
urls.back().Swap(manifest_url.get());
}
}
return urls;
}
scoped_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
ChromeSettingsOverrides* overrides,
base::string16* error) {
if (!overrides->search_provider)
return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
if (!CreateManifestURL(overrides->search_provider->favicon_url)) {
*error = extensions::ErrorUtils::FormatErrorMessageUTF16(
manifest_errors::kInvalidSearchEngineURL,
overrides->search_provider->favicon_url);
return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
}
if (!CreateManifestURL(overrides->search_provider->search_url)) {
*error = extensions::ErrorUtils::FormatErrorMessageUTF16(
manifest_errors::kInvalidSearchEngineURL,
overrides->search_provider->search_url);
return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
}
return overrides->search_provider.Pass();
}
// A www. prefix is not informative and thus not worth the limited real estate
// in the permissions UI.
std::string RemoveWwwPrefix(const std::string& url) {
if (StartsWithASCII(url, kWwwPrefix, false))
return url.substr(strlen(kWwwPrefix));
return url;
}
} // namespace
// The manifest permission implementation supports a permission for hiding
// the bookmark button.
class SettingsOverridesHandler::ManifestPermissionImpl
: public ManifestPermission {
public:
explicit ManifestPermissionImpl(bool hide_bookmark_button_permission)
: hide_bookmark_button_permission_(hide_bookmark_button_permission) {}
// extensions::ManifestPermission overrides.
virtual std::string name() const OVERRIDE {
return manifest_keys::kSettingsOverride;
}
virtual std::string id() const OVERRIDE {
return name();
}
virtual bool HasMessages() const OVERRIDE {
return hide_bookmark_button_permission_;
}
virtual PermissionMessages GetMessages() const OVERRIDE {
PermissionMessages result;
if (hide_bookmark_button_permission_) {
result.push_back(PermissionMessage(
PermissionMessage::kHideBookmarkButton,
l10n_util::GetStringUTF16(
IDS_EXTENSION_PROMPT_WARNING_HIDE_BOOKMARK_STAR)));
}
return result;
}
virtual bool FromValue(const base::Value* value) OVERRIDE {
return value && value->GetAsBoolean(&hide_bookmark_button_permission_);
}
virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
return scoped_ptr<base::Value>(
new base::FundamentalValue(hide_bookmark_button_permission_)).Pass();
}
virtual ManifestPermission* Clone() const OVERRIDE {
return scoped_ptr<ManifestPermissionImpl>(
new ManifestPermissionImpl(hide_bookmark_button_permission_)).release();
}
virtual ManifestPermission* Diff(const ManifestPermission* rhs) const
OVERRIDE {
const ManifestPermissionImpl* other =
static_cast<const ManifestPermissionImpl*>(rhs);
return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
hide_bookmark_button_permission_ &&
!other->hide_bookmark_button_permission_)).release();
}
virtual ManifestPermission* Union(const ManifestPermission* rhs) const
OVERRIDE {
const ManifestPermissionImpl* other =
static_cast<const ManifestPermissionImpl*>(rhs);
return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
hide_bookmark_button_permission_ ||
other->hide_bookmark_button_permission_)).release();
}
virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const
OVERRIDE {
const ManifestPermissionImpl* other =
static_cast<const ManifestPermissionImpl*>(rhs);
return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
hide_bookmark_button_permission_ &&
other->hide_bookmark_button_permission_)).release();
}
virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
const ManifestPermissionImpl* other =
static_cast<const ManifestPermissionImpl*>(rhs);
return !other->hide_bookmark_button_permission_ ||
hide_bookmark_button_permission_;
}
virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
const ManifestPermissionImpl* other =
static_cast<const ManifestPermissionImpl*>(rhs);
return hide_bookmark_button_permission_ ==
other->hide_bookmark_button_permission_;
}
virtual void Write(IPC::Message* m) const OVERRIDE {
IPC::WriteParam(m, hide_bookmark_button_permission_);
}
virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
return IPC::ReadParam(m, iter, &hide_bookmark_button_permission_);
}
virtual void Log(std::string* log) const OVERRIDE {
IPC::LogParam(hide_bookmark_button_permission_, log);
}
private:
bool hide_bookmark_button_permission_;
};
SettingsOverrides::SettingsOverrides() {}
SettingsOverrides::~SettingsOverrides() {}
const SettingsOverrides* SettingsOverrides::Get(
const Extension* extension) {
return static_cast<SettingsOverrides*>(
extension->GetManifestData(manifest_keys::kSettingsOverride));
}
bool SettingsOverrides::RequiresHideBookmarkButtonPermission() const {
return bookmarks_ui && bookmarks_ui->hide_bookmark_button &&
*bookmarks_ui->hide_bookmark_button;
}
SettingsOverridesHandler::SettingsOverridesHandler() {}
SettingsOverridesHandler::~SettingsOverridesHandler() {}
bool SettingsOverridesHandler::Parse(Extension* extension,
base::string16* error) {
const base::Value* dict = NULL;
CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
scoped_ptr<ChromeSettingsOverrides> settings(
ChromeSettingsOverrides::FromValue(*dict, error));
if (!settings)
return false;
scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
info->bookmarks_ui.swap(settings->bookmarks_ui);
info->homepage = ParseHomepage(*settings, error);
info->search_engine = ParseSearchEngine(settings.get(), error);
info->startup_pages = ParseStartupPage(*settings, error);
if (!info->bookmarks_ui && !info->homepage &&
!info->search_engine && info->startup_pages.empty()) {
*error = ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides);
return false;
}
info->manifest_permission.reset(new ManifestPermissionImpl(
info->RequiresHideBookmarkButtonPermission()));
APIPermissionSet* permission_set =
PermissionsData::GetInitialAPIPermissions(extension);
DCHECK(permission_set);
if (info->search_engine) {
permission_set->insert(new SettingsOverrideAPIPermission(
PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider),
RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)->
GetOrigin().host())));
}
if (!info->startup_pages.empty()) {
permission_set->insert(new SettingsOverrideAPIPermission(
PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages),
// We only support one startup page even though the type of the manifest
// property is a list, only the first one is used.
RemoveWwwPrefix(info->startup_pages[0].GetContent())));
}
if (info->homepage) {
permission_set->insert(new SettingsOverrideAPIPermission(
PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
RemoveWwwPrefix(info->homepage.get()->GetContent())));
}
extension->SetManifestData(manifest_keys::kSettingsOverride,
info.release());
return true;
}
bool SettingsOverridesHandler::Validate(
const Extension* extension,
std::string* error,
std::vector<InstallWarning>* warnings) const {
const SettingsOverrides* settings_overrides =
SettingsOverrides::Get(extension);
if (settings_overrides && settings_overrides->bookmarks_ui &&
!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
warnings->push_back(InstallWarning(
ErrorUtils::FormatErrorMessage(
manifest_errors::kUnrecognizedManifestProperty,
manifest_keys::kHideBookmarkButton,
manifest_keys::kBookmarkUI)));
}
return true;
}
ManifestPermission* SettingsOverridesHandler::CreatePermission() {
return new ManifestPermissionImpl(false);
}
ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission(
const Extension* extension) {
const SettingsOverrides* data = SettingsOverrides::Get(extension);
if (data)
return data->manifest_permission->Clone();
return NULL;
}
const std::vector<std::string> SettingsOverridesHandler::Keys() const {
return SingleKey(manifest_keys::kSettingsOverride);
}
} // namespace extensions