blob: e0290920e512c99d3aff049ec5d151637a69b11f [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/sms/sms_fetcher_impl.h"
#include "base/callback.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/sms/sms_parser.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
namespace content {
const char kSmsFetcherImplKeyName[] = "sms_fetcher";
SmsFetcherImpl::SmsFetcherImpl(SmsProvider* provider) : provider_(provider) {
if (provider_)
provider_->AddObserver(this);
}
SmsFetcherImpl::~SmsFetcherImpl() {
if (provider_)
provider_->RemoveObserver(this);
}
// static
SmsFetcher* SmsFetcher::Get(BrowserContext* context) {
if (!context->GetUserData(kSmsFetcherImplKeyName)) {
auto fetcher = std::make_unique<SmsFetcherImpl>(
BrowserMainLoop::GetInstance()->GetSmsProvider());
context->SetUserData(kSmsFetcherImplKeyName, std::move(fetcher));
}
return static_cast<SmsFetcherImpl*>(
context->GetUserData(kSmsFetcherImplKeyName));
}
void SmsFetcherImpl::Subscribe(const OriginList& origin_list,
SmsQueue::Subscriber* subscriber) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(subscriber);
// Should not be called multiple times for the same subscriber and origin.
DCHECK(!subscribers_.HasSubscriber(origin_list, subscriber));
subscribers_.Push(origin_list, subscriber);
if (provider_)
provider_->Retrieve(nullptr, SmsFetchType::kRemote);
}
void SmsFetcherImpl::Subscribe(const OriginList& origin_list,
SmsQueue::Subscriber* subscriber,
RenderFrameHost* render_frame_host) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(subscriber);
DCHECK(render_frame_host);
// This function cannot get called during prerendering because
// WebOTPService::Receive() calls this, but WebOTPService is deferred during
// prerendering by MojoBinderPolicyApplier. This DCHECK proves we don't have
// to worry about prerendering when using WebContents::FromRenderFrameHost()
// below (see function comments for WebContents::FromRenderFrameHost() for
// more details).
DCHECK_NE(render_frame_host->GetLifecycleState(),
RenderFrameHost::LifecycleState::kPrerendering);
// Should not be called multiple times for the same subscriber.
DCHECK(!remote_cancel_callbacks_.count(subscriber));
DCHECK(!subscribers_.HasSubscriber(origin_list, subscriber));
subscribers_.Push(origin_list, subscriber);
// Fetches a remote SMS.
base::OnceClosure cancel_callback =
GetContentClient()->browser()->FetchRemoteSms(
WebContents::FromRenderFrameHost(render_frame_host), origin_list,
base::BindOnce(&SmsFetcherImpl::OnRemote,
weak_ptr_factory_.GetWeakPtr()));
if (cancel_callback)
remote_cancel_callbacks_[subscriber] = std::move(cancel_callback);
// Fetches a local SMS.
if (provider_)
provider_->Retrieve(render_frame_host, SmsFetchType::kLocal);
}
void SmsFetcherImpl::Unsubscribe(const OriginList& origin_list,
SmsQueue::Subscriber* subscriber) {
// Unsubscribe does not make a call to the provider because currently there
// is no mechanism to cancel a subscription.
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
subscribers_.Remove(origin_list, subscriber);
// A subscriber does not have a remote cancel callback in the map when
// 1. it has been unsubscribed before. e.g. we unsubscribe a subscriber when
// a verification flow is successful and when the subscriber is destroyed.
// 2. TODO(crbug.com/1015645): no need to keep cancel callback when we don't
// fetch a remote sms. e.g. when kWebOTPCrossDevice is disabled.
auto it = remote_cancel_callbacks_.find(subscriber);
if (it == remote_cancel_callbacks_.end())
return;
std::move(it->second).Run();
remote_cancel_callbacks_.erase(it);
}
bool SmsFetcherImpl::Notify(const OriginList& origin_list,
const std::string& one_time_code,
UserConsent consent_requirement) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// The received OTP is returned to the first subscriber for the origin.
auto* subscriber = subscribers_.Pop(origin_list);
if (!subscriber)
return false;
subscriber->OnReceive(origin_list, one_time_code, consent_requirement);
return true;
}
void SmsFetcherImpl::OnRemote(absl::optional<OriginList> origin_list,
absl::optional<std::string> one_time_code,
absl::optional<FailureType> failure_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (failure_type) {
OnFailure(failure_type.value());
return;
}
if (!origin_list || !one_time_code)
return;
Notify(origin_list.value(), one_time_code.value(), UserConsent::kObtained);
}
bool SmsFetcherImpl::OnReceive(const OriginList& origin_list,
const std::string& one_time_code,
UserConsent consent_requirement) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return Notify(origin_list, one_time_code, consent_requirement);
}
bool SmsFetcherImpl::OnFailure(FailureType failure_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return subscribers_.NotifyFailure(failure_type);
}
bool SmsFetcherImpl::HasSubscribers() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return subscribers_.HasSubscribers();
}
} // namespace content