Commit 54e0d1eb authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Web Payment] Enable secure payment confirmation from an iframe.

Before this patch, invoking PaymentRequest API with secure payment
confirmation method in a cross-origin iframe would display the secure
payment confirmation dialog UI, but proceeding to verify the payment
with WebAuthn would return NOT_ALLOWED_ERROR.

This patch creates autofill::InternalAuthenticator on the top-level
RenderFrameHost of the WebContents instead of the RenderFrameHost of the
exact iframe that invoked PaymentRequest API.

After this patch, it is possible to use secure payment confirmation
method in a cross-origin iframe.

Bug: 1123217
Change-Id: Ifc3ec58a5bb57a2544c51d15aaa1035b15da6190
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2383452Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarNick Burris <nburris@chromium.org>
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802974}
parent 1b6200aa
...@@ -183,9 +183,14 @@ bool ChromePaymentRequestDelegate::IsBrowserWindowActive() const { ...@@ -183,9 +183,14 @@ bool ChromePaymentRequestDelegate::IsBrowserWindowActive() const {
} }
std::unique_ptr<autofill::InternalAuthenticator> std::unique_ptr<autofill::InternalAuthenticator>
ChromePaymentRequestDelegate::CreateInternalAuthenticator( ChromePaymentRequestDelegate::CreateInternalAuthenticator() const {
content::RenderFrameHost* rfh) const { // This authenticator can be used in a cross-origin iframe only if the
return std::make_unique<content::InternalAuthenticatorImpl>(rfh); // 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<content::InternalAuthenticatorImpl>(
web_contents_->GetMainFrame());
} }
scoped_refptr<PaymentManifestWebDataService> scoped_refptr<PaymentManifestWebDataService>
...@@ -244,4 +249,8 @@ std::string ChromePaymentRequestDelegate::GetTwaPackageName() const { ...@@ -244,4 +249,8 @@ std::string ChromePaymentRequestDelegate::GetTwaPackageName() const {
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
} }
PaymentRequestDialog* ChromePaymentRequestDelegate::GetDialogForTesting() {
return shown_dialog_.get();
}
} // namespace payments } // namespace payments
...@@ -48,8 +48,8 @@ class ChromePaymentRequestDelegate : public ContentPaymentRequestDelegate { ...@@ -48,8 +48,8 @@ class ChromePaymentRequestDelegate : public ContentPaymentRequestDelegate {
bool IsBrowserWindowActive() const override; bool IsBrowserWindowActive() const override;
// ContentPaymentRequestDelegate: // ContentPaymentRequestDelegate:
std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator( std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator()
content::RenderFrameHost* rfh) const override; const override;
scoped_refptr<PaymentManifestWebDataService> scoped_refptr<PaymentManifestWebDataService>
GetPaymentManifestWebDataService() const override; GetPaymentManifestWebDataService() const override;
PaymentRequestDisplayManager* GetDisplayManager() override; PaymentRequestDisplayManager* GetDisplayManager() override;
...@@ -60,6 +60,7 @@ class ChromePaymentRequestDelegate : public ContentPaymentRequestDelegate { ...@@ -60,6 +60,7 @@ class ChromePaymentRequestDelegate : public ContentPaymentRequestDelegate {
std::string GetInvalidSslCertificateErrorMessage() override; std::string GetInvalidSslCertificateErrorMessage() override;
bool SkipUiForBasicCard() const override; bool SkipUiForBasicCard() const override;
std::string GetTwaPackageName() const override; std::string GetTwaPackageName() const override;
PaymentRequestDialog* GetDialogForTesting() override;
protected: protected:
// Reference to the dialog so that we can satisfy calls to CloseDialog(). This // Reference to the dialog so that we can satisfy calls to CloseDialog(). This
......
...@@ -116,7 +116,14 @@ class SecurePaymentConfirmationTest ...@@ -116,7 +116,14 @@ class SecurePaymentConfirmationTest
databse_write_responded_ = true; databse_write_responded_ = true;
} }
void OnAppListReady() override {
PaymentRequestPlatformBrowserTestBase::OnAppListReady();
if (confirm_payment_)
ASSERT_TRUE(test_controller()->ConfirmPayment());
}
bool databse_write_responded_ = false; bool databse_write_responded_ = false;
bool confirm_payment_ = false;
}; };
IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationTest, NoAuthenticator) { IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationTest, NoAuthenticator) {
...@@ -327,9 +334,13 @@ class SecurePaymentConfirmationCreationTest ...@@ -327,9 +334,13 @@ class SecurePaymentConfirmationCreationTest
// that still needs to be investigated. // that still needs to be investigated.
#define MAYBE_CreatePaymentCredential DISABLED_CreatePaymentCredential #define MAYBE_CreatePaymentCredential DISABLED_CreatePaymentCredential
#define MAYBE_LookupPaymentCredential DISABLED_LookupPaymentCredential #define MAYBE_LookupPaymentCredential DISABLED_LookupPaymentCredential
#define MAYBE_ConfirmPaymentInCrossOriginIframe \
DISABLED_ConfirmPaymentInCrossOriginIframe
#else #else
#define MAYBE_CreatePaymentCredential CreatePaymentCredential #define MAYBE_CreatePaymentCredential CreatePaymentCredential
#define MAYBE_LookupPaymentCredential LookupPaymentCredential #define MAYBE_LookupPaymentCredential LookupPaymentCredential
#define MAYBE_ConfirmPaymentInCrossOriginIframe \
ConfirmPaymentInCrossOriginIframe
#endif #endif
IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest, IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
MAYBE_CreatePaymentCredential) { MAYBE_CreatePaymentCredential) {
...@@ -373,6 +384,8 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest, ...@@ -373,6 +384,8 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
"}}])", "}}])",
credentialIdentifier); credentialIdentifier);
// Cross the origin boundary.
NavigateTo("b.com", "/payment_handler_status.html");
test_controller()->SetHasAuthenticator(true); test_controller()->SetHasAuthenticator(true);
ResetEventWaiterForSingleEvent(TestEvent::kAppListReady); ResetEventWaiterForSingleEvent(TestEvent::kAppListReady);
...@@ -386,6 +399,37 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest, ...@@ -386,6 +399,37 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
EXPECT_EQ("display_name_for_instrument", EXPECT_EQ("display_name_for_instrument",
test_controller()->app_descriptions().front().label); test_controller()->app_descriptions().front().label);
} }
IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
MAYBE_ConfirmPaymentInCrossOriginIframe) {
NavigateTo("a.com", "/payment_handler_status.html");
ReplaceFidoDiscoveryFactory();
std::string credentialIdentifier =
content::EvalJs(
GetActiveWebContents(),
base::StrCat(
{"async function createPaymentCredential() {",
getPaymentCreationOptions(GetDefaultIconURL()),
" const c = await navigator.credentials.create("
" {payment: PAYMENT_CREATION_OPTIONS});"
" return btoa(String.fromCharCode(...new Uint8Array(c.rawId)));"
"};"
"createPaymentCredential();"}))
.ExtractString();
NavigateTo("b.com", "/iframe_poster.html");
test_controller()->SetHasAuthenticator(true);
confirm_payment_ = true;
// EvalJs waits for JavaScript promise to resolve.
EXPECT_EQ(
"success",
content::EvalJs(
GetActiveWebContents(),
content::JsReplace(
"postToIframe($1, $2);",
https_server()->GetURL("c.com", "/iframe_receiver.html").spec(),
credentialIdentifier)));
}
#endif // !defined(OS_ANDROID) #endif // !defined(OS_ANDROID)
} // namespace } // namespace
......
...@@ -212,6 +212,10 @@ void PaymentRequestDialogView::RetryDialog() { ...@@ -212,6 +212,10 @@ void PaymentRequestDialogView::RetryDialog() {
} }
} }
void PaymentRequestDialogView::ConfirmPaymentForTesting() {
Pay();
}
void PaymentRequestDialogView::OnStartUpdating( void PaymentRequestDialogView::OnStartUpdating(
PaymentRequestSpec::UpdateReason reason) { PaymentRequestSpec::UpdateReason reason) {
ShowProcessingSpinner(); ShowProcessingSpinner();
......
...@@ -116,6 +116,7 @@ class PaymentRequestDialogView : public views::DialogDelegateView, ...@@ -116,6 +116,7 @@ class PaymentRequestDialogView : public views::DialogDelegateView,
const GURL& url, const GURL& url,
PaymentHandlerOpenWindowCallback callback) override; PaymentHandlerOpenWindowCallback callback) override;
void RetryDialog() override; void RetryDialog() override;
void ConfirmPaymentForTesting() override;
// PaymentRequestSpec::Observer: // PaymentRequestSpec::Observer:
void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override; void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/memory/weak_ptr.h"
#include "build/build_config.h" #include "build/build_config.h"
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
...@@ -23,6 +24,8 @@ class WebContents; ...@@ -23,6 +24,8 @@ class WebContents;
namespace payments { namespace payments {
class ContentPaymentRequestDelegate;
struct AppDescription { struct AppDescription {
std::string label; std::string label;
std::string sublabel; std::string sublabel;
...@@ -82,6 +85,11 @@ class PaymentRequestTestController { ...@@ -82,6 +85,11 @@ class PaymentRequestTestController {
bool ClickPaymentHandlerSecurityIcon(); bool ClickPaymentHandlerSecurityIcon();
#endif #endif
// Confirms payment in a browser payment sheet, be it either PAYMENT_REQUEST
// or SECURE_PAYMENT_CONFIRMATION type. Returns true if the dialog was
// available.
bool ConfirmPayment();
// Confirms payment in minimal UI. Returns true on success or if the minimal // Confirms payment in minimal UI. Returns true on success or if the minimal
// UI is not implemented on the current platform. // UI is not implemented on the current platform.
bool ConfirmMinimalUI(); bool ConfirmMinimalUI();
...@@ -135,6 +143,8 @@ class PaymentRequestTestController { ...@@ -135,6 +143,8 @@ class PaymentRequestTestController {
class ObserverConverter; class ObserverConverter;
std::unique_ptr<ObserverConverter> observer_converter_; std::unique_ptr<ObserverConverter> observer_converter_;
base::WeakPtr<ContentPaymentRequestDelegate> delegate_;
#endif #endif
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/test/payments/payment_request_test_controller.h" #include "chrome/test/payments/payment_request_test_controller.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/notreached.h"
#include "chrome/browser/android/background_task_scheduler/chrome_background_task_factory.h" #include "chrome/browser/android/background_task_scheduler/chrome_background_task_factory.h"
#include "chrome/test/payments/android/payment_request_test_bridge.h" #include "chrome/test/payments/android/payment_request_test_bridge.h"
...@@ -23,6 +24,11 @@ bool PaymentRequestTestController::ClickPaymentHandlerSecurityIcon() { ...@@ -23,6 +24,11 @@ bool PaymentRequestTestController::ClickPaymentHandlerSecurityIcon() {
return ClickPaymentHandlerSecurityIconForTest(); return ClickPaymentHandlerSecurityIconForTest();
} }
bool PaymentRequestTestController::ConfirmPayment() {
NOTIMPLEMENTED();
return false;
}
bool PaymentRequestTestController::ConfirmMinimalUI() { bool PaymentRequestTestController::ConfirmMinimalUI() {
return ConfirmMinimalUIForTest(); return ConfirmMinimalUIForTest();
} }
......
...@@ -54,6 +54,7 @@ class ChromePaymentRequestTestDelegate : public ChromePaymentRequestDelegate { ...@@ -54,6 +54,7 @@ class ChromePaymentRequestTestDelegate : public ChromePaymentRequestDelegate {
const std::string& twa_package_name, const std::string& twa_package_name,
bool has_authenticator) bool has_authenticator)
: ChromePaymentRequestDelegate(web_contents), : ChromePaymentRequestDelegate(web_contents),
web_contents_(web_contents),
is_off_the_record_(is_off_the_record), is_off_the_record_(is_off_the_record),
valid_ssl_(valid_ssl), valid_ssl_(valid_ssl),
prefs_(prefs), prefs_(prefs),
...@@ -67,12 +68,14 @@ class ChromePaymentRequestTestDelegate : public ChromePaymentRequestDelegate { ...@@ -67,12 +68,14 @@ class ChromePaymentRequestTestDelegate : public ChromePaymentRequestDelegate {
PrefService* GetPrefService() override { return prefs_; } PrefService* GetPrefService() override { return prefs_; }
bool IsBrowserWindowActive() const override { return true; } bool IsBrowserWindowActive() const override { return true; }
std::string GetTwaPackageName() const override { return twa_package_name_; } std::string GetTwaPackageName() const override { return twa_package_name_; }
std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator( std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator()
content::RenderFrameHost* rfh) const override { const override {
return std::make_unique<TestAuthenticator>(rfh, has_authenticator_); return std::make_unique<TestAuthenticator>(web_contents_->GetMainFrame(),
has_authenticator_);
} }
private: private:
content::WebContents* web_contents_;
const bool is_off_the_record_; const bool is_off_the_record_;
const bool valid_ssl_; const bool valid_ssl_;
PrefService* const prefs_; PrefService* const prefs_;
...@@ -140,6 +143,18 @@ PaymentRequestTestController::GetPaymentHandlerWebContents() { ...@@ -140,6 +143,18 @@ PaymentRequestTestController::GetPaymentHandlerWebContents() {
return nullptr; return nullptr;
} }
bool PaymentRequestTestController::ConfirmPayment() {
if (!delegate_)
return false;
PaymentRequestDialog* dialog = delegate_->GetDialogForTesting();
if (!dialog)
return false;
dialog->ConfirmPaymentForTesting();
return true;
}
bool PaymentRequestTestController::ConfirmMinimalUI() { bool PaymentRequestTestController::ConfirmMinimalUI() {
// Desktop does not have a minimal UI. // Desktop does not have a minimal UI.
return true; return true;
...@@ -210,6 +225,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() { ...@@ -210,6 +225,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() {
const std::string& twa_package_name, bool has_authenticator, const std::string& twa_package_name, bool has_authenticator,
const std::string& twa_payment_app_method_name, const std::string& twa_payment_app_method_name,
const std::string& twa_payment_app_response, const std::string& twa_payment_app_response,
base::WeakPtr<ContentPaymentRequestDelegate>* delegate_weakptr,
mojo::PendingReceiver<payments::mojom::PaymentRequest> receiver, mojo::PendingReceiver<payments::mojom::PaymentRequest> receiver,
content::RenderFrameHost* render_frame_host) { content::RenderFrameHost* render_frame_host) {
content::WebContents* web_contents = content::WebContents* web_contents =
...@@ -218,6 +234,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() { ...@@ -218,6 +234,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() {
auto delegate = std::make_unique<ChromePaymentRequestTestDelegate>( auto delegate = std::make_unique<ChromePaymentRequestTestDelegate>(
web_contents, is_off_the_record, valid_ssl, prefs, twa_package_name, web_contents, is_off_the_record, valid_ssl, prefs, twa_package_name,
has_authenticator); has_authenticator);
*delegate_weakptr = delegate->GetContentWeakPtr();
PaymentRequestWebContentsManager* manager = PaymentRequestWebContentsManager* manager =
PaymentRequestWebContentsManager::GetOrCreateForWebContents( PaymentRequestWebContentsManager::GetOrCreateForWebContents(
web_contents); web_contents);
...@@ -233,7 +250,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() { ...@@ -233,7 +250,7 @@ void PaymentRequestTestController::UpdateDelegateFactory() {
}, },
observer_converter_.get(), is_off_the_record_, valid_ssl_, prefs_.get(), observer_converter_.get(), is_off_the_record_, valid_ssl_, prefs_.get(),
twa_package_name_, has_authenticator_, twa_payment_app_method_name_, twa_package_name_, has_authenticator_, twa_payment_app_method_name_,
twa_payment_app_response_)); twa_payment_app_response_, &delegate_));
} }
void PaymentRequestTestController::OnCanMakePaymentCalled() { void PaymentRequestTestController::OnCanMakePaymentCalled() {
......
...@@ -88,6 +88,7 @@ static_library("content") { ...@@ -88,6 +88,7 @@ static_library("content") {
sources += [ "secure_payment_confirmation_view_stub.cc" ] sources += [ "secure_payment_confirmation_view_stub.cc" ]
} else { } else {
sources += [ sources += [
"content_payment_request_delegate.cc",
"content_payment_request_delegate.h", "content_payment_request_delegate.h",
"payment_credential.cc", "payment_credential.cc",
"payment_credential.h", "payment_credential.h",
...@@ -173,8 +174,6 @@ source_set("unit_tests") { ...@@ -173,8 +174,6 @@ source_set("unit_tests") {
"android_payment_app_unittest.cc", "android_payment_app_unittest.cc",
"payment_method_manifest_table_unittest.cc", "payment_method_manifest_table_unittest.cc",
"service_worker_payment_app_finder_unittest.cc", "service_worker_payment_app_finder_unittest.cc",
"test_content_payment_request_delegate.cc",
"test_content_payment_request_delegate.h",
"web_app_manifest_section_table_unittest.cc", "web_app_manifest_section_table_unittest.cc",
] ]
...@@ -188,6 +187,8 @@ source_set("unit_tests") { ...@@ -188,6 +187,8 @@ source_set("unit_tests") {
"secure_payment_confirmation_app_unittest.cc", "secure_payment_confirmation_app_unittest.cc",
"secure_payment_confirmation_model_unittest.cc", "secure_payment_confirmation_model_unittest.cc",
"service_worker_payment_app_unittest.cc", "service_worker_payment_app_unittest.cc",
"test_content_payment_request_delegate.cc",
"test_content_payment_request_delegate.h",
] ]
} }
......
// Copyright 2020 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 "components/payments/content/content_payment_request_delegate.h"
namespace payments {
ContentPaymentRequestDelegate::~ContentPaymentRequestDelegate() = default;
base::WeakPtr<ContentPaymentRequestDelegate>
ContentPaymentRequestDelegate::GetContentWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
ContentPaymentRequestDelegate::ContentPaymentRequestDelegate() = default;
} // namespace payments
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "base/memory/weak_ptr.h"
#include "components/payments/content/payment_request_display_manager.h" #include "components/payments/content/payment_request_display_manager.h"
#include "components/payments/core/payment_request_delegate.h" #include "components/payments/core/payment_request_delegate.h"
...@@ -18,24 +19,21 @@ namespace autofill { ...@@ -18,24 +19,21 @@ namespace autofill {
class InternalAuthenticator; class InternalAuthenticator;
} // namespace autofill } // namespace autofill
namespace content {
class RenderFrameHost;
} // namespace content
namespace payments { namespace payments {
class PaymentManifestWebDataService; class PaymentManifestWebDataService;
class PaymentRequestDialog;
class PaymentRequestDisplayManager; class PaymentRequestDisplayManager;
// The delegate for PaymentRequest that can use content. // The delegate for PaymentRequest that can use content.
class ContentPaymentRequestDelegate : public PaymentRequestDelegate { class ContentPaymentRequestDelegate : public PaymentRequestDelegate {
public: public:
~ContentPaymentRequestDelegate() override {} ~ContentPaymentRequestDelegate() override;
// Creates and returns an instance of the InternalAuthenticator interface for // Creates and returns an instance of the InternalAuthenticator interface for
// communication with WebAuthn. // communication with WebAuthn.
virtual std::unique_ptr<autofill::InternalAuthenticator> virtual std::unique_ptr<autofill::InternalAuthenticator>
CreateInternalAuthenticator(content::RenderFrameHost* rfh) const = 0; CreateInternalAuthenticator() const = 0;
// Returns the web data service for caching payment method manifests. // Returns the web data service for caching payment method manifests.
virtual scoped_refptr<PaymentManifestWebDataService> virtual scoped_refptr<PaymentManifestWebDataService>
...@@ -73,6 +71,17 @@ class ContentPaymentRequestDelegate : public PaymentRequestDelegate { ...@@ -73,6 +71,17 @@ class ContentPaymentRequestDelegate : public PaymentRequestDelegate {
// Returns the Android package name of the Trusted Web Activity that invoked // Returns the Android package name of the Trusted Web Activity that invoked
// this browser, if any. Otherwise, an empty string. // this browser, if any. Otherwise, an empty string.
virtual std::string GetTwaPackageName() const = 0; virtual std::string GetTwaPackageName() const = 0;
virtual PaymentRequestDialog* GetDialogForTesting() = 0;
// Returns a weak pointer to this delegate.
base::WeakPtr<ContentPaymentRequestDelegate> GetContentWeakPtr();
protected:
ContentPaymentRequestDelegate();
private:
base::WeakPtrFactory<ContentPaymentRequestDelegate> weak_ptr_factory_{this};
}; };
} // namespace payments } // namespace payments
......
...@@ -47,6 +47,9 @@ class PaymentRequestDialog { ...@@ -47,6 +47,9 @@ class PaymentRequestDialog {
virtual void ShowPaymentHandlerScreen( virtual void ShowPaymentHandlerScreen(
const GURL& url, const GURL& url,
PaymentHandlerOpenWindowCallback callback) = 0; PaymentHandlerOpenWindowCallback callback) = 0;
// Confirms payment. Used only in tests.
virtual void ConfirmPaymentForTesting() = 0;
}; };
} // namespace payments } // namespace payments
......
...@@ -139,8 +139,7 @@ PaymentRequestState::GetMethodData() const { ...@@ -139,8 +139,7 @@ PaymentRequestState::GetMethodData() const {
std::unique_ptr<autofill::InternalAuthenticator> std::unique_ptr<autofill::InternalAuthenticator>
PaymentRequestState::CreateInternalAuthenticator() const { PaymentRequestState::CreateInternalAuthenticator() const {
return GetPaymentRequestDelegate()->CreateInternalAuthenticator( return GetPaymentRequestDelegate()->CreateInternalAuthenticator();
initiator_render_frame_host_);
} }
scoped_refptr<PaymentManifestWebDataService> scoped_refptr<PaymentManifestWebDataService>
......
...@@ -161,6 +161,10 @@ void SecurePaymentConfirmationController::ShowPaymentHandlerScreen( ...@@ -161,6 +161,10 @@ void SecurePaymentConfirmationController::ShowPaymentHandlerScreen(
NOTREACHED(); NOTREACHED();
} }
void SecurePaymentConfirmationController::ConfirmPaymentForTesting() {
OnConfirm();
}
void SecurePaymentConfirmationController::OnInitialized( void SecurePaymentConfirmationController::OnInitialized(
InitializationTask* initialization_task) { InitializationTask* initialization_task) {
if (--number_of_initialization_tasks_ == 0) if (--number_of_initialization_tasks_ == 0)
......
...@@ -44,6 +44,7 @@ class SecurePaymentConfirmationController ...@@ -44,6 +44,7 @@ class SecurePaymentConfirmationController
void ShowPaymentHandlerScreen( void ShowPaymentHandlerScreen(
const GURL& url, const GURL& url,
PaymentHandlerOpenWindowCallback callback) override; PaymentHandlerOpenWindowCallback callback) override;
void ConfirmPaymentForTesting() override;
// InitializationTask::Observer: // InitializationTask::Observer:
void OnInitialized(InitializationTask* initialization_task) override; void OnInitialized(InitializationTask* initialization_task) override;
......
...@@ -16,8 +16,7 @@ TestContentPaymentRequestDelegate::TestContentPaymentRequestDelegate( ...@@ -16,8 +16,7 @@ TestContentPaymentRequestDelegate::TestContentPaymentRequestDelegate(
TestContentPaymentRequestDelegate::~TestContentPaymentRequestDelegate() {} TestContentPaymentRequestDelegate::~TestContentPaymentRequestDelegate() {}
std::unique_ptr<autofill::InternalAuthenticator> std::unique_ptr<autofill::InternalAuthenticator>
TestContentPaymentRequestDelegate::CreateInternalAuthenticator( TestContentPaymentRequestDelegate::CreateInternalAuthenticator() const {
content::RenderFrameHost* rfh) const {
return nullptr; return nullptr;
} }
...@@ -63,6 +62,10 @@ std::string TestContentPaymentRequestDelegate::GetTwaPackageName() const { ...@@ -63,6 +62,10 @@ std::string TestContentPaymentRequestDelegate::GetTwaPackageName() const {
return ""; return "";
} }
PaymentRequestDialog* TestContentPaymentRequestDelegate::GetDialogForTesting() {
return nullptr;
}
autofill::PersonalDataManager* autofill::PersonalDataManager*
TestContentPaymentRequestDelegate::GetPersonalDataManager() { TestContentPaymentRequestDelegate::GetPersonalDataManager() {
return core_delegate_.GetPersonalDataManager(); return core_delegate_.GetPersonalDataManager();
......
...@@ -22,8 +22,8 @@ class TestContentPaymentRequestDelegate : public ContentPaymentRequestDelegate { ...@@ -22,8 +22,8 @@ class TestContentPaymentRequestDelegate : public ContentPaymentRequestDelegate {
~TestContentPaymentRequestDelegate() override; ~TestContentPaymentRequestDelegate() override;
// ContentPaymentRequestDelegate: // ContentPaymentRequestDelegate:
std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator( std::unique_ptr<autofill::InternalAuthenticator> CreateInternalAuthenticator()
content::RenderFrameHost* rfh) const override; const override;
scoped_refptr<PaymentManifestWebDataService> scoped_refptr<PaymentManifestWebDataService>
GetPaymentManifestWebDataService() const override; GetPaymentManifestWebDataService() const override;
PaymentRequestDisplayManager* GetDisplayManager() override; PaymentRequestDisplayManager* GetDisplayManager() override;
...@@ -35,6 +35,7 @@ class TestContentPaymentRequestDelegate : public ContentPaymentRequestDelegate { ...@@ -35,6 +35,7 @@ class TestContentPaymentRequestDelegate : public ContentPaymentRequestDelegate {
bool IsBrowserWindowActive() const override; bool IsBrowserWindowActive() const override;
bool SkipUiForBasicCard() const override; bool SkipUiForBasicCard() const override;
std::string GetTwaPackageName() const override; std::string GetTwaPackageName() const override;
PaymentRequestDialog* GetDialogForTesting() override;
autofill::PersonalDataManager* GetPersonalDataManager() override; autofill::PersonalDataManager* GetPersonalDataManager() override;
const std::string& GetApplicationLocale() const override; const std::string& GetApplicationLocale() const override;
bool IsOffTheRecord() const override; bool IsOffTheRecord() const override;
......
<!DOCTYPE html>
<!--
Copyright 2020 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.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<title>Iframe Poster</title>
</head>
<body>
<iframe id="iframe" allow="payment"></iframe>
<script src="iframe_poster.js"></script>
</body>
</html>
/*
* Copyright 2020 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.
*/
/**
* Opens the given `url` in an iframe, posts the `msg` to it, and waits for the
* iframe to return a response.
* @param {string} url - The url to open in the iframe.
* @param {object} msg - The message to post to the iframe.
* @return {Promise<object>} - What the iframe returned.
*/
async function postToIframe(url, msg) { // eslint-disable-line no-unused-vars
let resolveFunction = null;
const promise = new Promise((resolve) => {
resolveFunction = resolve;
});
window.onmessage = (e) => {
resolveFunction(e.data);
};
const iframe = document.getElementById('iframe');
iframe.onload = (e) => {
iframe.contentWindow.postMessage(msg, url);
};
iframe.src = url;
return promise;
}
<!DOCTYPE html>
<!--
Copyright 2020 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.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<title>Iframe Receiver</title>
</head>
<body>
<script src="iframe_receiver.js"></script>
</body>
</html>
/*
* Copyright 2020 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.
*/
window.onmessage = (e) => {
requestPayment(e.data).then((result) => {
e.source.postMessage(result, e.origin);
}).catch((error) => {
e.source.postMessage(error, e.origin);
});
};
/**
* Requests a secure payment confirmation payment for the given credential
* identifier.
* @param {string} credentialId - The base64 encoded identifier of the
* credential to use for payment.
* @return {Promise<object>} - Either the string 'success' or an error message.
*/
async function requestPayment(credentialId) {
try {
const request = new PaymentRequest(
[{supportedMethods: 'secure-payment-confirmation',
data: {
action: 'authenticate',
credentialIds: [Uint8Array.from(atob(credentialId),
(b) => b.charCodeAt(0))],
networkData: new TextEncoder().encode('hello world'),
timeout: 6000,
fallbackUrl: 'https://fallback.example/url',
}}],
{total: {label: 'TEST', amount: {currency: 'USD', value: '0.01'}}});
const response = await request.show();
await response.complete();
return 'success';
} catch (e) {
return e.message;
}
}
...@@ -66,3 +66,28 @@ async function getStatusForMethodDataAfterCanMakePayment( ...@@ -66,3 +66,28 @@ async function getStatusForMethodDataAfterCanMakePayment(
return e.message; return e.message;
} }
} }
/**
* Returns the status field from the payment handler's response for given
* payment method data. Passes a promise into PaymentRequest.show() to delay
* initialization by 1 second.
* @param {array<PaymentMethodData>} methodData - The method data to use.
* @return {string} - The status field or error message.
*/
async function getStatusForMethodDataWithShowPromise(methodData) { // eslint-disable-line no-unused-vars, max-len
try {
const details = {total: {label: 'TEST',
amount: {currency: 'USD', value: '0.01'}}};
const request = new PaymentRequest(methodData, details);
const response = await request.show(new Promise((resolve) => {
window.setTimeout(() => resolve(details), 1000);
}));
await response.complete();
if (!response.details.status) {
return 'Payment handler did not specify the status.';
}
return response.details.status;
} catch (e) {
return e.message;
}
}
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