blob: a7c2a8443b865123f43464e6f89d801d156ed670 [file] [log] [blame]
// Copyright (c) 2012 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/browser/extensions/api/content_settings/content_settings_api.h"
#include <memory>
#include <set>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
#include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h"
#include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
#include "chrome/browser/extensions/api/content_settings/content_settings_store.h"
#include "chrome/browser/extensions/api/preference/preference_api_constants.h"
#include "chrome/browser/extensions/api/preference/preference_helpers.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "chrome/browser/plugins/plugin_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/content_settings.h"
#include "components/content_settings/core/browser/content_settings_info.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/plugin_service.h"
#include "extensions/browser/extension_prefs_scope.h"
#include "extensions/common/error_utils.h"
using content::BrowserThread;
using content::PluginService;
namespace Clear = extensions::api::content_settings::ContentSetting::Clear;
namespace Get = extensions::api::content_settings::ContentSetting::Get;
namespace Set = extensions::api::content_settings::ContentSetting::Set;
namespace pref_helpers = extensions::preference_helpers;
namespace pref_keys = extensions::preference_api_constants;
namespace {
bool RemoveContentType(base::ListValue* args,
ContentSettingsType* content_type) {
std::string content_type_str;
if (!args->GetString(0, &content_type_str))
return false;
// We remove the ContentSettingsType parameter since this is added by the
// renderer, and is not part of the JSON schema.
args->Remove(0, NULL);
*content_type =
extensions::content_settings_helpers::StringToContentSettingsType(
content_type_str);
return *content_type != CONTENT_SETTINGS_TYPE_DEFAULT;
}
} // namespace
namespace extensions {
namespace helpers = content_settings_helpers;
namespace keys = content_settings_api_constants;
bool ContentSettingsContentSettingClearFunction::RunSync() {
ContentSettingsType content_type;
EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
std::unique_ptr<Clear::Params> params(Clear::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
bool incognito = false;
if (params->details.scope ==
api::content_settings::SCOPE_INCOGNITO_SESSION_ONLY) {
scope = kExtensionPrefsScopeIncognitoSessionOnly;
incognito = true;
}
if (incognito) {
// We don't check incognito permissions here, as an extension should be
// always allowed to clear its own settings.
} else {
// Incognito profiles can't access regular mode ever, they only exist in
// split mode.
if (GetProfile()->IsOffTheRecord()) {
error_ = keys::kIncognitoContextError;
return false;
}
}
scoped_refptr<ContentSettingsStore> store =
ContentSettingsService::Get(GetProfile())->content_settings_store();
store->ClearContentSettingsForExtension(extension_id(), scope);
return true;
}
bool ContentSettingsContentSettingGetFunction::RunSync() {
ContentSettingsType content_type;
EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
std::unique_ptr<Get::Params> params(Get::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
GURL primary_url(params->details.primary_url);
if (!primary_url.is_valid()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
params->details.primary_url);
return false;
}
GURL secondary_url(primary_url);
if (params->details.secondary_url.get()) {
secondary_url = GURL(*params->details.secondary_url);
if (!secondary_url.is_valid()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
*params->details.secondary_url);
return false;
}
}
std::string resource_identifier;
if (params->details.resource_identifier.get())
resource_identifier = params->details.resource_identifier->id;
bool incognito = false;
if (params->details.incognito.get())
incognito = *params->details.incognito;
if (incognito && !include_incognito()) {
error_ = pref_keys::kIncognitoErrorMessage;
return false;
}
HostContentSettingsMap* map;
content_settings::CookieSettings* cookie_settings;
if (incognito) {
if (!GetProfile()->HasOffTheRecordProfile()) {
// TODO(bauerb): Allow reading incognito content settings
// outside of an incognito session.
error_ = keys::kIncognitoSessionOnlyError;
return false;
}
map = HostContentSettingsMapFactory::GetForProfile(
GetProfile()->GetOffTheRecordProfile());
cookie_settings = CookieSettingsFactory::GetForProfile(
GetProfile()->GetOffTheRecordProfile()).get();
} else {
map = HostContentSettingsMapFactory::GetForProfile(GetProfile());
cookie_settings = CookieSettingsFactory::GetForProfile(GetProfile()).get();
}
ContentSetting setting;
if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
// TODO(jochen): Do we return the value for setting or for reading cookies?
bool setting_cookie = false;
setting = cookie_settings->GetCookieSetting(primary_url, secondary_url,
setting_cookie, NULL);
} else {
setting = map->GetContentSetting(primary_url, secondary_url, content_type,
resource_identifier);
}
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
std::string setting_string =
content_settings::ContentSettingToString(setting);
DCHECK(!setting_string.empty());
result->SetString(keys::kContentSettingKey, setting_string);
SetResult(std::move(result));
return true;
}
bool ContentSettingsContentSettingSetFunction::RunSync() {
ContentSettingsType content_type;
EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
std::unique_ptr<Set::Params> params(Set::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
std::string primary_error;
ContentSettingsPattern primary_pattern =
helpers::ParseExtensionPattern(params->details.primary_pattern,
&primary_error);
if (!primary_pattern.IsValid()) {
error_ = primary_error;
return false;
}
ContentSettingsPattern secondary_pattern = ContentSettingsPattern::Wildcard();
if (params->details.secondary_pattern.get()) {
std::string secondary_error;
secondary_pattern =
helpers::ParseExtensionPattern(*params->details.secondary_pattern,
&secondary_error);
if (!secondary_pattern.IsValid()) {
error_ = secondary_error;
return false;
}
}
std::string resource_identifier;
if (params->details.resource_identifier.get())
resource_identifier = params->details.resource_identifier->id;
std::string setting_str;
EXTENSION_FUNCTION_VALIDATE(
params->details.setting->GetAsString(&setting_str));
ContentSetting setting;
EXTENSION_FUNCTION_VALIDATE(
content_settings::ContentSettingFromString(setting_str, &setting));
EXTENSION_FUNCTION_VALIDATE(
content_settings::ContentSettingsRegistry::GetInstance()
->Get(content_type)
->IsSettingValid(setting));
// Some content setting types support the full set of values listed in
// content_settings.json only for exceptions. For the default setting,
// some values might not be supported.
// For example, camera supports [allow, ask, block] for exceptions, but only
// [ask, block] for the default setting.
if (primary_pattern == ContentSettingsPattern::Wildcard() &&
secondary_pattern == ContentSettingsPattern::Wildcard() &&
!HostContentSettingsMap::IsDefaultSettingAllowedForType(setting,
content_type)) {
static const char kUnsupportedDefaultSettingError[] =
"'%s' is not supported as the default setting of %s.";
// TODO(msramek): Get the same human readable name as is presented
// externally in the API, i.e. chrome.contentSettings.<name>.set().
std::string readable_type_name;
if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
readable_type_name = "microphone";
} else if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
readable_type_name = "camera";
} else {
NOTREACHED() << "No human-readable type name defined for this type.";
}
error_ = base::StringPrintf(
kUnsupportedDefaultSettingError,
setting_str.c_str(),
readable_type_name.c_str());
return false;
}
ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
bool incognito = false;
if (params->details.scope ==
api::content_settings::SCOPE_INCOGNITO_SESSION_ONLY) {
scope = kExtensionPrefsScopeIncognitoSessionOnly;
incognito = true;
}
if (incognito) {
// Regular profiles can't access incognito unless include_incognito is true.
if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
error_ = pref_keys::kIncognitoErrorMessage;
return false;
}
} else {
// Incognito profiles can't access regular mode ever, they only exist in
// split mode.
if (GetProfile()->IsOffTheRecord()) {
error_ = keys::kIncognitoContextError;
return false;
}
}
if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
!GetProfile()->HasOffTheRecordProfile()) {
error_ = pref_keys::kIncognitoSessionOnlyErrorMessage;
return false;
}
scoped_refptr<ContentSettingsStore> store =
ContentSettingsService::Get(GetProfile())->content_settings_store();
store->SetExtensionContentSetting(extension_id(), primary_pattern,
secondary_pattern, content_type,
resource_identifier, setting, scope);
return true;
}
bool ContentSettingsContentSettingGetResourceIdentifiersFunction::RunAsync() {
ContentSettingsType content_type;
EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS) {
SendResponse(true);
return true;
}
PluginService::GetInstance()->GetPlugins(
base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
OnGotPlugins,
this));
return true;
}
void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins(
const std::vector<content::WebPluginInfo>& plugins) {
PluginFinder* finder = PluginFinder::GetInstance();
std::set<std::string> group_identifiers;
std::unique_ptr<base::ListValue> list(new base::ListValue());
for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
it != plugins.end(); ++it) {
std::unique_ptr<PluginMetadata> plugin_metadata(
finder->GetPluginMetadata(*it));
const std::string& group_identifier = plugin_metadata->identifier();
if (group_identifiers.find(group_identifier) != group_identifiers.end())
continue;
group_identifiers.insert(group_identifier);
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetString(keys::kIdKey, group_identifier);
dict->SetString(keys::kDescriptionKey, plugin_metadata->name());
list->Append(dict);
}
SetResult(std::move(list));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(
&ContentSettingsContentSettingGetResourceIdentifiersFunction::
SendResponse,
this,
true));
}
} // namespace extensions