|  | // Copyright 2021 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/base_paths.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/files/file_enumerator.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/path_service.h" | 
|  | #include "base/test/bind.h" | 
|  | #include "base/test/scoped_feature_list.h" | 
|  | #include "base/threading/thread_restrictions.h" | 
|  | #include "content/browser/lock_screen/lock_screen_service_impl.h" | 
|  | #include "content/browser/lock_screen/lock_screen_storage_impl.h" | 
|  | #include "content/public/browser/render_frame_host.h" | 
|  | #include "content/public/common/content_features.h" | 
|  | #include "content/public/test/browser_test.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  | #include "content/public/test/content_browser_test.h" | 
|  | #include "content/public/test/content_browser_test_utils.h" | 
|  | #include "content/shell/browser/shell.h" | 
|  | #include "mojo/public/cpp/bindings/remote.h" | 
|  | #include "net/dns/mock_host_resolver.h" | 
|  | #include "services/service_manager/public/cpp/interface_provider.h" | 
|  | #include "third_party/blink/public/mojom/lock_screen/lock_screen.mojom.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | class LockScreenServiceImplBrowserTest : public ContentBrowserTest { | 
|  | public: | 
|  | LockScreenServiceImplBrowserTest() { | 
|  | feature_list_.InitAndEnableFeature(features::kWebLockScreenApi); | 
|  | } | 
|  |  | 
|  | LockScreenServiceImplBrowserTest(const LockScreenServiceImplBrowserTest&) = | 
|  | delete; | 
|  | LockScreenServiceImplBrowserTest& operator=( | 
|  | const LockScreenServiceImplBrowserTest&) = delete; | 
|  |  | 
|  | ~LockScreenServiceImplBrowserTest() override = default; | 
|  |  | 
|  | base::FilePath GetStoragePath() { | 
|  | base::FilePath path; | 
|  | EXPECT_TRUE(base::PathService::Get(base::DIR_TEMP, &path)); | 
|  | path = path.AppendASCII("web_lock_screen_api_data"); | 
|  | path = path.AppendASCII("test-user"); | 
|  | return path; | 
|  | } | 
|  |  | 
|  | void SetUpOnMainThread() override { | 
|  | ContentBrowserTest::SetUpOnMainThread(); | 
|  | EXPECT_TRUE(base::DeletePathRecursively(GetStoragePath())); | 
|  | LockScreenStorageImpl::GetInstance()->InitForTesting( | 
|  | shell()->web_contents()->GetBrowserContext(), GetStoragePath()); | 
|  | host_resolver()->AddRule("*", "127.0.0.1"); | 
|  | content::SetupCrossSiteRedirector(embedded_test_server()); | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url = embedded_test_server()->GetURL("/lock_screen/simple.html"); | 
|  | lock_screen_service_ = NavigateAndCreateService(url); | 
|  | } | 
|  |  | 
|  | void TearDownOnMainThread() override { | 
|  | ContentBrowserTest::TearDownOnMainThread(); | 
|  | } | 
|  |  | 
|  | mojo::Remote<blink::mojom::LockScreenService> NavigateAndCreateService( | 
|  | const GURL& url) { | 
|  | Shell* shell = CreateBrowser(); | 
|  | EXPECT_TRUE(NavigateToURL(shell, url)); | 
|  | RenderFrameHost* rfh = shell->web_contents()->GetPrimaryMainFrame(); | 
|  | mojo::Remote<blink::mojom::LockScreenService> service; | 
|  | LockScreenServiceImpl::Create(rfh, service.BindNewPipeAndPassReceiver()); | 
|  | return service; | 
|  | } | 
|  |  | 
|  | blink::mojom::LockScreenService* service() { | 
|  | return lock_screen_service_.get(); | 
|  | } | 
|  |  | 
|  | blink::mojom::LockScreenServiceStatus AwaitSetData( | 
|  | blink::mojom::LockScreenService* service, | 
|  | const std::string& key, | 
|  | const std::string& data) { | 
|  | base::RunLoop run_loop; | 
|  | blink::mojom::LockScreenServiceStatus result; | 
|  | service->SetData(key, data, | 
|  | base::BindLambdaForTesting( | 
|  | [&](blink::mojom::LockScreenServiceStatus status) { | 
|  | result = status; | 
|  | run_loop.Quit(); | 
|  | })); | 
|  | run_loop.Run(); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | std::vector<std::string> AwaitGetKeys( | 
|  | blink::mojom::LockScreenService* service) { | 
|  | base::RunLoop run_loop; | 
|  | std::vector<std::string> result; | 
|  | service->GetKeys( | 
|  | base::BindLambdaForTesting([&](const std::vector<std::string>& keys) { | 
|  | result = keys; | 
|  | run_loop.Quit(); | 
|  | })); | 
|  | run_loop.Run(); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | private: | 
|  | base::test::ScopedFeatureList feature_list_; | 
|  | mojo::Remote<blink::mojom::LockScreenService> lock_screen_service_; | 
|  | }; | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(LockScreenServiceImplBrowserTest, | 
|  | CorrectDirectoryCreated) { | 
|  | base::ScopedAllowBlockingForTesting allow_blocking; | 
|  | base::FilePath expected_dir = GetStoragePath(); | 
|  | EXPECT_FALSE(base::PathExists(expected_dir)); | 
|  | // TODO(crbug.com/1268227): Consider testing write failure case. | 
|  | ASSERT_EQ(blink::mojom::LockScreenServiceStatus::kSuccess, | 
|  | AwaitSetData(service(), "key1", "data1")); | 
|  | ASSERT_TRUE(base::PathExists(expected_dir)); | 
|  |  | 
|  | base::FileEnumerator e(expected_dir, false, | 
|  | base::FileEnumerator::DIRECTORIES); | 
|  | std::vector<base::FilePath> directories; | 
|  | for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) { | 
|  | directories.push_back(name); | 
|  | } | 
|  | ASSERT_EQ(1u, directories.size()); | 
|  | EXPECT_EQ(64u, directories[0].BaseName().MaybeAsASCII().size()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(LockScreenServiceImplBrowserTest, SetDataOpaqueOrigin) { | 
|  | auto service = NavigateAndCreateService(GURL("about:blank")); | 
|  | ASSERT_EQ(blink::mojom::LockScreenServiceStatus::kNotAllowedFromContext, | 
|  | AwaitSetData(service.get(), "key1", "data1")); | 
|  | ASSERT_EQ(blink::mojom::LockScreenServiceStatus::kNotAllowedFromContext, | 
|  | AwaitSetData(service.get(), "key2", "data2")); | 
|  |  | 
|  | std::vector<std::string> result = AwaitGetKeys(service.get()); | 
|  | ASSERT_EQ(0u, result.size()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(LockScreenServiceImplBrowserTest, GetKeys) { | 
|  | std::vector<std::string> result = AwaitGetKeys(service()); | 
|  | ASSERT_EQ(0u, result.size()); | 
|  |  | 
|  | AwaitSetData(service(), "key1", "data1"); | 
|  | AwaitSetData(service(), "key2", "data2"); | 
|  | result = AwaitGetKeys(service()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  |  | 
|  | AwaitSetData(service(), "key2", "data3"); | 
|  | result = AwaitGetKeys(service()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(LockScreenServiceImplBrowserTest, | 
|  | DataNotSharedBetweenDifferentOrigins) { | 
|  | GURL url_a = | 
|  | embedded_test_server()->GetURL("a.com", "/lock_screen/simple.html"); | 
|  | GURL url_b = | 
|  | embedded_test_server()->GetURL("b.com", "/lock_screen/simple.html"); | 
|  | auto service_a = NavigateAndCreateService(url_a); | 
|  | auto service_b = NavigateAndCreateService(url_b); | 
|  |  | 
|  | AwaitSetData(service_a.get(), "key1", "a"); | 
|  | AwaitSetData(service_a.get(), "key2", "a"); | 
|  | std::vector<std::string> result = AwaitGetKeys(service_a.get()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  |  | 
|  | AwaitSetData(service_b.get(), "key1", "b"); | 
|  | AwaitSetData(service_b.get(), "key3", "b"); | 
|  | result = AwaitGetKeys(service_b.get()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key3", result[1]); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(LockScreenServiceImplBrowserTest, | 
|  | DataSharedBetweenSameOrigins) { | 
|  | GURL url_a = embedded_test_server()->GetURL("/lock_screen/simple.html"); | 
|  | GURL url_b = embedded_test_server()->GetURL("/lock_screen/simple.html?abcd"); | 
|  | auto service_a = NavigateAndCreateService(url_a); | 
|  | auto service_b = NavigateAndCreateService(url_b); | 
|  |  | 
|  | AwaitSetData(service_a.get(), "key1", "a"); | 
|  | AwaitSetData(service_a.get(), "key2", "a"); | 
|  | std::vector<std::string> result = AwaitGetKeys(service_a.get()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  |  | 
|  | result = AwaitGetKeys(service_b.get()); | 
|  | ASSERT_EQ(2u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  |  | 
|  | AwaitSetData(service_b.get(), "key1", "b"); | 
|  | AwaitSetData(service_b.get(), "key3", "b"); | 
|  | result = AwaitGetKeys(service_a.get()); | 
|  | ASSERT_EQ(3u, result.size()); | 
|  | EXPECT_EQ("key1", result[0]); | 
|  | EXPECT_EQ("key2", result[1]); | 
|  | EXPECT_EQ("key3", result[2]); | 
|  | } | 
|  |  | 
|  | }  // namespace content |