Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 1 | // 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 Goto | c1294cab | 2019-07-15 22:36:01 | [diff] [blame] | 5 | #include "content/browser/sms/sms_service.h" |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 6 | |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 7 | #include <iterator> |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 8 | #include <memory> |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 9 | #include <queue> |
Ayu Ishii | d2945546 | 2019-10-18 23:23:19 | [diff] [blame] | 10 | #include <string> |
Sam Goto | c1294cab | 2019-07-15 22:36:01 | [diff] [blame] | 11 | #include <utility> |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 12 | |
| 13 | #include "base/bind.h" |
| 14 | #include "base/callback_helpers.h" |
Hans Wennborg | 0917de89 | 2020-04-28 20:21:15 | [diff] [blame] | 15 | #include "base/check_op.h" |
Ayu Ishii | dbdd5c9 | 2020-03-20 23:40:52 | [diff] [blame] | 16 | #include "base/command_line.h" |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 17 | #include "base/optional.h" |
danakj | 30f5b7dd | 2020-09-16 15:38:45 | [diff] [blame] | 18 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Ayu Ishii | 9d303da5 | 2019-07-26 15:50:47 | [diff] [blame] | 19 | #include "content/browser/sms/sms_metrics.h" |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 20 | #include "content/browser/sms/user_consent_handler.h" |
Ayu Ishii | f035717c | 2019-11-26 19:33:36 | [diff] [blame] | 21 | #include "content/public/browser/navigation_details.h" |
| 22 | #include "content/public/browser/navigation_type.h" |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 23 | #include "content/public/browser/sms_fetcher.h" |
Sam Goto | c108b7b | 2019-07-18 20:12:15 | [diff] [blame] | 24 | #include "content/public/browser/web_contents.h" |
| 25 | #include "content/public/browser/web_contents_delegate.h" |
Ayu Ishii | dbdd5c9 | 2020-03-20 23:40:52 | [diff] [blame] | 26 | #include "content/public/common/content_features.h" |
| 27 | #include "content/public/common/content_switches.h" |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 28 | #include "third_party/blink/public/mojom/sms/sms_receiver.mojom-shared.h" |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 29 | |
Ayu Ishii | f035717c | 2019-11-26 19:33:36 | [diff] [blame] | 30 | using blink::SmsReceiverDestroyedReason; |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 31 | using blink::mojom::SmsStatus; |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 32 | |
| 33 | namespace content { |
| 34 | |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 35 | SmsService::SmsService( |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 36 | SmsFetcher* fetcher, |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 37 | std::unique_ptr<UserConsentHandler> consent_handler, |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 38 | const url::Origin& origin, |
| 39 | RenderFrameHost* host, |
| 40 | mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver) |
| 41 | : FrameServiceBase(host, std::move(receiver)), |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 42 | fetcher_(fetcher), |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 43 | consent_handler_(std::move(consent_handler)), |
Ayu Ishii | b0994171 | 2020-04-10 01:23:25 | [diff] [blame] | 44 | origin_(origin) { |
| 45 | DCHECK(fetcher_); |
| 46 | } |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 47 | |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 48 | SmsService::SmsService( |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 49 | SmsFetcher* fetcher, |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 50 | RenderFrameHost* host, |
| 51 | mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver) |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 52 | : SmsService(fetcher, |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 53 | nullptr, |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 54 | host->GetLastCommittedOrigin(), |
| 55 | host, |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 56 | 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 Valipour | d28c95efb | 2020-07-22 15:25:32 | [diff] [blame] | 62 | consent_handler_ = std::make_unique<PromptBasedUserConsentHandler>( |
| 63 | render_frame_host(), origin_); |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 64 | } else { |
| 65 | consent_handler_ = std::make_unique<NoopUserConsentHandler>(); |
| 66 | } |
| 67 | } |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 68 | |
Sam Goto | c1294cab | 2019-07-15 22:36:01 | [diff] [blame] | 69 | SmsService::~SmsService() { |
Jun Cai | 2055a0d6 | 2019-07-24 17:11:06 | [diff] [blame] | 70 | if (callback_) |
Yi Gu | 2615772 | 2020-10-08 19:52:43 | [diff] [blame^] | 71 | CompleteRequest(SmsStatus::kUnhandledRequest); |
Ayu Ishii | b0994171 | 2020-04-10 01:23:25 | [diff] [blame] | 72 | DCHECK(!callback_); |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 73 | } |
| 74 | |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 75 | // static |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 76 | void SmsService::Create( |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 77 | SmsFetcher* fetcher, |
Miyoung Shin | 8ff3aa89 | 2019-08-31 03:01:38 | [diff] [blame] | 78 | RenderFrameHost* host, |
| 79 | mojo::PendingReceiver<blink::mojom::SmsReceiver> receiver) { |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 80 | 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 Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 85 | new SmsService(fetcher, host, std::move(receiver)); |
Harkiran Bolaria | 4ecdd82 | 2020-06-26 21:42:40 | [diff] [blame] | 86 | static_cast<RenderFrameHostImpl*>(host)->OnSchedulerTrackedFeatureUsed( |
| 87 | blink::scheduler::WebSchedulerTrackedFeature::kSmsService); |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 88 | } |
| 89 | |
Ayu Ishii | ac09053 | 2019-09-04 14:12:06 | [diff] [blame] | 90 | void SmsService::Receive(ReceiveCallback callback) { |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 91 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 92 | |
| 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 Ishii | 0a088fca | 2020-03-03 20:05:28 | [diff] [blame] | 99 | // 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 Ishii | 72b5815 | 2020-03-16 06:24:04 | [diff] [blame] | 105 | std::move(callback).Run(SmsStatus::kCancelled, base::nullopt); |
Ayu Ishii | 0a088fca | 2020-03-03 20:05:28 | [diff] [blame] | 106 | return; |
| 107 | } |
| 108 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 109 | // Abort the last request if there is we have not yet handled it. |
Jun Cai | 2055a0d6 | 2019-07-24 17:11:06 | [diff] [blame] | 110 | if (callback_) { |
Ayu Ishii | 72b5815 | 2020-03-16 06:24:04 | [diff] [blame] | 111 | std::move(callback_).Run(SmsStatus::kCancelled, base::nullopt); |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 112 | fetcher_->Unsubscribe(origin_, this); |
Sam Goto | c108b7b | 2019-07-18 20:12:15 | [diff] [blame] | 113 | } |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 114 | |
Ayu Ishii | ae662c2 | 2019-08-06 16:24:09 | [diff] [blame] | 115 | start_time_ = base::TimeTicks::Now(); |
Jun Cai | 2055a0d6 | 2019-07-24 17:11:06 | [diff] [blame] | 116 | callback_ = std::move(callback); |
Sam Goto | c108b7b | 2019-07-18 20:12:15 | [diff] [blame] | 117 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 118 | // |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 Gu | 39d531dd | 2020-08-17 20:25:25 | [diff] [blame] | 122 | if (consent_handler_->is_active()) |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 123 | return; |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 124 | |
Ayu Ishii | fdabd1a | 2020-04-28 01:50:32 | [diff] [blame] | 125 | fetcher_->Subscribe(origin_, this, render_frame_host()); |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 126 | } |
| 127 | |
Ayu Ishii | 72b5815 | 2020-03-16 06:24:04 | [diff] [blame] | 128 | void SmsService::OnReceive(const std::string& one_time_code) { |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 129 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Ayu Ishii | be802a3 | 2020-02-13 20:54:18 | [diff] [blame] | 130 | DCHECK(!one_time_code_); |
Ayu Ishii | ae662c2 | 2019-08-06 16:24:09 | [diff] [blame] | 131 | DCHECK(!start_time_.is_null()); |
| 132 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 133 | receive_time_ = base::TimeTicks::Now(); |
| 134 | RecordSmsReceiveTime(receive_time_ - start_time_); |
Sam Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 135 | |
Ayu Ishii | be802a3 | 2020-02-13 20:54:18 | [diff] [blame] | 136 | one_time_code_ = one_time_code; |
Sam Goto | 4fedd24 | 2019-08-22 03:35:32 | [diff] [blame] | 137 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 138 | consent_handler_->RequestUserConsent( |
Majid Valipour | d28c95efb | 2020-07-22 15:25:32 | [diff] [blame] | 139 | one_time_code, base::BindOnce(&SmsService::CompleteRequest, |
| 140 | weak_ptr_factory_.GetWeakPtr())); |
Sam Goto | 354bc1ad | 2019-08-30 00:10:40 | [diff] [blame] | 141 | } |
| 142 | |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 143 | void SmsService::Abort() { |
| 144 | DCHECK(callback_); |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 145 | CompleteRequest(SmsStatus::kAborted); |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 146 | } |
| 147 | |
Ayu Ishii | f035717c | 2019-11-26 19:33:36 | [diff] [blame] | 148 | void 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 Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 166 | void 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 Ishii | 0a088fca | 2020-03-03 20:05:28 | [diff] [blame] | 173 | } |
Sam Goto | 4fedd24 | 2019-08-22 03:35:32 | [diff] [blame] | 174 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 175 | // 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 Goto | 36d9117 | 2019-07-18 02:55:21 | [diff] [blame] | 186 | |
Majid Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 187 | if (callback_) { |
| 188 | std::move(callback_).Run(status, code); |
| 189 | } |
| 190 | |
Sam Goto | 4fedd24 | 2019-08-22 03:35:32 | [diff] [blame] | 191 | CleanUp(); |
Jun Cai | 2055a0d6 | 2019-07-24 17:11:06 | [diff] [blame] | 192 | } |
| 193 | |
Sam Goto | 4fedd24 | 2019-08-22 03:35:32 | [diff] [blame] | 194 | void SmsService::CleanUp() { |
Ayu Ishii | be802a3 | 2020-02-13 20:54:18 | [diff] [blame] | 195 | // 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 Valipour | dcd50fa | 2020-07-20 16:59:43 | [diff] [blame] | 198 | if (!consent_handler_->is_active()) { |
Ayu Ishii | be802a3 | 2020-02-13 20:54:18 | [diff] [blame] | 199 | one_time_code_.reset(); |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 200 | receive_time_ = base::TimeTicks(); |
| 201 | } |
Darren Shen | 9b0c43d | 2019-11-22 03:01:40 | [diff] [blame] | 202 | start_time_ = base::TimeTicks(); |
Ayu Ishii | 3a50e49 | 2019-11-26 01:49:30 | [diff] [blame] | 203 | callback_.Reset(); |
Sam Goto | 5cf068e8 | 2019-11-04 23:08:44 | [diff] [blame] | 204 | fetcher_->Unsubscribe(origin_, this); |
Sam Goto | c108b7b | 2019-07-18 20:12:15 | [diff] [blame] | 205 | } |
| 206 | |
Sam Goto | 9c87da7e | 2019-04-30 23:09:45 | [diff] [blame] | 207 | } // namespace content |