1// Copyright 2014 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 "components/search_engines/default_search_policy_handler.h" 6 7#include "base/prefs/pref_value_map.h" 8#include "base/stl_util.h" 9#include "base/strings/string_number_conversions.h" 10#include "base/strings/string_util.h" 11#include "components/policy/core/browser/policy_error_map.h" 12#include "components/policy/core/common/policy_map.h" 13#include "components/search_engines/default_search_manager.h" 14#include "components/search_engines/search_engines_pref_names.h" 15#include "components/search_engines/search_terms_data.h" 16#include "components/search_engines/template_url.h" 17#include "grit/components_strings.h" 18#include "policy/policy_constants.h" 19 20namespace policy { 21 22namespace { 23// Extracts a list from a policy value and adds it to a pref dictionary. 24void SetListInPref(const PolicyMap& policies, 25 const char* policy_name, 26 const char* key, 27 base::DictionaryValue* dict) { 28 DCHECK(dict); 29 const base::Value* policy_value = policies.GetValue(policy_name); 30 const base::ListValue* policy_list = NULL; 31 if (policy_value) { 32 bool is_list = policy_value->GetAsList(&policy_list); 33 DCHECK(is_list); 34 } 35 dict->Set(key, policy_list ? policy_list->DeepCopy() : new base::ListValue()); 36} 37 38// Extracts a string from a policy value and adds it to a pref dictionary. 39void SetStringInPref(const PolicyMap& policies, 40 const char* policy_name, 41 const char* key, 42 base::DictionaryValue* dict) { 43 DCHECK(dict); 44 const base::Value* policy_value = policies.GetValue(policy_name); 45 std::string str; 46 if (policy_value) { 47 bool is_string = policy_value->GetAsString(&str); 48 DCHECK(is_string); 49 } 50 dict->SetString(key, str); 51} 52 53} // namespace 54 55// List of policy types to preference names, for policies affecting the default 56// search provider. 57const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[] = { 58 { key::kDefaultSearchProviderEnabled, 59 prefs::kDefaultSearchProviderEnabled, 60 base::Value::TYPE_BOOLEAN }, 61 { key::kDefaultSearchProviderName, 62 prefs::kDefaultSearchProviderName, 63 base::Value::TYPE_STRING }, 64 { key::kDefaultSearchProviderKeyword, 65 prefs::kDefaultSearchProviderKeyword, 66 base::Value::TYPE_STRING }, 67 { key::kDefaultSearchProviderSearchURL, 68 prefs::kDefaultSearchProviderSearchURL, 69 base::Value::TYPE_STRING }, 70 { key::kDefaultSearchProviderSuggestURL, 71 prefs::kDefaultSearchProviderSuggestURL, 72 base::Value::TYPE_STRING }, 73 { key::kDefaultSearchProviderInstantURL, 74 prefs::kDefaultSearchProviderInstantURL, 75 base::Value::TYPE_STRING }, 76 { key::kDefaultSearchProviderIconURL, 77 prefs::kDefaultSearchProviderIconURL, 78 base::Value::TYPE_STRING }, 79 { key::kDefaultSearchProviderEncodings, 80 prefs::kDefaultSearchProviderEncodings, 81 base::Value::TYPE_LIST }, 82 { key::kDefaultSearchProviderAlternateURLs, 83 prefs::kDefaultSearchProviderAlternateURLs, 84 base::Value::TYPE_LIST }, 85 { key::kDefaultSearchProviderSearchTermsReplacementKey, 86 prefs::kDefaultSearchProviderSearchTermsReplacementKey, 87 base::Value::TYPE_STRING }, 88 { key::kDefaultSearchProviderImageURL, 89 prefs::kDefaultSearchProviderImageURL, 90 base::Value::TYPE_STRING }, 91 { key::kDefaultSearchProviderNewTabURL, 92 prefs::kDefaultSearchProviderNewTabURL, 93 base::Value::TYPE_STRING }, 94 { key::kDefaultSearchProviderSearchURLPostParams, 95 prefs::kDefaultSearchProviderSearchURLPostParams, 96 base::Value::TYPE_STRING }, 97 { key::kDefaultSearchProviderSuggestURLPostParams, 98 prefs::kDefaultSearchProviderSuggestURLPostParams, 99 base::Value::TYPE_STRING }, 100 { key::kDefaultSearchProviderInstantURLPostParams, 101 prefs::kDefaultSearchProviderInstantURLPostParams, 102 base::Value::TYPE_STRING }, 103 { key::kDefaultSearchProviderImageURLPostParams, 104 prefs::kDefaultSearchProviderImageURLPostParams, 105 base::Value::TYPE_STRING }, 106}; 107 108// List of policy types to preference names, for policies affecting the default 109// search provider. 110const PolicyToPreferenceMapEntry kDefaultSearchPolicyDataMap[] = { 111 {key::kDefaultSearchProviderName, DefaultSearchManager::kShortName, 112 base::Value::TYPE_STRING}, 113 {key::kDefaultSearchProviderKeyword, DefaultSearchManager::kKeyword, 114 base::Value::TYPE_STRING}, 115 {key::kDefaultSearchProviderSearchURL, DefaultSearchManager::kURL, 116 base::Value::TYPE_STRING}, 117 {key::kDefaultSearchProviderSuggestURL, 118 DefaultSearchManager::kSuggestionsURL, base::Value::TYPE_STRING}, 119 {key::kDefaultSearchProviderInstantURL, DefaultSearchManager::kInstantURL, 120 base::Value::TYPE_STRING}, 121 {key::kDefaultSearchProviderIconURL, DefaultSearchManager::kFaviconURL, 122 base::Value::TYPE_STRING}, 123 {key::kDefaultSearchProviderEncodings, 124 DefaultSearchManager::kInputEncodings, base::Value::TYPE_LIST}, 125 {key::kDefaultSearchProviderAlternateURLs, 126 DefaultSearchManager::kAlternateURLs, base::Value::TYPE_LIST}, 127 {key::kDefaultSearchProviderSearchTermsReplacementKey, 128 DefaultSearchManager::kSearchTermsReplacementKey, 129 base::Value::TYPE_STRING}, 130 {key::kDefaultSearchProviderImageURL, DefaultSearchManager::kImageURL, 131 base::Value::TYPE_STRING}, 132 {key::kDefaultSearchProviderNewTabURL, DefaultSearchManager::kNewTabURL, 133 base::Value::TYPE_STRING}, 134 {key::kDefaultSearchProviderSearchURLPostParams, 135 DefaultSearchManager::kSearchURLPostParams, base::Value::TYPE_STRING}, 136 {key::kDefaultSearchProviderSuggestURLPostParams, 137 DefaultSearchManager::kSuggestionsURLPostParams, base::Value::TYPE_STRING}, 138 {key::kDefaultSearchProviderInstantURLPostParams, 139 DefaultSearchManager::kInstantURLPostParams, base::Value::TYPE_STRING}, 140 {key::kDefaultSearchProviderImageURLPostParams, 141 DefaultSearchManager::kImageURLPostParams, base::Value::TYPE_STRING}, 142}; 143 144// DefaultSearchEncodingsPolicyHandler implementation -------------------------- 145 146DefaultSearchEncodingsPolicyHandler::DefaultSearchEncodingsPolicyHandler() 147 : TypeCheckingPolicyHandler(key::kDefaultSearchProviderEncodings, 148 base::Value::TYPE_LIST) {} 149 150DefaultSearchEncodingsPolicyHandler::~DefaultSearchEncodingsPolicyHandler() { 151} 152 153void DefaultSearchEncodingsPolicyHandler::ApplyPolicySettings( 154 const PolicyMap& policies, PrefValueMap* prefs) { 155 // The DefaultSearchProviderEncodings policy has type list, but the related 156 // preference has type string. Convert one into the other here, using 157 // ';' as a separator. 158 const base::Value* value = policies.GetValue(policy_name()); 159 const base::ListValue* list; 160 if (!value || !value->GetAsList(&list)) 161 return; 162 163 base::ListValue::const_iterator iter(list->begin()); 164 base::ListValue::const_iterator end(list->end()); 165 std::vector<std::string> string_parts; 166 for (; iter != end; ++iter) { 167 std::string s; 168 if ((*iter)->GetAsString(&s)) { 169 string_parts.push_back(s); 170 } 171 } 172 std::string encodings = JoinString(string_parts, ';'); 173 prefs->SetString(prefs::kDefaultSearchProviderEncodings, encodings); 174} 175 176 177// DefaultSearchPolicyHandler implementation ----------------------------------- 178 179DefaultSearchPolicyHandler::DefaultSearchPolicyHandler() { 180 for (size_t i = 0; i < arraysize(kDefaultSearchPolicyMap); ++i) { 181 const char* policy_name = kDefaultSearchPolicyMap[i].policy_name; 182 if (policy_name == key::kDefaultSearchProviderEncodings) { 183 handlers_.push_back(new DefaultSearchEncodingsPolicyHandler()); 184 } else { 185 handlers_.push_back(new SimplePolicyHandler( 186 policy_name, 187 kDefaultSearchPolicyMap[i].preference_path, 188 kDefaultSearchPolicyMap[i].value_type)); 189 } 190 } 191} 192 193DefaultSearchPolicyHandler::~DefaultSearchPolicyHandler() { 194 STLDeleteElements(&handlers_); 195} 196 197bool DefaultSearchPolicyHandler::CheckPolicySettings(const PolicyMap& policies, 198 PolicyErrorMap* errors) { 199 if (!CheckIndividualPolicies(policies, errors)) 200 return false; 201 202 if (DefaultSearchProviderIsDisabled(policies)) { 203 // Add an error for all specified default search policies except 204 // DefaultSearchProviderEnabled. 205 206 for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler = 207 handlers_.begin(); 208 handler != handlers_.end(); ++handler) { 209 const char* policy_name = (*handler)->policy_name(); 210 if (policy_name != key::kDefaultSearchProviderEnabled && 211 HasDefaultSearchPolicy(policies, policy_name)) { 212 errors->AddError(policy_name, IDS_POLICY_DEFAULT_SEARCH_DISABLED); 213 } 214 } 215 return true; 216 } 217 218 const base::Value* url; 219 std::string dummy; 220 if (DefaultSearchURLIsValid(policies, &url, &dummy) || 221 !AnyDefaultSearchPoliciesSpecified(policies)) 222 return true; 223 errors->AddError(key::kDefaultSearchProviderSearchURL, url ? 224 IDS_POLICY_INVALID_SEARCH_URL_ERROR : IDS_POLICY_NOT_SPECIFIED_ERROR); 225 return false; 226} 227 228void DefaultSearchPolicyHandler::HandleDictionaryPref(const PolicyMap& policies, 229 PrefValueMap* prefs) { 230 if (DefaultSearchProviderIsDisabled(policies)) { 231 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); 232 dict->SetBoolean(DefaultSearchManager::kDisabledByPolicy, true); 233 DefaultSearchManager::AddPrefValueToMap(dict.release(), prefs); 234 return; 235 } 236 237 // The search URL is required. The other entries are optional. Just make 238 // sure that they are all specified via policy, so that the regular prefs 239 // aren't used. 240 const base::Value* dummy; 241 std::string url; 242 if (!DefaultSearchURLIsValid(policies, &dummy, &url)) 243 return; 244 245 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); 246 for (size_t i = 0; i < arraysize(kDefaultSearchPolicyDataMap); ++i) { 247 const char* policy_name = kDefaultSearchPolicyDataMap[i].policy_name; 248 switch (kDefaultSearchPolicyDataMap[i].value_type) { 249 case base::Value::TYPE_STRING: 250 SetStringInPref(policies, 251 policy_name, 252 kDefaultSearchPolicyDataMap[i].preference_path, 253 dict.get()); 254 break; 255 case base::Value::TYPE_LIST: 256 SetListInPref(policies, 257 policy_name, 258 kDefaultSearchPolicyDataMap[i].preference_path, 259 dict.get()); 260 break; 261 default: 262 NOTREACHED(); 263 break; 264 } 265 } 266 267 // Set the fields which are not specified by the policy to default values. 268 dict->SetString(DefaultSearchManager::kID, 269 base::Int64ToString(kInvalidTemplateURLID)); 270 dict->SetInteger(DefaultSearchManager::kPrepopulateID, 0); 271 dict->SetString(DefaultSearchManager::kSyncGUID, std::string()); 272 dict->SetString(DefaultSearchManager::kOriginatingURL, std::string()); 273 dict->SetBoolean(DefaultSearchManager::kSafeForAutoReplace, true); 274 dict->SetDouble(DefaultSearchManager::kDateCreated, 275 base::Time::Now().ToInternalValue()); 276 dict->SetDouble(DefaultSearchManager::kLastModified, 277 base::Time::Now().ToInternalValue()); 278 dict->SetInteger(DefaultSearchManager::kUsageCount, 0); 279 dict->SetBoolean(DefaultSearchManager::kCreatedByPolicy, true); 280 281 // For the name and keyword, default to the host if not specified. If 282 // there is no host (as is the case with file URLs of the form: 283 // "file:///c:/..."), use "_" to guarantee that the keyword is non-empty. 284 std::string name, keyword; 285 dict->GetString(DefaultSearchManager::kKeyword, &keyword); 286 dict->GetString(DefaultSearchManager::kShortName, &name); 287 dict->GetString(DefaultSearchManager::kURL, &url); 288 289 std::string host(GURL(url).host()); 290 if (host.empty()) 291 host = "_"; 292 if (name.empty()) 293 dict->SetString(DefaultSearchManager::kShortName, host); 294 if (keyword.empty()) 295 dict->SetString(DefaultSearchManager::kKeyword, host); 296 297 DefaultSearchManager::AddPrefValueToMap(dict.release(), prefs); 298} 299 300void DefaultSearchPolicyHandler::ApplyPolicySettings(const PolicyMap& policies, 301 PrefValueMap* prefs) { 302 HandleDictionaryPref(policies, prefs); 303 304 if (DefaultSearchProviderIsDisabled(policies)) { 305 prefs->SetBoolean(prefs::kDefaultSearchProviderEnabled, false); 306 307 // If default search is disabled, the other fields are ignored. 308 prefs->SetString(prefs::kDefaultSearchProviderName, std::string()); 309 prefs->SetString(prefs::kDefaultSearchProviderSearchURL, std::string()); 310 prefs->SetString(prefs::kDefaultSearchProviderSuggestURL, std::string()); 311 prefs->SetString(prefs::kDefaultSearchProviderIconURL, std::string()); 312 prefs->SetString(prefs::kDefaultSearchProviderEncodings, std::string()); 313 prefs->SetString(prefs::kDefaultSearchProviderKeyword, std::string()); 314 prefs->SetString(prefs::kDefaultSearchProviderInstantURL, std::string()); 315 prefs->SetString(prefs::kDefaultSearchProviderNewTabURL, std::string()); 316 prefs->SetValue(prefs::kDefaultSearchProviderAlternateURLs, 317 new base::ListValue()); 318 prefs->SetString( 319 prefs::kDefaultSearchProviderSearchTermsReplacementKey, std::string()); 320 prefs->SetString(prefs::kDefaultSearchProviderImageURL, std::string()); 321 prefs->SetString( 322 prefs::kDefaultSearchProviderSearchURLPostParams, std::string()); 323 prefs->SetString( 324 prefs::kDefaultSearchProviderSuggestURLPostParams, std::string()); 325 prefs->SetString( 326 prefs::kDefaultSearchProviderInstantURLPostParams, std::string()); 327 prefs->SetString( 328 prefs::kDefaultSearchProviderImageURLPostParams, std::string()); 329 } else { 330 // The search URL is required. The other entries are optional. Just make 331 // sure that they are all specified via policy, so that the regular prefs 332 // aren't used. 333 const base::Value* dummy; 334 std::string url; 335 if (DefaultSearchURLIsValid(policies, &dummy, &url)) { 336 337 for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler = 338 handlers_.begin(); 339 handler != handlers_.end(); ++handler) { 340 (*handler)->ApplyPolicySettings(policies, prefs); 341 } 342 343 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderSuggestURL); 344 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderIconURL); 345 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderEncodings); 346 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderKeyword); 347 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderInstantURL); 348 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderNewTabURL); 349 EnsureListPrefExists(prefs, prefs::kDefaultSearchProviderAlternateURLs); 350 EnsureStringPrefExists( 351 prefs, 352 prefs::kDefaultSearchProviderSearchTermsReplacementKey); 353 EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderImageURL); 354 EnsureStringPrefExists( 355 prefs, 356 prefs::kDefaultSearchProviderSearchURLPostParams); 357 EnsureStringPrefExists( 358 prefs, 359 prefs::kDefaultSearchProviderSuggestURLPostParams); 360 EnsureStringPrefExists( 361 prefs, 362 prefs::kDefaultSearchProviderInstantURLPostParams); 363 EnsureStringPrefExists( 364 prefs, 365 prefs::kDefaultSearchProviderImageURLPostParams); 366 367 // For the name and keyword, default to the host if not specified. If 368 // there is no host (file: URLs? Not sure), use "_" to guarantee that the 369 // keyword is non-empty. 370 std::string name, keyword; 371 std::string host(GURL(url).host()); 372 if (host.empty()) 373 host = "_"; 374 if (!prefs->GetString(prefs::kDefaultSearchProviderName, &name) || 375 name.empty()) { 376 prefs->SetString(prefs::kDefaultSearchProviderName, host); 377 } 378 if (!prefs->GetString(prefs::kDefaultSearchProviderKeyword, &keyword) || 379 keyword.empty()) { 380 prefs->SetString(prefs::kDefaultSearchProviderKeyword, host); 381 } 382 383 // And clear the IDs since these are not specified via policy. 384 prefs->SetString(prefs::kDefaultSearchProviderID, std::string()); 385 prefs->SetString(prefs::kDefaultSearchProviderPrepopulateID, 386 std::string()); 387 } 388 } 389} 390 391bool DefaultSearchPolicyHandler::CheckIndividualPolicies( 392 const PolicyMap& policies, 393 PolicyErrorMap* errors) { 394 for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler = 395 handlers_.begin(); 396 handler != handlers_.end(); ++handler) { 397 if (!(*handler)->CheckPolicySettings(policies, errors)) 398 return false; 399 } 400 return true; 401} 402 403bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy( 404 const PolicyMap& policies, 405 const char* policy_name) { 406 return policies.Get(policy_name) != NULL; 407} 408 409bool DefaultSearchPolicyHandler::AnyDefaultSearchPoliciesSpecified( 410 const PolicyMap& policies) { 411 for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler = 412 handlers_.begin(); 413 handler != handlers_.end(); ++handler) { 414 if (policies.Get((*handler)->policy_name())) 415 return true; 416 } 417 return false; 418} 419 420bool DefaultSearchPolicyHandler::DefaultSearchProviderIsDisabled( 421 const PolicyMap& policies) { 422 const base::Value* provider_enabled = 423 policies.GetValue(key::kDefaultSearchProviderEnabled); 424 bool enabled = true; 425 return provider_enabled && provider_enabled->GetAsBoolean(&enabled) && 426 !enabled; 427} 428 429bool DefaultSearchPolicyHandler::DefaultSearchURLIsValid( 430 const PolicyMap& policies, 431 const base::Value** url_value, 432 std::string* url_string) { 433 *url_value = policies.GetValue(key::kDefaultSearchProviderSearchURL); 434 if (!*url_value || !(*url_value)->GetAsString(url_string) || 435 url_string->empty()) 436 return false; 437 TemplateURLData data; 438 data.SetURL(*url_string); 439 SearchTermsData search_terms_data; 440 return TemplateURL(data).SupportsReplacement(search_terms_data); 441} 442 443void DefaultSearchPolicyHandler::EnsureStringPrefExists( 444 PrefValueMap* prefs, 445 const std::string& path) { 446 std::string value; 447 if (!prefs->GetString(path, &value)) 448 prefs->SetString(path, value); 449} 450 451void DefaultSearchPolicyHandler::EnsureListPrefExists( 452 PrefValueMap* prefs, 453 const std::string& path) { 454 base::Value* value; 455 base::ListValue* list_value; 456 if (!prefs->GetValue(path, &value) || !value->GetAsList(&list_value)) 457 prefs->SetValue(path, new base::ListValue()); 458} 459 460} // namespace policy 461