1 // Copyright 2013 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/ui/webui/settings/reset_settings_handler.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/metrics/user_metrics.h"
13 #include "base/strings/string16.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "build/build_config.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/google/google_brand.h"
19 #include "chrome/browser/net/system_network_context_manager.h"
20 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
21 #include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
22 #include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
23 #include "chrome/browser/profile_resetter/profile_resetter.h"
24 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/prefs/pref_service.h"
29 #include "content/public/browser/web_ui.h"
30 #include "content/public/browser/web_ui_data_source.h"
31 #include "services/network/public/mojom/url_loader_factory.mojom.h"
32 #include "ui/base/l10n/l10n_util.h"
33 
34 #if defined(OS_CHROMEOS)
35 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/browser_process_platform_part.h"
37 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
38 #include "chrome/browser/chromeos/reset/metrics.h"
39 #include "chrome/common/pref_names.h"
40 #include "components/user_manager/user_manager.h"
41 #endif  // defined(OS_CHROMEOS)
42 
43 #if defined(OS_WIN)
44 #include "chrome/browser/profile_resetter/triggered_profile_resetter.h"
45 #include "chrome/browser/profile_resetter/triggered_profile_resetter_factory.h"
46 #endif  // defined(OS_WIN)
47 
48 namespace settings {
49 
50 namespace {
51 
52 reset_report::ChromeResetReport::ResetRequestOrigin
ResetRequestOriginFromString(const std::string & request_origin)53 ResetRequestOriginFromString(const std::string& request_origin) {
54   static const char kOriginUserClick[] = "userclick";
55   static const char kOriginTriggeredReset[] = "triggeredreset";
56 
57   if (request_origin == ResetSettingsHandler::kCctResetSettingsHash)
58     return reset_report::ChromeResetReport::RESET_REQUEST_ORIGIN_CCT;
59   if (request_origin == kOriginUserClick)
60     return reset_report::ChromeResetReport::RESET_REQUEST_ORIGIN_USER_CLICK;
61   if (request_origin == kOriginTriggeredReset) {
62     return reset_report::ChromeResetReport::
63         RESET_REQUEST_ORIGIN_TRIGGERED_RESET;
64   }
65   if (!request_origin.empty())
66     NOTREACHED();
67 
68   return reset_report::ChromeResetReport::RESET_REQUEST_ORIGIN_UNKNOWN;
69 }
70 
71 }  // namespace
72 
73 const char ResetSettingsHandler::kCctResetSettingsHash[] = "cct";
74 
ResetSettingsHandler(Profile * profile)75 ResetSettingsHandler::ResetSettingsHandler(Profile* profile)
76     : profile_(profile) {
77   google_brand::GetBrand(&brandcode_);
78 }
79 
~ResetSettingsHandler()80 ResetSettingsHandler::~ResetSettingsHandler() {}
81 
Create(content::WebUIDataSource * html_source,Profile * profile)82 ResetSettingsHandler* ResetSettingsHandler::Create(
83     content::WebUIDataSource* html_source, Profile* profile) {
84 #if defined(OS_CHROMEOS)
85   // TODO(crbug.com/891905): Centralize powerwash restriction checks.
86   bool allow_powerwash = false;
87   policy::BrowserPolicyConnectorChromeOS* connector =
88       g_browser_process->platform_part()->browser_policy_connector_chromeos();
89   allow_powerwash =
90       !connector->IsEnterpriseManaged() &&
91       !user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
92       !user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser() &&
93       !user_manager::UserManager::Get()->IsLoggedInAsChildUser();
94   html_source->AddBoolean("allowPowerwash", allow_powerwash);
95 #endif  // defined(OS_CHROMEOS)
96 
97   bool show_reset_profile_banner = false;
98   static const int kBannerShowTimeInDays = 5;
99   const base::Time then = chrome_prefs::GetResetTime(profile);
100   if (!then.is_null()) {
101     show_reset_profile_banner =
102         (base::Time::Now() - then).InDays() < kBannerShowTimeInDays;
103   }
104   html_source->AddBoolean("showResetProfileBanner", show_reset_profile_banner);
105 
106   return new ResetSettingsHandler(profile);
107 }
108 
OnJavascriptDisallowed()109 void ResetSettingsHandler::OnJavascriptDisallowed() {
110   callback_weak_ptr_factory_.InvalidateWeakPtrs();
111 }
112 
RegisterMessages()113 void ResetSettingsHandler::RegisterMessages() {
114   web_ui()->RegisterMessageCallback(
115       "performResetProfileSettings",
116       base::BindRepeating(&ResetSettingsHandler::HandleResetProfileSettings,
117                           base::Unretained(this)));
118   web_ui()->RegisterMessageCallback(
119       "onShowResetProfileDialog",
120       base::BindRepeating(&ResetSettingsHandler::OnShowResetProfileDialog,
121                           base::Unretained(this)));
122   web_ui()->RegisterMessageCallback(
123       "getReportedSettings",
124       base::BindRepeating(&ResetSettingsHandler::HandleGetReportedSettings,
125                           base::Unretained(this)));
126   web_ui()->RegisterMessageCallback(
127       "onHideResetProfileDialog",
128       base::BindRepeating(&ResetSettingsHandler::OnHideResetProfileDialog,
129                           base::Unretained(this)));
130   web_ui()->RegisterMessageCallback(
131       "onHideResetProfileBanner",
132       base::BindRepeating(&ResetSettingsHandler::OnHideResetProfileBanner,
133                           base::Unretained(this)));
134   web_ui()->RegisterMessageCallback(
135       "getTriggeredResetToolName",
136       base::BindRepeating(
137           &ResetSettingsHandler::HandleGetTriggeredResetToolName,
138           base::Unretained(this)));
139 #if defined(OS_CHROMEOS)
140   web_ui()->RegisterMessageCallback(
141       "onPowerwashDialogShow",
142       base::BindRepeating(&ResetSettingsHandler::OnShowPowerwashDialog,
143                           base::Unretained(this)));
144 #endif  // defined(OS_CHROMEOS)
145 }
146 
HandleResetProfileSettings(const base::ListValue * args)147 void ResetSettingsHandler::HandleResetProfileSettings(
148     const base::ListValue* args) {
149   AllowJavascript();
150 
151   CHECK_EQ(3U, args->GetSize());
152   std::string callback_id;
153   CHECK(args->GetString(0, &callback_id));
154   bool send_settings = false;
155   CHECK(args->GetBoolean(1, &send_settings));
156   std::string request_origin_string;
157   CHECK(args->GetString(2, &request_origin_string));
158   reset_report::ChromeResetReport::ResetRequestOrigin request_origin =
159       ResetRequestOriginFromString(request_origin_string);
160 
161   DCHECK(brandcode_.empty() || config_fetcher_);
162   if (config_fetcher_ && config_fetcher_->IsActive()) {
163     // Reset once the prefs are fetched.
164     config_fetcher_->SetCallback(base::Bind(&ResetSettingsHandler::ResetProfile,
165                                             base::Unretained(this), callback_id,
166                                             send_settings, request_origin));
167   } else {
168     ResetProfile(callback_id, send_settings, request_origin);
169   }
170 }
171 
OnResetProfileSettingsDone(std::string callback_id,bool send_feedback,reset_report::ChromeResetReport::ResetRequestOrigin request_origin)172 void ResetSettingsHandler::OnResetProfileSettingsDone(
173     std::string callback_id,
174     bool send_feedback,
175     reset_report::ChromeResetReport::ResetRequestOrigin request_origin) {
176   ResolveJavascriptCallback(base::Value(callback_id), base::Value());
177   if (send_feedback && setting_snapshot_) {
178     ResettableSettingsSnapshot current_snapshot(profile_);
179     int difference = setting_snapshot_->FindDifferentFields(current_snapshot);
180     if (difference) {
181       setting_snapshot_->Subtract(current_snapshot);
182       std::unique_ptr<reset_report::ChromeResetReport> report_proto =
183           SerializeSettingsReportToProto(*setting_snapshot_, difference);
184       if (report_proto) {
185         report_proto->set_reset_request_origin(request_origin);
186         SendSettingsFeedbackProto(*report_proto, profile_);
187       }
188     }
189   }
190   setting_snapshot_.reset();
191 }
192 
HandleGetReportedSettings(const base::ListValue * args)193 void ResetSettingsHandler::HandleGetReportedSettings(
194     const base::ListValue* args) {
195   AllowJavascript();
196 
197   CHECK_EQ(1U, args->GetSize());
198   std::string callback_id;
199   CHECK(args->GetString(0, &callback_id));
200 
201   setting_snapshot_->RequestShortcuts(
202       base::Bind(&ResetSettingsHandler::OnGetReportedSettingsDone,
203                  callback_weak_ptr_factory_.GetWeakPtr(), callback_id));
204 }
205 
OnGetReportedSettingsDone(std::string callback_id)206 void ResetSettingsHandler::OnGetReportedSettingsDone(std::string callback_id) {
207   std::unique_ptr<base::ListValue> list =
208       GetReadableFeedbackForSnapshot(profile_, *setting_snapshot_);
209   ResolveJavascriptCallback(base::Value(callback_id), *list);
210 }
211 
OnShowResetProfileDialog(const base::ListValue * args)212 void ResetSettingsHandler::OnShowResetProfileDialog(
213     const base::ListValue* args) {
214   if (!GetResetter()->IsActive()) {
215     setting_snapshot_ = std::make_unique<ResettableSettingsSnapshot>(profile_);
216   }
217 
218   if (brandcode_.empty())
219     return;
220   config_fetcher_ = std::make_unique<BrandcodeConfigFetcher>(
221       g_browser_process->system_network_context_manager()
222           ->GetURLLoaderFactory(),
223       base::Bind(&ResetSettingsHandler::OnSettingsFetched,
224                  base::Unretained(this)),
225       GURL("https://tools.google.com/service/update2"), brandcode_);
226 }
227 
OnHideResetProfileDialog(const base::ListValue * args)228 void ResetSettingsHandler::OnHideResetProfileDialog(
229     const base::ListValue* args) {
230   if (!GetResetter()->IsActive())
231     setting_snapshot_.reset();
232 }
233 
OnHideResetProfileBanner(const base::ListValue * args)234 void ResetSettingsHandler::OnHideResetProfileBanner(
235     const base::ListValue* args) {
236   chrome_prefs::ClearResetTime(profile_);
237 }
238 
OnSettingsFetched()239 void ResetSettingsHandler::OnSettingsFetched() {
240   DCHECK(config_fetcher_);
241   DCHECK(!config_fetcher_->IsActive());
242   // The master prefs is fetched. We are waiting for user pressing 'Reset'.
243 }
244 
ResetProfile(const std::string & callback_id,bool send_settings,reset_report::ChromeResetReport::ResetRequestOrigin request_origin)245 void ResetSettingsHandler::ResetProfile(
246     const std::string& callback_id,
247     bool send_settings,
248     reset_report::ChromeResetReport::ResetRequestOrigin request_origin) {
249   CHECK(!GetResetter()->IsActive());
250 
251   std::unique_ptr<BrandcodedDefaultSettings> default_settings;
252   if (config_fetcher_) {
253     DCHECK(!config_fetcher_->IsActive());
254     default_settings = config_fetcher_->GetSettings();
255     config_fetcher_.reset();
256   } else {
257     DCHECK(brandcode_.empty());
258   }
259 
260   // If failed to fetch BrandcodedDefaultSettings or this is an organic
261   // installation, use default settings.
262   if (!default_settings)
263     default_settings = std::make_unique<BrandcodedDefaultSettings>();
264 
265   GetResetter()->Reset(
266       ProfileResetter::ALL, std::move(default_settings),
267       base::Bind(&ResetSettingsHandler::OnResetProfileSettingsDone,
268                  callback_weak_ptr_factory_.GetWeakPtr(), callback_id,
269                  send_settings, request_origin));
270   base::RecordAction(base::UserMetricsAction("ResetProfile"));
271   UMA_HISTOGRAM_ENUMERATION(
272       "ProfileReset.ResetRequestOrigin", request_origin,
273       reset_report::ChromeResetReport::ResetRequestOrigin_MAX + 1);
274 }
275 
GetResetter()276 ProfileResetter* ResetSettingsHandler::GetResetter() {
277   if (!resetter_)
278     resetter_ = std::make_unique<ProfileResetter>(profile_);
279   return resetter_.get();
280 }
281 
HandleGetTriggeredResetToolName(const base::ListValue * args)282 void ResetSettingsHandler::HandleGetTriggeredResetToolName(
283     const base::ListValue* args) {
284   AllowJavascript();
285 
286   CHECK_EQ(1U, args->GetSize());
287   const base::Value* callback_id;
288   CHECK(args->Get(0, &callback_id));
289 
290   // Set up the localized strings for the triggered profile reset dialog.
291   // Custom reset tool names are supported on Windows only.
292   base::string16 reset_tool_name;
293 #if defined(OS_WIN)
294   Profile* profile = Profile::FromWebUI(web_ui());
295   TriggeredProfileResetter* triggered_profile_resetter =
296       TriggeredProfileResetterFactory::GetForBrowserContext(profile);
297   // TriggeredProfileResetter instance will be nullptr for incognito profiles.
298   if (triggered_profile_resetter) {
299     reset_tool_name = triggered_profile_resetter->GetResetToolName();
300 
301     // Now that a reset UI has been shown, don't trigger again for this profile.
302     triggered_profile_resetter->ClearResetTrigger();
303   }
304 #endif  // defined(OS_WIN)
305 
306   if (reset_tool_name.empty()) {
307     reset_tool_name = l10n_util::GetStringUTF16(
308         IDS_TRIGGERED_RESET_PROFILE_SETTINGS_DEFAULT_TOOL_NAME);
309   }
310 
311   base::Value string_value(reset_tool_name);
312   ResolveJavascriptCallback(*callback_id, string_value);
313 }
314 
315 #if defined(OS_CHROMEOS)
OnShowPowerwashDialog(const base::ListValue * args)316 void ResetSettingsHandler::OnShowPowerwashDialog(
317      const base::ListValue* args) {
318   UMA_HISTOGRAM_ENUMERATION(
319       "Reset.ChromeOS.PowerwashDialogShown",
320       chromeos::reset::DIALOG_FROM_OPTIONS,
321       chromeos::reset::DIALOG_VIEW_TYPE_SIZE);
322 }
323 #endif  // defined(OS_CHROMEOS)
324 
325 }  // namespace settings
326