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