blob: 279a6da8b7974cf4be03283499d3a9525a095de0 [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 "components/gcm_driver/gcm_driver_desktop.h"
#include <stdint.h>
#include "base/base64.h"
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/message_loop/message_loop_current.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/gcm_driver/crypto/gcm_decryption_result.h"
#include "components/gcm_driver/crypto/gcm_encryption_provider.h"
#include "components/gcm_driver/crypto/gcm_encryption_result.h"
#include "components/gcm_driver/fake_gcm_client_factory.h"
#include "components/gcm_driver/gcm_client_factory.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "crypto/ec_private_key.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
namespace {
const char kTestAppID1[] = "TestApp1";
void PumpCurrentLoop() {
base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
}
} // namespace
class GCMDriverBaseTest : public testing::Test {
public:
enum WaitToFinish { DO_NOT_WAIT, WAIT };
GCMDriverBaseTest();
~GCMDriverBaseTest() override;
// testing::Test:
void SetUp() override;
void TearDown() override;
GCMDriverDesktop* driver() { return driver_.get(); }
const std::string& p256dh() const { return p256dh_; }
const std::string& auth_secret() const { return auth_secret_; }
network::TestURLLoaderFactory& loader() { return test_url_loader_factory_; }
GCMEncryptionResult encryption_result() { return encryption_result_; }
const std::string& encrypted_message() { return encrypted_message_; }
GCMDecryptionResult decryption_result() { return decryption_result_; }
const std::string& decrypted_message() { return decrypted_message_; }
void PumpIOLoop();
void CreateDriver();
void ShutdownDriver();
void GetEncryptionInfo(const std::string& app_id,
WaitToFinish wait_to_finish);
void EncryptMessage(const std::string& app_id,
const std::string& authorized_entity,
const std::string& p256dh,
const std::string& auth_secret,
const std::string& message,
WaitToFinish wait_to_finish);
void DecryptMessage(const std::string& app_id,
const std::string& authorized_entity,
const std::string& message,
WaitToFinish wait_to_finish);
void GetEncryptionInfoCompleted(std::string p256dh, std::string auth_secret);
void EncryptMessageCompleted(GCMEncryptionResult result, std::string message);
void DecryptMessageCompleted(GCMDecryptionResult result, std::string message);
void UnregisterCompleted(GCMClient::Result result);
private:
base::ScopedTempDir temp_dir_;
TestingPrefServiceSimple prefs_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::MainThreadType::UI};
base::Thread io_thread_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<GCMDriverDesktop> driver_;
base::OnceClosure async_operation_completed_callback_;
std::string p256dh_;
std::string auth_secret_;
GCMEncryptionResult encryption_result_ =
GCMEncryptionResult::ENCRYPTION_FAILED;
std::string encrypted_message_;
GCMDecryptionResult decryption_result_ = GCMDecryptionResult::UNENCRYPTED;
std::string decrypted_message_;
DISALLOW_COPY_AND_ASSIGN(GCMDriverBaseTest);
};
GCMDriverBaseTest::GCMDriverBaseTest() : io_thread_("IOThread") {}
GCMDriverBaseTest::~GCMDriverBaseTest() = default;
void GCMDriverBaseTest::SetUp() {
io_thread_.Start();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
CreateDriver();
PumpIOLoop();
PumpCurrentLoop();
}
void GCMDriverBaseTest::TearDown() {
if (!driver_)
return;
ShutdownDriver();
driver_.reset();
PumpIOLoop();
io_thread_.Stop();
task_environment_.RunUntilIdle();
ASSERT_TRUE(temp_dir_.Delete());
}
void GCMDriverBaseTest::PumpIOLoop() {
base::RunLoop run_loop;
io_thread_.task_runner()->PostTaskAndReply(
FROM_HERE, base::BindOnce(&PumpCurrentLoop), run_loop.QuitClosure());
run_loop.Run();
}
void GCMDriverBaseTest::CreateDriver() {
scoped_refptr<net::URLRequestContextGetter> request_context =
new net::TestURLRequestContextGetter(io_thread_.task_runner());
GCMClient::ChromeBuildInfo chrome_build_info;
chrome_build_info.product_category_for_subtypes = "com.chrome.macosx";
driver_ = std::make_unique<GCMDriverDesktop>(
std::make_unique<FakeGCMClientFactory>(
base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner()),
chrome_build_info, "user-agent-string", &prefs_, temp_dir_.GetPath(),
/*remove_account_mappings_with_email_key=*/true, base::DoNothing(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
network::TestNetworkConnectionTracker::GetInstance(),
base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner(),
task_environment_.GetMainThreadTaskRunner());
}
void GCMDriverBaseTest::ShutdownDriver() {
driver()->Shutdown();
}
void GCMDriverBaseTest::GetEncryptionInfo(const std::string& app_id,
WaitToFinish wait_to_finish) {
base::RunLoop run_loop;
async_operation_completed_callback_ = run_loop.QuitClosure();
driver_->GetEncryptionInfo(
app_id, base::BindOnce(&GCMDriverBaseTest::GetEncryptionInfoCompleted,
base::Unretained(this)));
if (wait_to_finish == WAIT)
run_loop.Run();
}
void GCMDriverBaseTest::EncryptMessage(const std::string& app_id,
const std::string& authorized_entity,
const std::string& p256dh,
const std::string& auth_secret,
const std::string& message,
WaitToFinish wait_to_finish) {
base::RunLoop run_loop;
async_operation_completed_callback_ = run_loop.QuitClosure();
driver()->EncryptMessage(
app_id, authorized_entity, p256dh, auth_secret, message,
base::BindOnce(&GCMDriverBaseTest::EncryptMessageCompleted,
base::Unretained(this)));
if (wait_to_finish == WAIT)
run_loop.Run();
}
void GCMDriverBaseTest::DecryptMessage(const std::string& app_id,
const std::string& authorized_entity,
const std::string& message,
WaitToFinish wait_to_finish) {
base::RunLoop run_loop;
async_operation_completed_callback_ = run_loop.QuitClosure();
driver()->DecryptMessage(
app_id, authorized_entity, message,
base::BindOnce(&GCMDriverBaseTest::DecryptMessageCompleted,
base::Unretained(this)));
if (wait_to_finish == WAIT)
run_loop.Run();
}
void GCMDriverBaseTest::GetEncryptionInfoCompleted(std::string p256dh,
std::string auth_secret) {
p256dh_ = std::move(p256dh);
auth_secret_ = std::move(auth_secret);
if (!async_operation_completed_callback_.is_null())
std::move(async_operation_completed_callback_).Run();
}
void GCMDriverBaseTest::EncryptMessageCompleted(GCMEncryptionResult result,
std::string message) {
encryption_result_ = result;
encrypted_message_ = std::move(message);
if (!async_operation_completed_callback_.is_null())
std::move(async_operation_completed_callback_).Run();
}
void GCMDriverBaseTest::DecryptMessageCompleted(GCMDecryptionResult result,
std::string message) {
decryption_result_ = result;
decrypted_message_ = std::move(message);
if (!async_operation_completed_callback_.is_null())
std::move(async_operation_completed_callback_).Run();
}
TEST_F(GCMDriverBaseTest, EncryptionDecryptionRoundTrip) {
GetEncryptionInfo(kTestAppID1, GCMDriverBaseTest::WAIT);
std::string message = "payload";
ASSERT_NO_FATAL_FAILURE(
EncryptMessage(kTestAppID1, /* authorized_entity= */ "", p256dh(),
auth_secret(), message, GCMDriverBaseTest::WAIT));
EXPECT_EQ(GCMEncryptionResult::ENCRYPTED_DRAFT_08, encryption_result());
ASSERT_NO_FATAL_FAILURE(
DecryptMessage(kTestAppID1, /* authorized_entity= */ "",
encrypted_message(), GCMDriverBaseTest::WAIT));
EXPECT_EQ(GCMDecryptionResult::DECRYPTED_DRAFT_08, decryption_result());
EXPECT_EQ(message, decrypted_message());
}
TEST_F(GCMDriverBaseTest, EncryptionError) {
// Intentionally not creating encryption info.
std::string message = "payload";
ASSERT_NO_FATAL_FAILURE(
EncryptMessage(kTestAppID1, /* authorized_entity= */ "", p256dh(),
auth_secret(), message, GCMDriverBaseTest::WAIT));
EXPECT_EQ(GCMEncryptionResult::NO_KEYS, encryption_result());
}
} // namespace gcm