| // 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 "base/macros.h" |
| #include "build/build_config.h" |
| #include "chrome/test/base/chrome_test_utils.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/service_worker_host_interceptor.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| #if defined(OS_ANDROID) |
| #include "chrome/test/base/android/android_browser_test.h" |
| #else |
| #include "chrome/browser/payments/chrome_payment_request_delegate.h" |
| #include "chrome/browser/payments/payment_request_factory.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "components/payments/content/payment_request_web_contents_manager.h" |
| #endif |
| |
| namespace payments { |
| namespace { |
| |
| class PaymentHandlerExploitTest : public PlatformBrowserTest, |
| public content::ServiceWorkerHostInterceptor { |
| public: |
| PaymentHandlerExploitTest() |
| : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} |
| |
| ~PaymentHandlerExploitTest() override {} |
| |
| content::WebContents* GetActiveWebContents() { |
| return chrome_test_utils::GetActiveWebContents(this); |
| } |
| |
| void set_payment_handler_window_url(const GURL& url) { |
| payment_handler_window_url_ = url; |
| } |
| |
| GURL GetTestServerUrl(const std::string& relative_path) { |
| return https_server_.GetURL(relative_path); |
| } |
| |
| private: |
| #if !defined(OS_ANDROID) |
| // A delegate for PaymentRequest that mimics the browser window always being |
| // active, which is a requirement for launching PaymentRequest, but is false |
| // in MacOS browser tests. |
| class TestDelegate : public ChromePaymentRequestDelegate { |
| public: |
| explicit TestDelegate(content::WebContents* web_contents) |
| : ChromePaymentRequestDelegate(web_contents) {} |
| ~TestDelegate() override {} |
| |
| // ChromePaymentRequestDelegate: |
| bool IsBrowserWindowActive() const override { return true; } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TestDelegate); |
| }; |
| |
| void CreatePaymentRequestForTest( |
| payments::mojom::PaymentRequestRequest request, |
| content::RenderFrameHost* render_frame_host) { |
| auto* web_contents = |
| content::WebContents::FromRenderFrameHost(render_frame_host); |
| PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents) |
| ->CreatePaymentRequest(render_frame_host, web_contents, |
| std::make_unique<TestDelegate>(web_contents), |
| std::move(request), |
| /*observer_for_testing=*/nullptr); |
| } |
| #endif // !OS_ANDROID |
| |
| // PlatformBrowserTest: |
| void SetUpOnMainThread() override { |
| https_server_.ServeFilesFromSourceDirectory( |
| "components/test/data/payments"); |
| ASSERT_TRUE(https_server_.Start()); |
| ASSERT_TRUE(content::NavigateToURL( |
| GetActiveWebContents(), GetTestServerUrl("/payment_handler.html"))); |
| |
| #if !defined(OS_ANDROID) |
| // Use TestDelegate that helps with MacOS browser test environment: |
| payments::SetPaymentRequestFactoryForTesting(base::BindRepeating( |
| &PaymentHandlerExploitTest::CreatePaymentRequestForTest, |
| base::Unretained(this))); |
| #endif // !OS_ANDROID |
| |
| PlatformBrowserTest::SetUpOnMainThread(); |
| } |
| |
| // content::ServiceWorkerHostInterceptor: |
| bool WillOpenPaymentHandlerWindow(GURL* url) override { |
| *url = payment_handler_window_url_; |
| return true; |
| } |
| |
| GURL payment_handler_window_url_; |
| net::EmbeddedTestServer https_server_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PaymentHandlerExploitTest); |
| }; |
| |
| // Unable to launch a payment handler window on Android through browser test. |
| // https://crbug.com/998737 |
| #if defined(OS_ANDROID) |
| #define MAYBE_SmokeTest DISABLED_SmokeTest |
| #else |
| #define MAYBE_SmokeTest SmokeTest |
| #endif |
| IN_PROC_BROWSER_TEST_F(PaymentHandlerExploitTest, MAYBE_SmokeTest) { |
| std::string expected = "success"; |
| EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()")); |
| EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "launch()")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PaymentHandlerExploitTest, |
| RendererCannotOpenCrossOriginWindow) { |
| std::string expected = "success"; |
| EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()")); |
| |
| GURL service_worker_scope = GetTestServerUrl("/"); |
| int service_worker_process_id = -1; |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| InterceptServiceWorkerHostWithScope( |
| GetActiveWebContents()->GetBrowserContext(), |
| service_worker_scope, &service_worker_process_id)); |
| |
| content::RenderProcessHostWatcher crash_observer( |
| content::RenderProcessHost::FromID(service_worker_process_id), |
| content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| |
| GURL cross_origin_url("https://127.0.0.1:80"); |
| EXPECT_FALSE(url::IsSameOriginWith(cross_origin_url, service_worker_scope)); |
| set_payment_handler_window_url(cross_origin_url); |
| |
| EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), "launch()")); |
| |
| crash_observer.Wait(); |
| EXPECT_FALSE(crash_observer.did_exit_normally()); |
| } |
| |
| } // namespace |
| } // namespace payments |