1 // Copyright (c) 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/chromeos/login/screens/terms_of_service_screen.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/check.h"
12 #include "base/location.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/browser_process_platform_part.h"
16 #include "chrome/browser/chromeos/login/wizard_controller.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/net/system_network_context_manager.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/prefs/pref_service.h"
24 #include "content/public/browser/storage_partition.h"
25 #include "net/http/http_response_headers.h"
26 #include "services/network/public/cpp/resource_request.h"
27 #include "services/network/public/cpp/simple_url_loader.h"
28 #include "services/network/public/mojom/url_loader_factory.mojom.h"
29 #include "url/gurl.h"
30
31 namespace chromeos {
32 namespace {
33
34 constexpr const char kAccept[] = "accept";
35 constexpr const char kBack[] = "back";
36 constexpr const char kRetry[] = "retry";
37
38 } // namespace
39
40 // static
GetResultString(Result result)41 std::string TermsOfServiceScreen::GetResultString(Result result) {
42 switch (result) {
43 case Result::ACCEPTED:
44 return "Accepted";
45 case Result::DECLINED:
46 return "Declined";
47 case Result::NOT_APPLICABLE:
48 return BaseScreen::kNotApplicable;
49 }
50 }
51
TermsOfServiceScreen(TermsOfServiceScreenView * view,const ScreenExitCallback & exit_callback)52 TermsOfServiceScreen::TermsOfServiceScreen(
53 TermsOfServiceScreenView* view,
54 const ScreenExitCallback& exit_callback)
55 : BaseScreen(TermsOfServiceScreenView::kScreenId,
56 OobeScreenPriority::DEFAULT),
57 view_(view),
58 exit_callback_(exit_callback) {
59 DCHECK(view_);
60 if (view_)
61 view_->SetScreen(this);
62 }
63
~TermsOfServiceScreen()64 TermsOfServiceScreen::~TermsOfServiceScreen() {
65 if (view_)
66 view_->SetScreen(nullptr);
67 }
68
OnDecline()69 void TermsOfServiceScreen::OnDecline() {
70 exit_callback_.Run(Result::DECLINED);
71 }
72
OnAccept()73 void TermsOfServiceScreen::OnAccept() {
74 if (view_ && view_->AreTermsLoaded()) {
75 exit_callback_.Run(Result::ACCEPTED);
76 return;
77 }
78 // If the Terms of Service have not been successfully downloaded, the "accept
79 // and continue" button should not be accessible. If the user managed to
80 // activate it somehow anyway, do not treat this as acceptance of the Terms
81 // and Conditions and end the session instead, as if the user had declined.
82 OnDecline();
83 }
84
OnRetry()85 void TermsOfServiceScreen::OnRetry() {
86 // If the Terms of Service have been successfully downloaded or are still
87 // being downloaded, this button should not be accessible. If the user managed
88 // to activate it somehow anyway, do not do anything.
89 if (view_ && view_->AreTermsLoaded())
90 return;
91 if (terms_of_service_loader_)
92 return;
93
94 StartDownload();
95 }
96
OnViewDestroyed(TermsOfServiceScreenView * view)97 void TermsOfServiceScreen::OnViewDestroyed(TermsOfServiceScreenView* view) {
98 if (view_ == view)
99 view_ = nullptr;
100 }
101
MaybeSkip(WizardContext * context)102 bool TermsOfServiceScreen::MaybeSkip(WizardContext* context) {
103 // Only show the Terms of Service when logging into a public account and Terms
104 // of Service have been specified through policy. In all other cases, advance
105 // to the post-ToS part immediately.
106 if (!user_manager::UserManager::Get()->IsLoggedInAsPublicAccount() ||
107 !ProfileManager::GetActiveUserProfile()->GetPrefs()->IsManagedPreference(
108 prefs::kTermsOfServiceURL)) {
109 exit_callback_.Run(Result::NOT_APPLICABLE);
110 return true;
111 }
112
113 return false;
114 }
115
ShowImpl()116 void TermsOfServiceScreen::ShowImpl() {
117 if (!view_)
118 return;
119
120 // Set the domain name whose Terms of Service are being shown.
121 policy::BrowserPolicyConnectorChromeOS* connector =
122 g_browser_process->platform_part()->browser_policy_connector_chromeos();
123 view_->SetDomain(connector->GetEnterpriseDisplayDomain());
124
125 // Show the screen.
126 view_->Show();
127
128 // Start downloading the Terms of Service.
129 StartDownload();
130 }
131
HideImpl()132 void TermsOfServiceScreen::HideImpl() {
133 if (view_)
134 view_->Hide();
135 }
136
OnUserAction(const std::string & action_id)137 void TermsOfServiceScreen::OnUserAction(const std::string& action_id) {
138 if (action_id == kBack)
139 OnDecline();
140 else if (action_id == kAccept)
141 OnAccept();
142 else if (action_id == kRetry)
143 OnRetry();
144 else
145 BaseScreen::OnUserAction(action_id);
146 }
147
StartDownload()148 void TermsOfServiceScreen::StartDownload() {
149 const PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
150 // If an URL from which the Terms of Service can be downloaded has not been
151 // set, show an error message to the user.
152 std::string terms_of_service_url =
153 prefs->GetString(prefs::kTermsOfServiceURL);
154 if (terms_of_service_url.empty()) {
155 if (view_)
156 view_->OnLoadError();
157 return;
158 }
159
160 net::NetworkTrafficAnnotationTag traffic_annotation =
161 net::DefineNetworkTrafficAnnotation("terms_of_service_fetch", R"(
162 semantics {
163 sender: "Chrome OS Terms of Service"
164 description:
165 "Chrome OS downloads the latest terms of service document "
166 "from Google servers."
167 trigger:
168 "When a public session starts on managed devices and an admin "
169 "has uploaded a terms of service document for the domain."
170 data:
171 "URL of the terms of service document. "
172 "No user information is sent."
173 destination: WEBSITE
174 }
175 policy {
176 cookies_allowed: YES
177 cookies_store: "user"
178 setting: "Unconditionally enabled on Chrome OS."
179 policy_exception_justification:
180 "Not implemented, considered not useful."
181 })");
182 // Start downloading the Terms of Service.
183
184 auto resource_request = std::make_unique<network::ResourceRequest>();
185 resource_request->url = GURL(terms_of_service_url);
186 // Request a text/plain MIME type as only plain-text Terms of Service are
187 // accepted.
188 resource_request->headers.SetHeader("Accept", "text/plain");
189 terms_of_service_loader_ = network::SimpleURLLoader::Create(
190 std::move(resource_request), traffic_annotation);
191 // Retry up to three times if network changes are detected during the
192 // download.
193 terms_of_service_loader_->SetRetryOptions(
194 3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
195 network::mojom::URLLoaderFactory* loader_factory =
196 g_browser_process->system_network_context_manager()
197 ->GetURLLoaderFactory();
198 terms_of_service_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
199 loader_factory, base::BindOnce(&TermsOfServiceScreen::OnDownloaded,
200 base::Unretained(this)));
201
202 // Abort the download attempt if it takes longer than one minute.
203 download_timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1), this,
204 &TermsOfServiceScreen::OnDownloadTimeout);
205 }
206
OnDownloadTimeout()207 void TermsOfServiceScreen::OnDownloadTimeout() {
208 // Destroy the fetcher, which will abort the download attempt.
209 terms_of_service_loader_.reset();
210
211 // Show an error message to the user.
212 if (view_)
213 view_->OnLoadError();
214 }
215
OnDownloaded(std::unique_ptr<std::string> response_body)216 void TermsOfServiceScreen::OnDownloaded(
217 std::unique_ptr<std::string> response_body) {
218 download_timer_.Stop();
219
220 // Destroy the fetcher when this method returns.
221 std::unique_ptr<network::SimpleURLLoader> loader(
222 std::move(terms_of_service_loader_));
223 if (!view_)
224 return;
225
226 // If the Terms of Service could not be downloaded, do not have a MIME type of
227 // text/plain or are empty, show an error message to the user.
228 if (!response_body || *response_body == "" || !loader->ResponseInfo() ||
229 loader->ResponseInfo()->mime_type != "text/plain") {
230 view_->OnLoadError();
231 } else {
232 // If the Terms of Service were downloaded successfully, show them to the
233 // user.
234 view_->OnLoadSuccess(*response_body);
235 }
236 }
237
238 } // namespace chromeos
239