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