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/values.h" 14 #include "chrome/browser/content_settings/cookie_settings.h" 15 #include "chrome/browser/content_settings/host_content_settings_map.h" 16 #include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h" 17 #include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h" 18 #include "chrome/browser/extensions/api/content_settings/content_settings_service.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/plugins/plugin_finder.h" 23 #include "chrome/browser/plugins/plugin_installer.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/extensions/api/content_settings.h" 27 #include "content/public/browser/plugin_service.h" 28 #include "extensions/browser/extension_prefs_scope.h" 29 #include "extensions/common/error_utils.h" 30 31 using content::BrowserThread; 32 using content::PluginService; 33 34 namespace Clear = extensions::api::content_settings::ContentSetting::Clear; 35 namespace Get = extensions::api::content_settings::ContentSetting::Get; 36 namespace Set = extensions::api::content_settings::ContentSetting::Set; 37 namespace pref_helpers = extensions::preference_helpers; 38 namespace pref_keys = extensions::preference_api_constants; 39 40 namespace { 41 42 bool RemoveContentType(base::ListValue* args, 43 ContentSettingsType* content_type) { 44 std::string content_type_str; 45 if (!args->GetString(0, &content_type_str)) 46 return false; 47 // We remove the ContentSettingsType parameter since this is added by the 48 // renderer, and is not part of the JSON schema. 49 args->Remove(0, NULL); 50 *content_type = 51 extensions::content_settings_helpers::StringToContentSettingsType( 52 content_type_str); 53 return *content_type != CONTENT_SETTINGS_TYPE_DEFAULT; 54 } 55 56 } // namespace 57 58 namespace extensions { 59 60 namespace helpers = content_settings_helpers; 61 namespace keys = content_settings_api_constants; 62 63 bool ContentSettingsContentSettingClearFunction::RunSync() { 64 ContentSettingsType content_type; 65 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type)); 66 67 scoped_ptr<Clear::Params> params(Clear::Params::Create(*args_)); 68 EXTENSION_FUNCTION_VALIDATE(params.get()); 69 70 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular; 71 bool incognito = false; 72 if (params->details.scope == 73 Clear::Params::Details::SCOPE_INCOGNITO_SESSION_ONLY) { 74 scope = kExtensionPrefsScopeIncognitoSessionOnly; 75 incognito = true; 76 } 77 78 if (incognito) { 79 // We don't check incognito permissions here, as an extension should be 80 // always allowed to clear its own settings. 81 } else { 82 // Incognito profiles can't access regular mode ever, they only exist in 83 // split mode. 84 if (GetProfile()->IsOffTheRecord()) { 85 error_ = keys::kIncognitoContextError; 86 return false; 87 } 88 } 89 90 scoped_refptr<ContentSettingsStore> store = 91 ContentSettingsService::Get(GetProfile())->content_settings_store(); 92 store->ClearContentSettingsForExtension(extension_id(), scope); 93 94 return true; 95 } 96 97 bool ContentSettingsContentSettingGetFunction::RunSync() { 98 ContentSettingsType content_type; 99 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type)); 100 101 scoped_ptr<Get::Params> params(Get::Params::Create(*args_)); 102 EXTENSION_FUNCTION_VALIDATE(params.get()); 103 104 GURL primary_url(params->details.primary_url); 105 if (!primary_url.is_valid()) { 106 error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, 107 params->details.primary_url); 108 return false; 109 } 110 111 GURL secondary_url(primary_url); 112 if (params->details.secondary_url.get()) { 113 secondary_url = GURL(*params->details.secondary_url); 114 if (!secondary_url.is_valid()) { 115 error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, 116 *params->details.secondary_url); 117 return false; 118 } 119 } 120 121 std::string resource_identifier; 122 if (params->details.resource_identifier.get()) 123 resource_identifier = params->details.resource_identifier->id; 124 125 bool incognito = false; 126 if (params->details.incognito.get()) 127 incognito = *params->details.incognito; 128 if (incognito && !include_incognito()) { 129 error_ = pref_keys::kIncognitoErrorMessage; 130 return false; 131 } 132 133 HostContentSettingsMap* map; 134 CookieSettings* cookie_settings; 135 if (incognito) { 136 if (!GetProfile()->HasOffTheRecordProfile()) { 137 // TODO(bauerb): Allow reading incognito content settings 138 // outside of an incognito session. 139 error_ = keys::kIncognitoSessionOnlyError; 140 return false; 141 } 142 map = GetProfile()->GetOffTheRecordProfile()->GetHostContentSettingsMap(); 143 cookie_settings = CookieSettings::Factory::GetForProfile( 144 GetProfile()->GetOffTheRecordProfile()).get(); 145 } else { 146 map = GetProfile()->GetHostContentSettingsMap(); 147 cookie_settings = 148 CookieSettings::Factory::GetForProfile(GetProfile()).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::RunSync() { 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(HostContentSettingsMap::IsSettingAllowedForType( 210 GetProfile()->GetPrefs(), setting, content_type)); 211 212 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular; 213 bool incognito = false; 214 if (params->details.scope == 215 Set::Params::Details::SCOPE_INCOGNITO_SESSION_ONLY) { 216 scope = kExtensionPrefsScopeIncognitoSessionOnly; 217 incognito = true; 218 } 219 220 if (incognito) { 221 // Regular profiles can't access incognito unless include_incognito is true. 222 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) { 223 error_ = pref_keys::kIncognitoErrorMessage; 224 return false; 225 } 226 } else { 227 // Incognito profiles can't access regular mode ever, they only exist in 228 // split mode. 229 if (GetProfile()->IsOffTheRecord()) { 230 error_ = keys::kIncognitoContextError; 231 return false; 232 } 233 } 234 235 if (scope == kExtensionPrefsScopeIncognitoSessionOnly && 236 !GetProfile()->HasOffTheRecordProfile()) { 237 error_ = pref_keys::kIncognitoSessionOnlyErrorMessage; 238 return false; 239 } 240 241 scoped_refptr<ContentSettingsStore> store = 242 ContentSettingsService::Get(GetProfile())->content_settings_store(); 243 store->SetExtensionContentSetting(extension_id(), primary_pattern, 244 secondary_pattern, content_type, 245 resource_identifier, setting, scope); 246 return true; 247 } 248 249 bool ContentSettingsContentSettingGetResourceIdentifiersFunction::RunAsync() { 250 ContentSettingsType content_type; 251 EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type)); 252 253 if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS) { 254 SendResponse(true); 255 return true; 256 } 257 258 PluginService::GetInstance()->GetPlugins( 259 base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction:: 260 OnGotPlugins, 261 this)); 262 return true; 263 } 264 265 void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins( 266 const std::vector<content::WebPluginInfo>& plugins) { 267 PluginFinder* finder = PluginFinder::GetInstance(); 268 std::set<std::string> group_identifiers; 269 base::ListValue* list = new base::ListValue(); 270 for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin(); 271 it != plugins.end(); ++it) { 272 scoped_ptr<PluginMetadata> plugin_metadata(finder->GetPluginMetadata(*it)); 273 const std::string& group_identifier = plugin_metadata->identifier(); 274 if (group_identifiers.find(group_identifier) != group_identifiers.end()) 275 continue; 276 277 group_identifiers.insert(group_identifier); 278 base::DictionaryValue* dict = new base::DictionaryValue(); 279 dict->SetString(keys::kIdKey, group_identifier); 280 dict->SetString(keys::kDescriptionKey, plugin_metadata->name()); 281 list->Append(dict); 282 } 283 SetResult(list); 284 BrowserThread::PostTask( 285 BrowserThread::UI, FROM_HERE, base::Bind( 286 &ContentSettingsContentSettingGetResourceIdentifiersFunction:: 287 SendResponse, 288 this, 289 true)); 290 } 291 292 } // namespace extensions 293