1 // Copyright 2019 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/spellchecker/spellcheck_language_blacklist_policy_handler.h"
6
7 #include <unordered_set>
8 #include <utility>
9 #include <vector>
10
11 #include "base/strings/string_util.h"
12 #include "base/syslog_logging.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/policy/core/browser/policy_error_map.h"
17 #include "components/policy/policy_constants.h"
18 #include "components/prefs/pref_value_map.h"
19 #include "components/spellcheck/browser/pref_names.h"
20 #include "components/spellcheck/common/spellcheck_common.h"
21 #include "components/strings/grit/components_strings.h"
22
23 SpellcheckLanguageBlacklistPolicyHandler::
SpellcheckLanguageBlacklistPolicyHandler()24 SpellcheckLanguageBlacklistPolicyHandler()
25 : TypeCheckingPolicyHandler(policy::key::kSpellcheckLanguageBlacklist,
26 base::Value::Type::LIST) {}
27
28 SpellcheckLanguageBlacklistPolicyHandler::
29 ~SpellcheckLanguageBlacklistPolicyHandler() = default;
30
CheckPolicySettings(const policy::PolicyMap & policies,policy::PolicyErrorMap * errors)31 bool SpellcheckLanguageBlacklistPolicyHandler::CheckPolicySettings(
32 const policy::PolicyMap& policies,
33 policy::PolicyErrorMap* errors) {
34 const base::Value* value = nullptr;
35 bool ok = CheckAndGetValue(policies, errors, &value);
36
37 std::vector<base::Value> blacklisted;
38 std::vector<std::string> unknown;
39 std::vector<std::string> duplicates;
40 SortBlacklistedLanguages(policies, &blacklisted, &unknown, &duplicates);
41
42 #if !defined(OS_MACOSX)
43 for (const std::string& language : duplicates) {
44 errors->AddError(policy_name(), IDS_POLICY_SPELLCHECK_BLACKLIST_IGNORE,
45 language);
46 }
47
48 for (const std::string& language : unknown) {
49 errors->AddError(policy_name(), IDS_POLICY_SPELLCHECK_UNKNOWN_LANGUAGE,
50 language);
51 }
52 #endif
53
54 return ok;
55 }
56
ApplyPolicySettings(const policy::PolicyMap & policies,PrefValueMap * prefs)57 void SpellcheckLanguageBlacklistPolicyHandler::ApplyPolicySettings(
58 const policy::PolicyMap& policies,
59 PrefValueMap* prefs) {
60 // Ignore this policy if the SpellcheckEnabled policy disables spellcheck.
61 const base::Value* spellcheck_enabled_value =
62 policies.GetValue(policy::key::kSpellcheckEnabled);
63 if (spellcheck_enabled_value && spellcheck_enabled_value->GetBool() == false)
64 return;
65
66 // If this policy isn't set, don't modify spellcheck languages.
67 const base::Value* value = policies.GetValue(policy_name());
68 if (!value)
69 return;
70
71 // Set the blacklisted dictionaries preference based on this policy's values,
72 // and emit warnings for unknown or duplicate languages.
73 std::vector<base::Value> blacklisted;
74 std::vector<std::string> unknown;
75 std::vector<std::string> duplicates;
76 SortBlacklistedLanguages(policies, &blacklisted, &unknown, &duplicates);
77
78 for (const std::string& language : duplicates) {
79 SYSLOG(WARNING)
80 << "SpellcheckLanguageBlacklist policy: an entry was also found in"
81 " the SpellcheckLanguage policy: \""
82 << language << "\". Blacklist entry will be ignored.";
83 }
84
85 for (const std::string& language : unknown) {
86 SYSLOG(WARNING) << "SpellcheckLanguageBlacklist policy: Unknown or "
87 "unsupported language \""
88 << language << "\"";
89 }
90
91 prefs->SetValue(spellcheck::prefs::kSpellCheckBlacklistedDictionaries,
92 base::Value(std::move(blacklisted)));
93 }
94
SortBlacklistedLanguages(const policy::PolicyMap & policies,std::vector<base::Value> * const blacklisted,std::vector<std::string> * const unknown,std::vector<std::string> * const duplicates)95 void SpellcheckLanguageBlacklistPolicyHandler::SortBlacklistedLanguages(
96 const policy::PolicyMap& policies,
97 std::vector<base::Value>* const blacklisted,
98 std::vector<std::string>* const unknown,
99 std::vector<std::string>* const duplicates) {
100 const base::Value* value = policies.GetValue(policy_name());
101 if (!value)
102 return;
103
104 // Build a lookup of force-enabled spellcheck languages to find duplicates.
105 const base::Value* forced_enabled_value =
106 policies.GetValue(policy::key::kSpellcheckLanguage);
107 std::unordered_set<std::string> forced_languages_lookup;
108 if (forced_enabled_value) {
109 for (const auto& forced_language : forced_enabled_value->GetList())
110 forced_languages_lookup.insert(forced_language.GetString());
111 }
112
113 // Separate the valid languages from the unknown / unsupported languages and
114 // the languages that also appear in the SpellcheckLanguage policy.
115 for (const base::Value& language : value->GetList()) {
116 std::string current_language =
117 spellcheck::GetCorrespondingSpellCheckLanguage(
118 base::TrimWhitespaceASCII(language.GetString(), base::TRIM_ALL));
119
120 if (current_language.empty()) {
121 unknown->emplace_back(language.GetString());
122 } else {
123 if (forced_languages_lookup.find(language.GetString()) !=
124 forced_languages_lookup.end()) {
125 // If a language is both force-enabled and force-disabled, force-enable
126 // wins. Put the language in the list of duplicates.
127 duplicates->emplace_back(std::move(current_language));
128 } else {
129 blacklisted->emplace_back(std::move(current_language));
130 }
131 }
132 }
133 }
134