Commit 6dcf7e9d authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Web Contents] Delete authenticator before render frame.

Before this patch, it was possible to delete the render frame host
before the secure payment confirmation app, which owned an instance of
an authenticator that must outlive the render frame host. This caused a
crash.

This patch makes secure confirmation app observe the render frame host
deletion, so the app can delete the authenticator that it owns before
the associated render frame host is deleted.

The android implementation (currently behind
chrome://flags/#enable-web-platform-experimental-features flag) has been
changed to match the desktop implementation (behind origin trial in
M-86) to create the authenticator on the main frame of the web page, so
cross-origin web pages can exercise the payment credential, too.

After this patch, the authenticator is deleted before the render frame
host, which avoids the crash.

Bug: 1125614
Change-Id: I83502b1b6bf23b838211687497a6498d5c4777ff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2410348Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Reviewed-by: default avatarTommy Martino <tmartino@chromium.org>
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808390}
parent f719e12e
...@@ -107,6 +107,10 @@ void InternalAuthenticatorAndroid::Cancel() { ...@@ -107,6 +107,10 @@ void InternalAuthenticatorAndroid::Cancel() {
Java_AuthenticatorImpl_cancel(env, obj); Java_AuthenticatorImpl_cancel(env, obj);
} }
content::RenderFrameHost* InternalAuthenticatorAndroid::GetRenderFrameHost() {
return render_frame_host_;
}
void InternalAuthenticatorAndroid::InvokeMakeCredentialResponse( void InternalAuthenticatorAndroid::InvokeMakeCredentialResponse(
JNIEnv* env, JNIEnv* env,
jint status, jint status,
......
...@@ -47,6 +47,7 @@ class InternalAuthenticatorAndroid : public autofill::InternalAuthenticator { ...@@ -47,6 +47,7 @@ class InternalAuthenticatorAndroid : public autofill::InternalAuthenticator {
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) IsUserVerifyingPlatformAuthenticatorAvailableCallback callback)
override; override;
void Cancel() override; void Cancel() override;
content::RenderFrameHost* GetRenderFrameHost() override;
void InvokeMakeCredentialResponse( void InvokeMakeCredentialResponse(
JNIEnv* env, JNIEnv* env,
......
...@@ -252,7 +252,13 @@ PaymentAppServiceBridge::GetMethodData() const { ...@@ -252,7 +252,13 @@ PaymentAppServiceBridge::GetMethodData() const {
std::unique_ptr<autofill::InternalAuthenticator> std::unique_ptr<autofill::InternalAuthenticator>
PaymentAppServiceBridge::CreateInternalAuthenticator() const { PaymentAppServiceBridge::CreateInternalAuthenticator() const {
return std::make_unique<InternalAuthenticatorAndroid>(render_frame_host_); // This authenticator can be used in a cross-origin iframe only if the
// top-level frame allowed it with Feature Policy, e.g., with allow="payment"
// iframe attribute. The secure payment confirmation dialog displays the
// top-level origin in its UI before the user can click on the [Verify] button
// to invoke this authenticator.
return std::make_unique<InternalAuthenticatorAndroid>(
web_contents_->GetMainFrame());
} }
scoped_refptr<PaymentManifestWebDataService> scoped_refptr<PaymentManifestWebDataService>
......
...@@ -67,6 +67,10 @@ void InternalAuthenticatorImpl::Cancel() { ...@@ -67,6 +67,10 @@ void InternalAuthenticatorImpl::Cancel() {
authenticator_common_->Cancel(); authenticator_common_->Cancel();
} }
content::RenderFrameHost* InternalAuthenticatorImpl::GetRenderFrameHost() {
return render_frame_host_;
}
void InternalAuthenticatorImpl::DidFinishNavigation( void InternalAuthenticatorImpl::DidFinishNavigation(
NavigationHandle* navigation_handle) { NavigationHandle* navigation_handle) {
// If the RenderFrameHost itself is navigated then this function will cause // If the RenderFrameHost itself is navigated then this function will cause
......
...@@ -50,6 +50,7 @@ class InternalAuthenticatorImpl : public autofill::InternalAuthenticator, ...@@ -50,6 +50,7 @@ class InternalAuthenticatorImpl : public autofill::InternalAuthenticator,
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) IsUserVerifyingPlatformAuthenticatorAvailableCallback callback)
override; override;
void Cancel() override; void Cancel() override;
content::RenderFrameHost* GetRenderFrameHost() override;
// WebContentsObserver: // WebContentsObserver:
void DidFinishNavigation(NavigationHandle* navigation_handle) override; void DidFinishNavigation(NavigationHandle* navigation_handle) override;
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h" #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
#include "url/origin.h" #include "url/origin.h"
namespace content {
class RenderFrameHost;
} // namespace content
namespace autofill { namespace autofill {
// Interface similar to blink::mojom::Authenticator meant only for internal // Interface similar to blink::mojom::Authenticator meant only for internal
...@@ -47,6 +51,10 @@ class InternalAuthenticator { ...@@ -47,6 +51,10 @@ class InternalAuthenticator {
// Only one MakeCredential or GetAssertion call at a time is allowed, // Only one MakeCredential or GetAssertion call at a time is allowed,
// any future calls are cancelled. // any future calls are cancelled.
virtual void Cancel() = 0; virtual void Cancel() = 0;
// Returns the non-owned render frame host associated with this authenticator.
// Can be used for observing the host's deletion.
virtual content::RenderFrameHost* GetRenderFrameHost() = 0;
}; };
} // namespace autofill } // namespace autofill
......
...@@ -12,4 +12,8 @@ void TestInternalAuthenticator::IsUserVerifyingPlatformAuthenticatorAvailable( ...@@ -12,4 +12,8 @@ void TestInternalAuthenticator::IsUserVerifyingPlatformAuthenticatorAvailable(
std::move(callback).Run(false); std::move(callback).Run(false);
} }
content::RenderFrameHost* TestInternalAuthenticator::GetRenderFrameHost() {
return nullptr;
}
} // namespace autofill } // namespace autofill
...@@ -30,6 +30,7 @@ class TestInternalAuthenticator : public InternalAuthenticator { ...@@ -30,6 +30,7 @@ class TestInternalAuthenticator : public InternalAuthenticator {
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) IsUserVerifyingPlatformAuthenticatorAvailableCallback callback)
override; override;
void Cancel() override {} void Cancel() override {}
content::RenderFrameHost* GetRenderFrameHost() override;
}; };
} // namespace autofill } // namespace autofill
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "components/autofill/core/browser/payments/internal_authenticator.h" #include "components/autofill/core/browser/payments/internal_authenticator.h"
#include "components/payments/core/method_strings.h" #include "components/payments/core/method_strings.h"
#include "components/payments/core/payer_data.h" #include "components/payments/core/payer_data.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
#include "device/fido/fido_transport_protocol.h" #include "device/fido/fido_transport_protocol.h"
...@@ -79,6 +80,7 @@ std::vector<uint8_t> GetSecurePaymentConfirmationChallenge( ...@@ -79,6 +80,7 @@ std::vector<uint8_t> GetSecurePaymentConfirmationChallenge(
} // namespace } // namespace
SecurePaymentConfirmationApp::SecurePaymentConfirmationApp( SecurePaymentConfirmationApp::SecurePaymentConfirmationApp(
content::WebContents* web_contents_to_observe,
const std::string& effective_relying_party_identity, const std::string& effective_relying_party_identity,
std::unique_ptr<SkBitmap> icon, std::unique_ptr<SkBitmap> icon,
const base::string16& label, const base::string16& label,
...@@ -88,6 +90,9 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp( ...@@ -88,6 +90,9 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp(
mojom::SecurePaymentConfirmationRequestPtr request, mojom::SecurePaymentConfirmationRequestPtr request,
std::unique_ptr<autofill::InternalAuthenticator> authenticator) std::unique_ptr<autofill::InternalAuthenticator> authenticator)
: PaymentApp(/*icon_resource_id=*/0, PaymentApp::Type::INTERNAL), : PaymentApp(/*icon_resource_id=*/0, PaymentApp::Type::INTERNAL),
content::WebContentsObserver(web_contents_to_observe),
authenticator_render_frame_host_pointer_do_not_dereference_(
authenticator->GetRenderFrameHost()),
effective_relying_party_identity_(effective_relying_party_identity), effective_relying_party_identity_(effective_relying_party_identity),
icon_(std::move(icon)), icon_(std::move(icon)),
label_(label), label_(label),
...@@ -97,6 +102,8 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp( ...@@ -97,6 +102,8 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp(
total_(total.Clone()), total_(total.Clone()),
request_(std::move(request)), request_(std::move(request)),
authenticator_(std::move(authenticator)) { authenticator_(std::move(authenticator)) {
DCHECK_EQ(web_contents_to_observe->GetMainFrame(),
authenticator_render_frame_host_pointer_do_not_dereference_);
DCHECK(!credential_id_.empty()); DCHECK(!credential_id_.empty());
app_method_names_.insert(methods::kSecurePaymentConfirmation); app_method_names_.insert(methods::kSecurePaymentConfirmation);
...@@ -105,6 +112,9 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp( ...@@ -105,6 +112,9 @@ SecurePaymentConfirmationApp::SecurePaymentConfirmationApp(
SecurePaymentConfirmationApp::~SecurePaymentConfirmationApp() = default; SecurePaymentConfirmationApp::~SecurePaymentConfirmationApp() = default;
void SecurePaymentConfirmationApp::InvokePaymentApp(Delegate* delegate) { void SecurePaymentConfirmationApp::InvokePaymentApp(Delegate* delegate) {
if (!authenticator_)
return;
auto options = blink::mojom::PublicKeyCredentialRequestOptions::New(); auto options = blink::mojom::PublicKeyCredentialRequestOptions::New();
options->relying_party_id = effective_relying_party_identity_; options->relying_party_id = effective_relying_party_identity_;
options->timeout = request_->timeout.has_value() options->timeout = request_->timeout.has_value()
...@@ -241,6 +251,15 @@ void SecurePaymentConfirmationApp::AbortPaymentApp( ...@@ -241,6 +251,15 @@ void SecurePaymentConfirmationApp::AbortPaymentApp(
std::move(abort_callback).Run(/*abort_success=*/false); std::move(abort_callback).Run(/*abort_success=*/false);
} }
void SecurePaymentConfirmationApp::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
if (authenticator_render_frame_host_pointer_do_not_dereference_ ==
render_frame_host) {
// The authenticator requires to be deleted before the render frame.
authenticator_.reset();
}
}
void SecurePaymentConfirmationApp::OnGetAssertion( void SecurePaymentConfirmationApp::OnGetAssertion(
Delegate* delegate, Delegate* delegate,
blink::mojom::AuthenticatorStatus status, blink::mojom::AuthenticatorStatus status,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "components/payments/content/secure_payment_confirmation_controller.h" #include "components/payments/content/secure_payment_confirmation_controller.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h" #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
#include "url/origin.h" #include "url/origin.h"
...@@ -25,13 +26,20 @@ namespace autofill { ...@@ -25,13 +26,20 @@ namespace autofill {
class InternalAuthenticator; class InternalAuthenticator;
} // namespace autofill } // namespace autofill
namespace content {
class RenderFrameHost;
class WebContents;
} // namespace content
namespace payments { namespace payments {
class SecurePaymentConfirmationApp : public PaymentApp { class SecurePaymentConfirmationApp : public PaymentApp,
public content::WebContentsObserver {
public: public:
// Please use `std::move()` for the `credential_id` parameter to avoid extra // Please use `std::move()` for the `credential_id` parameter to avoid extra
// copies. // copies.
SecurePaymentConfirmationApp( SecurePaymentConfirmationApp(
content::WebContents* web_contents_to_observe,
const std::string& effective_relying_party_identity, const std::string& effective_relying_party_identity,
std::unique_ptr<SkBitmap> icon, std::unique_ptr<SkBitmap> icon,
const base::string16& label, const base::string16& label,
...@@ -75,12 +83,20 @@ class SecurePaymentConfirmationApp : public PaymentApp { ...@@ -75,12 +83,20 @@ class SecurePaymentConfirmationApp : public PaymentApp {
void OnPaymentDetailsNotUpdated() override; void OnPaymentDetailsNotUpdated() override;
void AbortPaymentApp(base::OnceCallback<void(bool)> abort_callback) override; void AbortPaymentApp(base::OnceCallback<void(bool)> abort_callback) override;
// WebContentsObserver implementation.
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
private: private:
void OnGetAssertion( void OnGetAssertion(
Delegate* delegate, Delegate* delegate,
blink::mojom::AuthenticatorStatus status, blink::mojom::AuthenticatorStatus status,
blink::mojom::GetAssertionAuthenticatorResponsePtr response); blink::mojom::GetAssertionAuthenticatorResponsePtr response);
// Used only for comparison with the RenderFrameHost pointer in
// RenderFrameDeleted() method.
const content::RenderFrameHost* const
authenticator_render_frame_host_pointer_do_not_dereference_;
const std::string effective_relying_party_identity_; const std::string effective_relying_party_identity_;
const std::unique_ptr<SkBitmap> icon_; const std::unique_ptr<SkBitmap> icon_;
const base::string16 label_; const base::string16 label_;
...@@ -89,7 +105,7 @@ class SecurePaymentConfirmationApp : public PaymentApp { ...@@ -89,7 +105,7 @@ class SecurePaymentConfirmationApp : public PaymentApp {
const url::Origin merchant_origin_; const url::Origin merchant_origin_;
const mojom::PaymentCurrencyAmountPtr total_; const mojom::PaymentCurrencyAmountPtr total_;
const mojom::SecurePaymentConfirmationRequestPtr request_; const mojom::SecurePaymentConfirmationRequestPtr request_;
const std::unique_ptr<autofill::InternalAuthenticator> authenticator_; std::unique_ptr<autofill::InternalAuthenticator> authenticator_;
base::WeakPtrFactory<SecurePaymentConfirmationApp> weak_ptr_factory_{this}; base::WeakPtrFactory<SecurePaymentConfirmationApp> weak_ptr_factory_{this};
}; };
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "components/payments/core/secure_payment_confirmation_instrument.h" #include "components/payments/core/secure_payment_confirmation_instrument.h"
#include "components/webdata/common/web_data_results.h" #include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_base.h" #include "components/webdata/common/web_data_service_base.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "services/data_decoder/public/cpp/decode_image.h" #include "services/data_decoder/public/cpp/decode_image.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
...@@ -140,15 +142,17 @@ void SecurePaymentConfirmationAppFactory::Create( ...@@ -140,15 +142,17 @@ void SecurePaymentConfirmationAppFactory::Create(
delegate->OnDoneCreatingPaymentApps(); delegate->OnDoneCreatingPaymentApps();
} }
struct SecurePaymentConfirmationAppFactory::Request { struct SecurePaymentConfirmationAppFactory::Request
: public content::WebContentsObserver {
Request(base::WeakPtr<PaymentAppFactory::Delegate> delegate, Request(base::WeakPtr<PaymentAppFactory::Delegate> delegate,
mojom::SecurePaymentConfirmationRequestPtr mojo_request, mojom::SecurePaymentConfirmationRequestPtr mojo_request,
std::unique_ptr<autofill::InternalAuthenticator> authenticator) std::unique_ptr<autofill::InternalAuthenticator> authenticator)
: delegate(delegate), : content::WebContentsObserver(delegate->GetWebContents()),
delegate(delegate),
mojo_request(std::move(mojo_request)), mojo_request(std::move(mojo_request)),
authenticator(std::move(authenticator)) {} authenticator(std::move(authenticator)) {}
~Request() = default; ~Request() override = default;
Request(const Request& other) = delete; Request(const Request& other) = delete;
Request& operator=(const Request& other) = delete; Request& operator=(const Request& other) = delete;
...@@ -168,7 +172,7 @@ void SecurePaymentConfirmationAppFactory::OnWebDataServiceRequestDone( ...@@ -168,7 +172,7 @@ void SecurePaymentConfirmationAppFactory::OnWebDataServiceRequestDone(
std::unique_ptr<Request> request = std::move(iterator->second); std::unique_ptr<Request> request = std::move(iterator->second);
requests_.erase(iterator); requests_.erase(iterator);
DCHECK(request.get()); DCHECK(request.get());
if (!request->delegate) if (!request->delegate || !request->web_contents())
return; return;
if (!result || result->GetType() != SECURE_PAYMENT_CONFIRMATION) { if (!result || result->GetType() != SECURE_PAYMENT_CONFIRMATION) {
...@@ -206,12 +210,22 @@ void SecurePaymentConfirmationAppFactory::OnAppIconDecoded( ...@@ -206,12 +210,22 @@ void SecurePaymentConfirmationAppFactory::OnAppIconDecoded(
std::unique_ptr<SecurePaymentConfirmationInstrument> instrument, std::unique_ptr<SecurePaymentConfirmationInstrument> instrument,
std::unique_ptr<Request> request, std::unique_ptr<Request> request,
const SkBitmap& decoded_icon) { const SkBitmap& decoded_icon) {
if (!request->delegate || !request->web_contents())
return;
if (request->authenticator->GetRenderFrameHost() !=
request->web_contents()->GetMainFrame()) {
request->delegate->OnDoneCreatingPaymentApps();
return;
}
DCHECK(!decoded_icon.drawsNothing()); DCHECK(!decoded_icon.drawsNothing());
auto icon = std::make_unique<SkBitmap>(decoded_icon); auto icon = std::make_unique<SkBitmap>(decoded_icon);
request->delegate->OnPaymentAppCreated( request->delegate->OnPaymentAppCreated(
std::make_unique<SecurePaymentConfirmationApp>( std::make_unique<SecurePaymentConfirmationApp>(
instrument->relying_party_id, std::move(icon), instrument->label, request->web_contents(), instrument->relying_party_id,
std::move(icon), instrument->label,
std::move(instrument->credential_id), std::move(instrument->credential_id),
url::Origin::Create(request->delegate->GetTopOrigin()), url::Origin::Create(request->delegate->GetTopOrigin()),
request->delegate->GetSpec()->details().total->amount, request->delegate->GetSpec()->details().total->amount,
......
...@@ -4,10 +4,16 @@ ...@@ -4,10 +4,16 @@
#include "components/payments/content/secure_payment_confirmation_app.h" #include "components/payments/content/secure_payment_confirmation_app.h"
#include <memory>
#include "base/base64.h" #include "base/base64.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/payments/internal_authenticator.h" #include "components/autofill/core/browser/payments/internal_authenticator.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_web_contents_factory.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h" #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
...@@ -24,6 +30,10 @@ static constexpr char kCredentialIdBase64[] = "cccc"; ...@@ -24,6 +30,10 @@ static constexpr char kCredentialIdBase64[] = "cccc";
class MockAuthenticator : public autofill::InternalAuthenticator { class MockAuthenticator : public autofill::InternalAuthenticator {
public: public:
MockAuthenticator()
: web_contents_(web_contents_factory_.CreateWebContents(&context_)) {}
~MockAuthenticator() override = default;
MOCK_METHOD1(SetEffectiveOrigin, void(const url::Origin&)); MOCK_METHOD1(SetEffectiveOrigin, void(const url::Origin&));
MOCK_METHOD2( MOCK_METHOD2(
MakeCredential, MakeCredential,
...@@ -35,6 +45,10 @@ class MockAuthenticator : public autofill::InternalAuthenticator { ...@@ -35,6 +45,10 @@ class MockAuthenticator : public autofill::InternalAuthenticator {
MOCK_METHOD0(Cancel, void()); MOCK_METHOD0(Cancel, void());
MOCK_METHOD1(VerifyChallenge, void(const std::vector<uint8_t>&)); MOCK_METHOD1(VerifyChallenge, void(const std::vector<uint8_t>&));
content::RenderFrameHost* GetRenderFrameHost() override {
return web_contents_->GetMainFrame();
}
// Implements an autofill::InternalAuthenticator method to delegate fields of // Implements an autofill::InternalAuthenticator method to delegate fields of
// |options| to gmock methods for easier verification. // |options| to gmock methods for easier verification.
void GetAssertion( void GetAssertion(
...@@ -42,6 +56,14 @@ class MockAuthenticator : public autofill::InternalAuthenticator { ...@@ -42,6 +56,14 @@ class MockAuthenticator : public autofill::InternalAuthenticator {
blink::mojom::Authenticator::GetAssertionCallback callback) override { blink::mojom::Authenticator::GetAssertionCallback callback) override {
VerifyChallenge(options->challenge); VerifyChallenge(options->challenge);
} }
content::WebContents* web_contents() { return web_contents_; }
private:
content::BrowserTaskEnvironment task_environment_;
content::TestBrowserContext context_;
content::TestWebContentsFactory web_contents_factory_;
content::WebContents* web_contents_; // Owned by `web_contents_factory_`.
}; };
class SecurePaymentConfirmationAppTest : public testing::Test { class SecurePaymentConfirmationAppTest : public testing::Test {
...@@ -77,9 +99,10 @@ TEST_F(SecurePaymentConfirmationAppTest, Smoke) { ...@@ -77,9 +99,10 @@ TEST_F(SecurePaymentConfirmationAppTest, Smoke) {
auto authenticator = std::make_unique<MockAuthenticator>(); auto authenticator = std::make_unique<MockAuthenticator>();
MockAuthenticator* mock_authenticator = authenticator.get(); MockAuthenticator* mock_authenticator = authenticator.get();
content::WebContents* web_contents = authenticator->web_contents();
SecurePaymentConfirmationApp app( SecurePaymentConfirmationApp app(
"effective_rp.example", web_contents, "effective_rp.example",
/*icon=*/std::make_unique<SkBitmap>(), label_, std::move(credential_id), /*icon=*/std::make_unique<SkBitmap>(), label_, std::move(credential_id),
url::Origin::Create(GURL("https://merchant.example")), total_, url::Origin::Create(GURL("https://merchant.example")), total_,
MakeRequest(), std::move(authenticator)); MakeRequest(), std::move(authenticator));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment