content_settings_api.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2012 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/browser/extensions/api/content_settings/content_settings_api.h"
6
7#include <set>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/prefs/pref_service.h"
14#include "base/values.h"
15#include "chrome/browser/content_settings/cookie_settings.h"
16#include "chrome/browser/content_settings/host_content_settings_map.h"
17#include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
18#include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h"
19#include "chrome/browser/extensions/api/content_settings/content_settings_store.h"
20#include "chrome/browser/extensions/api/preference/preference_api_constants.h"
21#include "chrome/browser/extensions/api/preference/preference_helpers.h"
22#include "chrome/browser/extensions/extension_service.h"
23#include "chrome/browser/extensions/extension_system.h"
24#include "chrome/browser/plugins/plugin_finder.h"
25#include "chrome/browser/plugins/plugin_installer.h"
26#include "chrome/browser/profiles/profile.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/common/extensions/api/content_settings.h"
29#include "content/public/browser/plugin_service.h"
30#include "extensions/common/error_utils.h"
31
32using content::BrowserThread;
33using content::PluginService;
34
35namespace Clear = extensions::api::content_settings::ContentSetting::Clear;
36namespace Get = extensions::api::content_settings::ContentSetting::Get;
37namespace Set = extensions::api::content_settings::ContentSetting::Set;
38namespace pref_helpers = extensions::preference_helpers;
39namespace pref_keys = extensions::preference_api_constants;
40
41namespace {
42
43bool RemoveContentType(base::ListValue* args,
44                       ContentSettingsType* content_type) {
45  std::string content_type_str;
46  if (!args->GetString(0, &content_type_str))
47    return false;
48  // We remove the ContentSettingsType parameter since this is added by the
49  // renderer, and is not part of the JSON schema.
50  args->Remove(0, NULL);
51  *content_type =
52      extensions::content_settings_helpers::StringToContentSettingsType(
53          content_type_str);
54  return *content_type != CONTENT_SETTINGS_TYPE_DEFAULT;
55}
56
57}  // namespace
58
59namespace extensions {
60
61namespace helpers = content_settings_helpers;
62namespace keys = content_settings_api_constants;
63
64bool ContentSettingsContentSettingClearFunction::RunImpl() {
65  ContentSettingsType content_type;
66  EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
67
68  scoped_ptr<Clear::Params> params(Clear::Params::Create(*args_));
69  EXTENSION_FUNCTION_VALIDATE(params.get());
70
71  ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
72  bool incognito = false;
73  if (params->details.scope ==
74          Clear::Params::Details::SCOPE_INCOGNITO_SESSION_ONLY) {
75    scope = kExtensionPrefsScopeIncognitoSessionOnly;
76    incognito = true;
77  }
78
79  if (incognito) {
80    // We don't check incognito permissions here, as an extension should be
81    // always allowed to clear its own settings.
82  } else {
83    // Incognito profiles can't access regular mode ever, they only exist in
84    // split mode.
85    if (profile()->IsOffTheRecord()) {
86      error_ = keys::kIncognitoContextError;
87      return false;
88    }
89  }
90
91  ContentSettingsStore* store = extensions::ExtensionSystem::Get(profile_)->
92      extension_service()->GetContentSettingsStore();
93  store->ClearContentSettingsForExtension(extension_id(), scope);
94
95  return true;
96}
97
98bool ContentSettingsContentSettingGetFunction::RunImpl() {
99  ContentSettingsType content_type;
100  EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
101
102  scoped_ptr<Get::Params> params(Get::Params::Create(*args_));
103  EXTENSION_FUNCTION_VALIDATE(params.get());
104
105  GURL primary_url(params->details.primary_url);
106  if (!primary_url.is_valid()) {
107    error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
108        params->details.primary_url);
109    return false;
110  }
111
112  GURL secondary_url(primary_url);
113  if (params->details.secondary_url.get()) {
114    secondary_url = GURL(*params->details.secondary_url);
115    if (!secondary_url.is_valid()) {
116      error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
117        *params->details.secondary_url);
118      return false;
119    }
120  }
121
122  std::string resource_identifier;
123  if (params->details.resource_identifier.get())
124    resource_identifier = params->details.resource_identifier->id;
125
126  bool incognito = false;
127  if (params->details.incognito.get())
128    incognito = *params->details.incognito;
129  if (incognito && !include_incognito()) {
130    error_ = pref_keys::kIncognitoErrorMessage;
131    return false;
132  }
133
134  HostContentSettingsMap* map;
135  CookieSettings* cookie_settings;
136  if (incognito) {
137    if (!profile()->HasOffTheRecordProfile()) {
138      // TODO(bauerb): Allow reading incognito content settings
139      // outside of an incognito session.
140      error_ = keys::kIncognitoSessionOnlyError;
141      return false;
142    }
143    map = profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap();
144    cookie_settings = CookieSettings::Factory::GetForProfile(
145        profile()->GetOffTheRecordProfile()).get();
146  } else {
147    map = profile()->GetHostContentSettingsMap();
148    cookie_settings = CookieSettings::Factory::GetForProfile(profile()).get();
149  }
150
151  ContentSetting setting;
152  if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
153    // TODO(jochen): Do we return the value for setting or for reading cookies?
154    bool setting_cookie = false;
155    setting = cookie_settings->GetCookieSetting(primary_url, secondary_url,
156                                                setting_cookie, NULL);
157  } else {
158    setting = map->GetContentSetting(primary_url, secondary_url, content_type,
159                                     resource_identifier);
160  }
161
162  base::DictionaryValue* result = new base::DictionaryValue();
163  result->SetString(keys::kContentSettingKey,
164                    helpers::ContentSettingToString(setting));
165
166  SetResult(result);
167
168  return true;
169}
170
171bool ContentSettingsContentSettingSetFunction::RunImpl() {
172  ContentSettingsType content_type;
173  EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
174
175  scoped_ptr<Set::Params> params(Set::Params::Create(*args_));
176  EXTENSION_FUNCTION_VALIDATE(params.get());
177
178  std::string primary_error;
179  ContentSettingsPattern primary_pattern =
180      helpers::ParseExtensionPattern(params->details.primary_pattern,
181                                     &primary_error);
182  if (!primary_pattern.IsValid()) {
183    error_ = primary_error;
184    return false;
185  }
186
187  ContentSettingsPattern secondary_pattern = ContentSettingsPattern::Wildcard();
188  std::string secondary_pattern_str;
189  if (params->details.secondary_pattern.get()) {
190    std::string secondary_error;
191    secondary_pattern =
192        helpers::ParseExtensionPattern(*params->details.secondary_pattern,
193                                       &secondary_error);
194    if (!secondary_pattern.IsValid()) {
195      error_ = secondary_error;
196      return false;
197    }
198  }
199
200  std::string resource_identifier;
201  if (params->details.resource_identifier.get())
202    resource_identifier = params->details.resource_identifier->id;
203
204  std::string setting_str;
205  EXTENSION_FUNCTION_VALIDATE(
206      params->details.setting->GetAsString(&setting_str));
207  ContentSetting setting;
208  EXTENSION_FUNCTION_VALIDATE(
209      helpers::StringToContentSetting(setting_str, &setting));
210  EXTENSION_FUNCTION_VALIDATE(
211      HostContentSettingsMap::IsSettingAllowedForType(profile()->GetPrefs(),
212                                                      setting,
213                                                      content_type));
214
215  ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
216  bool incognito = false;
217  if (params->details.scope ==
218          Set::Params::Details::SCOPE_INCOGNITO_SESSION_ONLY) {
219    scope = kExtensionPrefsScopeIncognitoSessionOnly;
220    incognito = true;
221  }
222
223  if (incognito) {
224    // Regular profiles can't access incognito unless include_incognito is true.
225    if (!profile()->IsOffTheRecord() && !include_incognito()) {
226      error_ = pref_keys::kIncognitoErrorMessage;
227      return false;
228    }
229  } else {
230    // Incognito profiles can't access regular mode ever, they only exist in
231    // split mode.
232    if (profile()->IsOffTheRecord()) {
233      error_ = keys::kIncognitoContextError;
234      return false;
235    }
236  }
237
238  if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
239      !profile_->HasOffTheRecordProfile()) {
240    error_ = pref_keys::kIncognitoSessionOnlyErrorMessage;
241    return false;
242  }
243
244  ContentSettingsStore* store = extensions::ExtensionSystem::Get(profile_)->
245      extension_service()->GetContentSettingsStore();
246  store->SetExtensionContentSetting(extension_id(), primary_pattern,
247                                    secondary_pattern, content_type,
248                                    resource_identifier, setting, scope);
249  return true;
250}
251
252bool ContentSettingsContentSettingGetResourceIdentifiersFunction::RunImpl() {
253  ContentSettingsType content_type;
254  EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
255
256  if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS) {
257    SendResponse(true);
258    return true;
259  }
260
261  PluginService::GetInstance()->GetPlugins(
262      base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
263                 OnGotPlugins,
264                 this));
265  return true;
266}
267
268void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins(
269    const std::vector<content::WebPluginInfo>& plugins) {
270  PluginFinder* finder = PluginFinder::GetInstance();
271  std::set<std::string> group_identifiers;
272  base::ListValue* list = new base::ListValue();
273  for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
274       it != plugins.end(); ++it) {
275    scoped_ptr<PluginMetadata> plugin_metadata(finder->GetPluginMetadata(*it));
276    const std::string& group_identifier = plugin_metadata->identifier();
277    if (group_identifiers.find(group_identifier) != group_identifiers.end())
278      continue;
279
280    group_identifiers.insert(group_identifier);
281    base::DictionaryValue* dict = new base::DictionaryValue();
282    dict->SetString(keys::kIdKey, group_identifier);
283    dict->SetString(keys::kDescriptionKey, plugin_metadata->name());
284    list->Append(dict);
285  }
286  SetResult(list);
287  BrowserThread::PostTask(
288      BrowserThread::UI, FROM_HERE, base::Bind(
289          &ContentSettingsContentSettingGetResourceIdentifiersFunction::
290          SendResponse,
291          this,
292          true));
293}
294
295}  // namespace extensions
296