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 32 using content::BrowserThread; 33 using content::PluginService; 34 35 namespace Clear = extensions::api::content_settings::ContentSetting::Clear; 36 namespace Get = extensions::api::content_settings::ContentSetting::Get; 37 namespace Set = extensions::api::content_settings::ContentSetting::Set; 38 namespace pref_helpers = extensions::preference_helpers; 39 namespace pref_keys = extensions::preference_api_constants; 40 41 namespace { 42 43 bool 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 59 namespace extensions { 60 61 namespace helpers = content_settings_helpers; 62 namespace keys = content_settings_api_constants; 63 64 bool 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 98 bool 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 171 bool 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 if (params->details.secondary_pattern.get()) { 189 std::string secondary_error; 190 secondary_pattern = 191 helpers::ParseExtensionPattern(*params->details.secondary_pattern, 192 &secondary_error); 193 if (!secondary_pattern.IsValid()) { 194 error_ = secondary_error; 195 return false; 196 } 197 } 198 199 std::string resource_identifier; 200 if (params->details.resource_identifier.get()) 201 resource_identifier = params->details.resource_identifier->id; 202 203 std::string setting_str; 204 EXTENSION_FUNCTION_VALIDATE( 205 params->details.setting->GetAsString(&setting_str)); 206 ContentSetting setting; 207 EXTENSION_FUNCTION_VALIDATE( 208 helpers::StringToContentSetting(setting_str, &setting)); 209 EXTENSION_FUNCTION_VALIDATE( 210 HostContentSettingsMap::IsSettingAllowedForType(profile()->GetPrefs(), 211 setting, 212 content_type)); 213 214 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular; 215 bool incognito = false; 216 if (params->details.scope == 217 Set::Params::Details::SCOPE_INCOGNITO_SESSION_ONLY) { 218 scope = kExtensionPrefsScopeIncognitoSessionOnly; 219 incognito = true; 220 } 221 222 if (incognito) { 223 // Regular profiles can't access incognito unless include_incognito is true. 224 if (!profile()->IsOffTheRecord() && !include_incognito()) { 225 error_ = pref_keys::kIncognitoErrorMessage; 226 return false; 227 } 228 } else { 229 // Incognito profiles can't access regular mode ever, they only exist in 230 // split mode. 231 if (profile()->IsOffTheRecord()) { 232 error_ = keys::kIncognitoContextError; 233 return false; 234 } 235 } 236 237 if (scope == kExtensionPrefsScopeIncognitoSessionOnly && 238 !profile_->HasOffTheRecordProfile()) { 239 error_ = pref_keys::kIncognitoSessionOnlyErrorMessage; 240 return false; 241 } 242 243 ContentSettingsStore* store = extensions::ExtensionSystem::Get(profile_)-> 244 extension_service()->GetContentSettingsStore(); 245 store->SetExtensionContentSetting(extension_id(), primary_pattern, 246 secondary_pattern, content_type, 247 resource_identifier, setting, scope); 248 return true; 249 } 250 251 bool ContentSettingsContentSettingGetResourceIdentifiersFunction::RunImpl() { 252 ContentSettingsType content_type; 253 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type)); 254 255 if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS) { 256 SendResponse(true); 257 return true; 258 } 259 260 PluginService::GetInstance()->GetPlugins( 261 base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction:: 262 OnGotPlugins, 263 this)); 264 return true; 265 } 266 267 void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins( 268 const std::vector<content::WebPluginInfo>& plugins) { 269 PluginFinder* finder = PluginFinder::GetInstance(); 270 std::set<std::string> group_identifiers; 271 base::ListValue* list = new base::ListValue(); 272 for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin(); 273 it != plugins.end(); ++it) { 274 scoped_ptr<PluginMetadata> plugin_metadata(finder->GetPluginMetadata(*it)); 275 const std::string& group_identifier = plugin_metadata->identifier(); 276 if (group_identifiers.find(group_identifier) != group_identifiers.end()) 277 continue; 278 279 group_identifiers.insert(group_identifier); 280 base::DictionaryValue* dict = new base::DictionaryValue(); 281 dict->SetString(keys::kIdKey, group_identifier); 282 dict->SetString(keys::kDescriptionKey, plugin_metadata->name()); 283 list->Append(dict); 284 } 285 SetResult(list); 286 BrowserThread::PostTask( 287 BrowserThread::UI, FROM_HERE, base::Bind( 288 &ContentSettingsContentSettingGetResourceIdentifiersFunction:: 289 SendResponse, 290 this, 291 true)); 292 } 293 294 } // namespace extensions 295