blob: 450f867ca58dd896de26fdbcc09cf31bc2f8fcf3 [file] [log] [blame]
Sam Goto9c87da7e2019-04-30 23:09:451// 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
Sam Gotoc1294cab2019-07-15 22:36:015#include "content/browser/sms/sms_service.h"
Sam Goto9c87da7e2019-04-30 23:09:456
Sam Goto36d91172019-07-18 02:55:217#include <iterator>
Majid Valipourdcd50fa2020-07-20 16:59:438#include <memory>
Sam Goto36d91172019-07-18 02:55:219#include <queue>
Ayu Ishiid29455462019-10-18 23:23:1910#include <string>
Sam Gotoc1294cab2019-07-15 22:36:0111#include <utility>
Sam Goto9c87da7e2019-04-30 23:09:4512
13#include "base/bind.h"
14#include "base/callback_helpers.h"
Hans Wennborg0917de892020-04-28 20:21:1515#include "base/check_op.h"
Ayu Ishiidbdd5c92020-03-20 23:40:5216#include "base/command_line.h"
Sam Goto36d91172019-07-18 02:55:2117#include "base/optional.h"
danakj30f5b7dd2020-09-16 15:38:4518#include "content/browser/renderer_host/render_frame_host_impl.h"
Ayu Ishii9d303da52019-07-26 15:50:4719#include "content/browser/sms/sms_metrics.h"
Majid Valipourdcd50fa2020-07-20 16:59:4320#include "content/browser/sms/user_consent_handler.h"
Ayu Ishiif035717c2019-11-26 19:33:3621#include "content/public/browser/navigation_details.h"
22#include "content/public/browser/navigation_type.h"
Sam Goto5cf068e82019-11-04 23:08:4423#include "content/public/browser/sms_fetcher.h"
Sam Gotoc108b7b2019-07-18 20:12:1524#include "content/public/browser/web_contents.h"
25#include "content/public/browser/web_contents_delegate.h"
Ayu Ishiidbdd5c92020-03-20 23:40:5226#include "content/public/common/content_features.h"
27#include "content/public/common/content_switches.h"
Majid Valipourdcd50fa2020-07-20 16:59:4328#include "third_party/blink/public/mojom/sms/sms_receiver.mojom-shared.h"
Sam Goto36d91172019-07-18 02:55:2129
Ayu Ishiif035717c2019-11-26 19:33:3630using blink::SmsReceiverDestroyedReason;
Sam Goto36d91172019-07-18 02:55:2131using blink::mojom::SmsStatus;
Sam Goto9c87da7e2019-04-30 23:09:4532
33namespace content {
34
Miyoung Shin8ff3aa892019-08-31 03:01:3835SmsService::SmsService(
Sam Goto5cf068e82019-11-04 23:08:4436 SmsFetcher* fetcher,
Majid Valipourdcd50fa2020-07-20 16:59:4337 std::unique_ptr<UserConsentHandler> consent_handler,
Miyoung Shin8ff3aa892019-08-31 03:01:3838 const url::Origin& origin,
39 RenderFrameHost* host,
40 mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver)
41 : FrameServiceBase(host, std::move(receiver)),
Sam Goto5cf068e82019-11-04 23:08:4442 fetcher_(fetcher),
Majid Valipourdcd50fa2020-07-20 16:59:4343 consent_handler_(std::move(consent_handler)),
Ayu Ishiib09941712020-04-10 01:23:2544 origin_(origin) {
45 DCHECK(fetcher_);
46}
Sam Goto36d91172019-07-18 02:55:2147
Miyoung Shin8ff3aa892019-08-31 03:01:3848SmsService::SmsService(
Sam Goto5cf068e82019-11-04 23:08:4449 SmsFetcher* fetcher,
Miyoung Shin8ff3aa892019-08-31 03:01:3850 RenderFrameHost* host,
51 mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver)
Sam Goto5cf068e82019-11-04 23:08:4452 : SmsService(fetcher,
Majid Valipourdcd50fa2020-07-20 16:59:4353 nullptr,
Sam Goto36d91172019-07-18 02:55:2154 host->GetLastCommittedOrigin(),
55 host,
Majid Valipourdcd50fa2020-07-20 16:59:4356 std::move(receiver)) {
57 bool needs_user_prompt =
58 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
59 switches::kWebOtpBackend) == switches::kWebOtpBackendSmsVerification;
60
61 if (needs_user_prompt) {
Majid Valipourd28c95efb2020-07-22 15:25:3262 consent_handler_ = std::make_unique<PromptBasedUserConsentHandler>(
63 render_frame_host(), origin_);
Majid Valipourdcd50fa2020-07-20 16:59:4364 } else {
65 consent_handler_ = std::make_unique<NoopUserConsentHandler>();
66 }
67}
Sam Goto9c87da7e2019-04-30 23:09:4568
Sam Gotoc1294cab2019-07-15 22:36:0169SmsService::~SmsService() {
Jun Cai2055a0d62019-07-24 17:11:0670 if (callback_)
Majid Valipourdcd50fa2020-07-20 16:59:4371 CompleteRequest(SmsStatus::kTimeout);
Ayu Ishiib09941712020-04-10 01:23:2572 DCHECK(!callback_);
Sam Goto9c87da7e2019-04-30 23:09:4573}
74
Sam Goto36d91172019-07-18 02:55:2175// static
Miyoung Shin8ff3aa892019-08-31 03:01:3876void SmsService::Create(
Sam Goto5cf068e82019-11-04 23:08:4477 SmsFetcher* fetcher,
Miyoung Shin8ff3aa892019-08-31 03:01:3878 RenderFrameHost* host,
79 mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver) {
Sam Goto36d91172019-07-18 02:55:2180 DCHECK(host);
81
82 // SmsService owns itself. It will self-destruct when a mojo interface
83 // error occurs, the render frame host is deleted, or the render frame host
84 // navigates to a new document.
Sam Goto5cf068e82019-11-04 23:08:4485 new SmsService(fetcher, host, std::move(receiver));
Harkiran Bolaria4ecdd822020-06-26 21:42:4086 static_cast<RenderFrameHostImpl*>(host)->OnSchedulerTrackedFeatureUsed(
87 blink::scheduler::WebSchedulerTrackedFeature::kSmsService);
Sam Goto9c87da7e2019-04-30 23:09:4588}
89
Ayu Ishiiac090532019-09-04 14:12:0690void SmsService::Receive(ReceiveCallback callback) {
Sam Goto9c87da7e2019-04-30 23:09:4591 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Majid Valipourdcd50fa2020-07-20 16:59:4392
93 // TODO(majidvp): The comment below seems incorrect. This flow is used for
94 // both prompted and unprompted backends so it is not clear if we should
95 // always cancel early. Also I don't believe that we are actually silently
96 // dropping the sms but in fact the logic cancels the request once
97 // an sms comes in and there is no delegate.
98
Ayu Ishii0a088fca2020-03-03 20:05:2899 // This flow relies on the delegate to display an infobar for user
100 // confirmation. Cancelling the call early if no delegate is available is
101 // easier to debug then silently dropping SMSes later on.
102 WebContents* web_contents =
103 content::WebContents::FromRenderFrameHost(render_frame_host());
104 if (!web_contents->GetDelegate()) {
Ayu Ishii72b58152020-03-16 06:24:04105 std::move(callback).Run(SmsStatus::kCancelled, base::nullopt);
Ayu Ishii0a088fca2020-03-03 20:05:28106 return;
107 }
108
Majid Valipourdcd50fa2020-07-20 16:59:43109 // Abort the last request if there is we have not yet handled it.
Jun Cai2055a0d62019-07-24 17:11:06110 if (callback_) {
Ayu Ishii72b58152020-03-16 06:24:04111 std::move(callback_).Run(SmsStatus::kCancelled, base::nullopt);
Sam Goto5cf068e82019-11-04 23:08:44112 fetcher_->Unsubscribe(origin_, this);
Sam Gotoc108b7b2019-07-18 20:12:15113 }
Sam Goto36d91172019-07-18 02:55:21114
Ayu Ishiiae662c22019-08-06 16:24:09115 start_time_ = base::TimeTicks::Now();
Jun Cai2055a0d62019-07-24 17:11:06116 callback_ = std::move(callback);
Sam Gotoc108b7b2019-07-18 20:12:15117
Majid Valipourdcd50fa2020-07-20 16:59:43118 // |one_time_code_| and prompt are still present from the previous request so
119 // a new subscription is unnecessary. Note that it is only safe for us to use
120 // the in flight otp with the new request since both requests belong to the
121 // same origin.
Yi Gu39d531dd2020-08-17 20:25:25122 if (consent_handler_->is_active())
Ayu Ishii3a50e492019-11-26 01:49:30123 return;
Ayu Ishii3a50e492019-11-26 01:49:30124
Ayu Ishiifdabd1a2020-04-28 01:50:32125 fetcher_->Subscribe(origin_, this, render_frame_host());
Sam Goto36d91172019-07-18 02:55:21126}
127
Ayu Ishii72b58152020-03-16 06:24:04128void SmsService::OnReceive(const std::string& one_time_code) {
Sam Goto36d91172019-07-18 02:55:21129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Ayu Ishiibe802a32020-02-13 20:54:18130 DCHECK(!one_time_code_);
Ayu Ishiiae662c22019-08-06 16:24:09131 DCHECK(!start_time_.is_null());
132
Majid Valipourdcd50fa2020-07-20 16:59:43133 receive_time_ = base::TimeTicks::Now();
134 RecordSmsReceiveTime(receive_time_ - start_time_);
Sam Goto36d91172019-07-18 02:55:21135
Ayu Ishiibe802a32020-02-13 20:54:18136 one_time_code_ = one_time_code;
Sam Goto4fedd242019-08-22 03:35:32137
Majid Valipourdcd50fa2020-07-20 16:59:43138 consent_handler_->RequestUserConsent(
Majid Valipourd28c95efb2020-07-22 15:25:32139 one_time_code, base::BindOnce(&SmsService::CompleteRequest,
140 weak_ptr_factory_.GetWeakPtr()));
Sam Goto354bc1ad2019-08-30 00:10:40141}
142
Ayu Ishii3a50e492019-11-26 01:49:30143void SmsService::Abort() {
144 DCHECK(callback_);
Majid Valipourdcd50fa2020-07-20 16:59:43145 CompleteRequest(SmsStatus::kAborted);
Ayu Ishii3a50e492019-11-26 01:49:30146}
147
Ayu Ishiif035717c2019-11-26 19:33:36148void SmsService::NavigationEntryCommitted(
149 const content::LoadCommittedDetails& load_details) {
150 switch (load_details.type) {
151 case NavigationType::NAVIGATION_TYPE_NEW_PAGE:
152 RecordDestroyedReason(SmsReceiverDestroyedReason::kNavigateNewPage);
153 break;
154 case NavigationType::NAVIGATION_TYPE_EXISTING_PAGE:
155 RecordDestroyedReason(SmsReceiverDestroyedReason::kNavigateExistingPage);
156 break;
157 case NavigationType::NAVIGATION_TYPE_SAME_PAGE:
158 RecordDestroyedReason(SmsReceiverDestroyedReason::kNavigateSamePage);
159 break;
160 default:
161 // Ignore cases we don't care about.
162 break;
163 }
164}
165
Majid Valipourdcd50fa2020-07-20 16:59:43166void SmsService::CompleteRequest(blink::mojom::SmsStatus status) {
167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168
169 base::Optional<std::string> code = base::nullopt;
170 if (status == SmsStatus::kSuccess) {
171 DCHECK(one_time_code_);
172 code = one_time_code_;
Ayu Ishii0a088fca2020-03-03 20:05:28173 }
Sam Goto4fedd242019-08-22 03:35:32174
Majid Valipourdcd50fa2020-07-20 16:59:43175 // Record ContinueOn timing values only if we are using an asynchronous
176 // consent handler (i.e. showing user prompts).
177 if (consent_handler_->is_async()) {
178 if (status == SmsStatus::kSuccess) {
179 DCHECK(!receive_time_.is_null());
180 RecordContinueOnSuccessTime(base::TimeTicks::Now() - receive_time_);
181 } else if (status == SmsStatus::kCancelled) {
182 DCHECK(!receive_time_.is_null());
183 RecordCancelOnSuccessTime(base::TimeTicks::Now() - receive_time_);
184 }
185 }
Sam Goto36d91172019-07-18 02:55:21186
Majid Valipourdcd50fa2020-07-20 16:59:43187 if (callback_) {
188 std::move(callback_).Run(status, code);
189 }
190
Sam Goto4fedd242019-08-22 03:35:32191 CleanUp();
Jun Cai2055a0d62019-07-24 17:11:06192}
193
Sam Goto4fedd242019-08-22 03:35:32194void SmsService::CleanUp() {
Ayu Ishiibe802a32020-02-13 20:54:18195 // Skip resetting |one_time_code_|, |sms| and |receive_time_| while prompt is
196 // still open in case it needs to be returned to the next incoming request
197 // upon prompt confirmation.
Majid Valipourdcd50fa2020-07-20 16:59:43198 if (!consent_handler_->is_active()) {
Ayu Ishiibe802a32020-02-13 20:54:18199 one_time_code_.reset();
Ayu Ishii3a50e492019-11-26 01:49:30200 receive_time_ = base::TimeTicks();
201 }
Darren Shen9b0c43d2019-11-22 03:01:40202 start_time_ = base::TimeTicks();
Ayu Ishii3a50e492019-11-26 01:49:30203 callback_.Reset();
Sam Goto5cf068e82019-11-04 23:08:44204 fetcher_->Unsubscribe(origin_, this);
Sam Gotoc108b7b2019-07-18 20:12:15205}
206
Sam Goto9c87da7e2019-04-30 23:09:45207} // namespace content