1 // Copyright 2017 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/safe_browsing/settings_reset_prompt/settings_reset_prompt_model.h"
6
7 #include <utility>
8
9 #include "base/callback.h"
10 #include "base/callback_helpers.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "chrome/browser/prefs/session_startup_pref.h"
14 #include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
15 #include "chrome/browser/profile_resetter/profile_resetter.h"
16 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h"
19 #include "chrome/browser/search_engines/template_url_service_factory.h"
20 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/prefs/pref_service.h"
23 #include "components/search_engines/template_url_service.h"
24 #include "components/url_formatter/url_fixer.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_id.h"
29
30 namespace safe_browsing {
31
32 namespace {
33
34 // These values are used for UMA metrics reporting. New enum values can be
35 // added, but existing enums must never be renumbered or deleted and reused.
36 enum SettingsReset {
37 SETTINGS_RESET_HOMEPAGE = 1,
38 SETTINGS_RESET_DEFAULT_SEARCH = 2,
39 SETTINGS_RESET_STARTUP_URLS = 3,
40 SETTINGS_RESET_MAX,
41 };
42
43 // Used to keep track of which settings types have been initialized in
44 // |SettingsResetPromptModel|.
45 enum SettingsType : uint32_t {
46 SETTINGS_TYPE_HOMEPAGE = 1 << 0,
47 SETTINGS_TYPE_DEFAULT_SEARCH = 1 << 1,
48 SETTINGS_TYPE_STARTUP_URLS = 1 << 2,
49 SETTINGS_TYPE_ALL = SETTINGS_TYPE_HOMEPAGE | SETTINGS_TYPE_DEFAULT_SEARCH |
50 SETTINGS_TYPE_STARTUP_URLS,
51 };
52
GetExtension(Profile * profile,const extensions::ExtensionId & extension_id)53 const extensions::Extension* GetExtension(
54 Profile* profile,
55 const extensions::ExtensionId& extension_id) {
56 return extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
57 extension_id);
58 }
59
FixupUrl(const std::string & url_text)60 GURL FixupUrl(const std::string& url_text) {
61 return url_formatter::FixupURL(url_text, /*desired_tld=*/std::string());
62 }
63
64 } // namespace
65
SettingsResetPromptModel(Profile * profile,std::unique_ptr<SettingsResetPromptConfig> prompt_config,std::unique_ptr<ProfileResetter> profile_resetter)66 SettingsResetPromptModel::SettingsResetPromptModel(
67 Profile* profile,
68 std::unique_ptr<SettingsResetPromptConfig> prompt_config,
69 std::unique_ptr<ProfileResetter> profile_resetter)
70 : profile_(profile),
71 prefs_manager_(profile, prompt_config->prompt_wave()),
72 prompt_config_(std::move(prompt_config)),
73 settings_snapshot_(std::make_unique<ResettableSettingsSnapshot>(profile)),
74 profile_resetter_(std::move(profile_resetter)),
75 time_since_last_prompt_(base::Time::Now() -
76 prefs_manager_.LastTriggeredPrompt()) {
77 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
78 DCHECK(profile_);
79 DCHECK(prompt_config_);
80 DCHECK(settings_snapshot_);
81 DCHECK(profile_resetter_);
82
83 InitDefaultSearchData();
84 InitStartupUrlsData();
85 InitHomepageData();
86 DCHECK_EQ(settings_types_initialized_, SETTINGS_TYPE_ALL);
87
88 BlockResetForSettingOverridenByExtension();
89
90 if (!SomeSettingRequiresReset())
91 return;
92
93 // For now, during the experimental phase, if policy controls any of the
94 // settings that we consider for reset (search, startup pages, homepage) or if
95 // an extension that needs to be disabled is managed by policy, then we do not
96 // show the reset prompt.
97 //
98 // TODO(alito): Consider how clients with policies should be prompted for
99 // reset.
100 if (SomeSettingIsManaged()) {
101 if (homepage_reset_state_ == RESET_REQUIRED)
102 homepage_reset_state_ = NO_RESET_REQUIRED_DUE_TO_POLICY;
103 if (default_search_reset_state_ == RESET_REQUIRED)
104 default_search_reset_state_ = NO_RESET_REQUIRED_DUE_TO_POLICY;
105 if (startup_urls_reset_state_ == RESET_REQUIRED)
106 startup_urls_reset_state_ = NO_RESET_REQUIRED_DUE_TO_POLICY;
107 }
108 }
109
~SettingsResetPromptModel()110 SettingsResetPromptModel::~SettingsResetPromptModel() {}
111
profile() const112 Profile* SettingsResetPromptModel::profile() const {
113 return profile_;
114 }
115
config() const116 SettingsResetPromptConfig* SettingsResetPromptModel::config() const {
117 return prompt_config_.get();
118 }
119
ShouldPromptForReset() const120 bool SettingsResetPromptModel::ShouldPromptForReset() const {
121 return SomeSettingRequiresReset();
122 }
123
PerformReset(std::unique_ptr<BrandcodedDefaultSettings> default_settings,base::OnceClosure done_callback)124 void SettingsResetPromptModel::PerformReset(
125 std::unique_ptr<BrandcodedDefaultSettings> default_settings,
126 base::OnceClosure done_callback) {
127 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
128 DCHECK(default_settings);
129
130 // Disable all the settings that need to be reset.
131 ProfileResetter::ResettableFlags reset_flags = 0;
132 if (homepage_reset_state() == RESET_REQUIRED) {
133 reset_flags |= ProfileResetter::HOMEPAGE;
134 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.SettingsReset",
135 SETTINGS_RESET_HOMEPAGE, SETTINGS_RESET_MAX);
136 }
137 if (default_search_reset_state() == RESET_REQUIRED) {
138 reset_flags |= ProfileResetter::DEFAULT_SEARCH_ENGINE;
139 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.SettingsReset",
140 SETTINGS_RESET_DEFAULT_SEARCH,
141 SETTINGS_RESET_MAX);
142 }
143 if (startup_urls_reset_state() == RESET_REQUIRED) {
144 reset_flags |= ProfileResetter::STARTUP_PAGES;
145 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.SettingsReset",
146 SETTINGS_RESET_STARTUP_URLS, SETTINGS_RESET_MAX);
147 }
148
149 profile_resetter_->Reset(reset_flags, std::move(default_settings),
150 std::move(done_callback));
151 }
152
DialogShown()153 void SettingsResetPromptModel::DialogShown() {
154 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
155 DCHECK(SomeSettingRequiresReset());
156
157 base::Time now = base::Time::Now();
158 if (default_search_reset_state() == RESET_REQUIRED)
159 prefs_manager_.RecordPromptShownForDefaultSearch(now);
160 if (startup_urls_reset_state() == RESET_REQUIRED)
161 prefs_manager_.RecordPromptShownForStartupUrls(now);
162 if (homepage_reset_state() == RESET_REQUIRED)
163 prefs_manager_.RecordPromptShownForHomepage(now);
164 }
165
homepage() const166 GURL SettingsResetPromptModel::homepage() const {
167 return homepage_url_;
168 }
169
170 SettingsResetPromptModel::ResetState
homepage_reset_state() const171 SettingsResetPromptModel::homepage_reset_state() const {
172 DCHECK(homepage_reset_state_ != RESET_REQUIRED ||
173 homepage_reset_domain_id_ >= 0);
174 return homepage_reset_state_;
175 }
176
default_search() const177 GURL SettingsResetPromptModel::default_search() const {
178 return default_search_url_;
179 }
180
181 SettingsResetPromptModel::ResetState
default_search_reset_state() const182 SettingsResetPromptModel::default_search_reset_state() const {
183 DCHECK(default_search_reset_state_ != RESET_REQUIRED ||
184 default_search_reset_domain_id_ >= 0);
185 return default_search_reset_state_;
186 }
187
startup_urls() const188 const std::vector<GURL>& SettingsResetPromptModel::startup_urls() const {
189 return startup_urls_;
190 }
191
startup_urls_to_reset() const192 const std::vector<GURL>& SettingsResetPromptModel::startup_urls_to_reset()
193 const {
194 return startup_urls_to_reset_;
195 }
196
197 SettingsResetPromptModel::ResetState
startup_urls_reset_state() const198 SettingsResetPromptModel::startup_urls_reset_state() const {
199 return startup_urls_reset_state_;
200 }
201
ReportUmaMetrics() const202 void SettingsResetPromptModel::ReportUmaMetrics() const {
203 UMA_HISTOGRAM_BOOLEAN("SettingsResetPrompt.PromptRequired",
204 ShouldPromptForReset());
205 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ResetState_DefaultSearch",
206 default_search_reset_state(), RESET_STATE_MAX);
207 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ResetState_StartupUrls",
208 startup_urls_reset_state(), RESET_STATE_MAX);
209 UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ResetState_Homepage",
210 homepage_reset_state(), RESET_STATE_MAX);
211 }
212
InitDefaultSearchData()213 void SettingsResetPromptModel::InitDefaultSearchData() {
214 // Default search data must be the first setting type to be initialized.
215 DCHECK_EQ(settings_types_initialized_, 0U);
216
217 settings_types_initialized_ |= SETTINGS_TYPE_DEFAULT_SEARCH;
218
219 default_search_url_ = FixupUrl(settings_snapshot_->dse_url());
220 default_search_reset_domain_id_ =
221 prompt_config_->UrlToResetDomainId(default_search_url_);
222 if (default_search_reset_domain_id_ < 0)
223 return;
224
225 default_search_reset_state_ = GetResetStateForSetting(
226 prefs_manager_.LastTriggeredPromptForDefaultSearch());
227 }
228
InitStartupUrlsData()229 void SettingsResetPromptModel::InitStartupUrlsData() {
230 // Default search data must have been initialized before startup URLs data.
231 DCHECK_EQ(settings_types_initialized_, SETTINGS_TYPE_DEFAULT_SEARCH);
232
233 settings_types_initialized_ |= SETTINGS_TYPE_STARTUP_URLS;
234
235 // Only the SessionStartupPref::URLS startup type is a candidate for
236 // resetting.
237 if (settings_snapshot_->startup_type() != SessionStartupPref::URLS)
238 return;
239
240 for (const GURL& startup_url : settings_snapshot_->startup_urls()) {
241 GURL fixed_url = FixupUrl(startup_url.possibly_invalid_spec());
242 startup_urls_.push_back(fixed_url);
243 int reset_domain_id = prompt_config_->UrlToResetDomainId(fixed_url);
244 if (reset_domain_id >= 0) {
245 startup_urls_to_reset_.push_back(fixed_url);
246 domain_ids_for_startup_urls_to_reset_.insert(reset_domain_id);
247 }
248 }
249
250 if (startup_urls_to_reset_.empty())
251 return;
252
253 startup_urls_reset_state_ = GetResetStateForSetting(
254 prefs_manager_.LastTriggeredPromptForStartupUrls());
255 }
256
InitHomepageData()257 void SettingsResetPromptModel::InitHomepageData() {
258 // Homepage data must be initialized after default search and startup URLs
259 // data.
260 DCHECK_EQ(settings_types_initialized_,
261 SETTINGS_TYPE_DEFAULT_SEARCH | SETTINGS_TYPE_STARTUP_URLS);
262
263 settings_types_initialized_ |= SETTINGS_TYPE_HOMEPAGE;
264
265 homepage_url_ = FixupUrl(settings_snapshot_->homepage());
266
267 // If the home button is not visible to the user, then the homepage setting
268 // has no real user-visible effect.
269 if (!settings_snapshot_->show_home_button())
270 return;
271
272 // We do not currently support resetting New Tab pages that are set by
273 // extensions.
274 if (settings_snapshot_->homepage_is_ntp())
275 return;
276
277 homepage_reset_domain_id_ = prompt_config_->UrlToResetDomainId(homepage_url_);
278 if (homepage_reset_domain_id_ < 0)
279 return;
280
281 homepage_reset_state_ =
282 GetResetStateForSetting(prefs_manager_.LastTriggeredPromptForHomepage());
283 }
284
285 // Reverts the decision to reset some setting if it's overriden by an extension.
286 // This function should be called after other Init*() functions.
BlockResetForSettingOverridenByExtension()287 void SettingsResetPromptModel::BlockResetForSettingOverridenByExtension() {
288 DCHECK_EQ(settings_types_initialized_, SETTINGS_TYPE_ALL);
289
290 // |enabled_extensions()| is a container of [id, name] pairs.
291 for (const auto& id_name : settings_snapshot_->enabled_extensions()) {
292 const extensions::Extension* extension =
293 GetExtension(profile_, id_name.first);
294 if (!extension)
295 continue;
296
297 const extensions::SettingsOverrides* overrides =
298 extensions::SettingsOverrides::Get(extension);
299 if (!overrides)
300 continue;
301
302 if (homepage_reset_state_ == RESET_REQUIRED && overrides->homepage)
303 homepage_reset_state_ = NO_RESET_REQUIRED_DUE_TO_EXTENSION_OVERRIDE;
304 if (default_search_reset_state_ == RESET_REQUIRED &&
305 overrides->search_engine) {
306 default_search_reset_state_ = NO_RESET_REQUIRED_DUE_TO_EXTENSION_OVERRIDE;
307 }
308 if (startup_urls_reset_state_ == RESET_REQUIRED &&
309 !overrides->startup_pages.empty()) {
310 startup_urls_reset_state_ = NO_RESET_REQUIRED_DUE_TO_EXTENSION_OVERRIDE;
311 }
312 }
313 }
314
315 SettingsResetPromptModel::ResetState
GetResetStateForSetting(const base::Time & last_triggered_for_setting) const316 SettingsResetPromptModel::GetResetStateForSetting(
317 const base::Time& last_triggered_for_setting) const {
318 if (!last_triggered_for_setting.is_null())
319 return NO_RESET_REQUIRED_DUE_TO_ALREADY_PROMPTED_FOR_SETTING;
320
321 if (time_since_last_prompt_ < prompt_config_->time_between_prompts())
322 return NO_RESET_REQUIRED_DUE_TO_RECENTLY_PROMPTED;
323
324 if (SomeSettingRequiresReset())
325 return NO_RESET_REQUIRED_DUE_TO_OTHER_SETTING_REQUIRING_RESET;
326
327 return RESET_REQUIRED;
328 }
329
SomeSettingRequiresReset() const330 bool SettingsResetPromptModel::SomeSettingRequiresReset() const {
331 return default_search_reset_state_ == RESET_REQUIRED ||
332 startup_urls_reset_state_ == RESET_REQUIRED ||
333 homepage_reset_state_ == RESET_REQUIRED;
334 }
335
SomeSettingIsManaged() const336 bool SettingsResetPromptModel::SomeSettingIsManaged() const {
337 PrefService* prefs = profile_->GetPrefs();
338 DCHECK(prefs);
339
340 // Check if homepage is managed.
341 const PrefService::Preference* homepage =
342 prefs->FindPreference(prefs::kHomePage);
343 if (homepage && (homepage->IsManaged() || homepage->IsManagedByCustodian()))
344 return true;
345
346 // Check if startup pages are managed.
347 if (SessionStartupPref::TypeIsManaged(prefs) ||
348 SessionStartupPref::URLsAreManaged(prefs)) {
349 return true;
350 }
351
352 // Check if default search is managed.
353 TemplateURLService* service =
354 TemplateURLServiceFactory::GetForProfile(profile_);
355 if (service && service->is_default_search_managed())
356 return true;
357
358 return false;
359 }
360
361 } // namespace safe_browsing.
362