// Copyright 2014 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 "net/ssl/default_channel_id_store.h"

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "crypto/ec_private_key.h"
#include "net/base/net_errors.h"
#include "net/test/channel_id_test_util.h"
#include "net/test/gtest_util.h"
#include "net/test/test_with_scoped_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using net::test::IsError;
using net::test::IsOk;

namespace net {

namespace {

void CallCounter(int* counter) {
  (*counter)++;
}

void GetChannelIDCallbackNotCalled(
    int err,
    const std::string& server_identifier,
    std::unique_ptr<crypto::ECPrivateKey> key_result) {
  ADD_FAILURE() << "Unexpected callback execution.";
}

class AsyncGetChannelIDHelper {
 public:
  AsyncGetChannelIDHelper() : called_(false) {}

  void Callback(int err,
                const std::string& server_identifier,
                std::unique_ptr<crypto::ECPrivateKey> key_result) {
    err_ = err;
    server_identifier_ = server_identifier;
    key_ = std::move(key_result);
    called_ = true;
  }

  int err_;
  std::string server_identifier_;
  std::unique_ptr<crypto::ECPrivateKey> key_;
  bool called_;
};

void GetAllCallback(
    ChannelIDStore::ChannelIDList* dest,
    const ChannelIDStore::ChannelIDList& result) {
  *dest = result;
}

class MockPersistentStore
    : public DefaultChannelIDStore::PersistentStore {
 public:
  MockPersistentStore();

  // DefaultChannelIDStore::PersistentStore implementation.
  void Load(const LoadedCallback& loaded_callback) override;
  void AddChannelID(
      const DefaultChannelIDStore::ChannelID& channel_id) override;
  void DeleteChannelID(
      const DefaultChannelIDStore::ChannelID& channel_id) override;
  void SetForceKeepSessionState() override;
  void Flush() override;

 protected:
  ~MockPersistentStore() override;

 private:
  typedef std::map<std::string, DefaultChannelIDStore::ChannelID>
      ChannelIDMap;

  ChannelIDMap channel_ids_;
};

MockPersistentStore::MockPersistentStore() = default;

void MockPersistentStore::Load(const LoadedCallback& loaded_callback) {
  std::unique_ptr<
      std::vector<std::unique_ptr<DefaultChannelIDStore::ChannelID>>>
      channel_ids(
          new std::vector<std::unique_ptr<DefaultChannelIDStore::ChannelID>>());
  ChannelIDMap::iterator it;

  for (it = channel_ids_.begin(); it != channel_ids_.end(); ++it) {
    channel_ids->push_back(
        std::make_unique<DefaultChannelIDStore::ChannelID>(it->second));
  }

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE, base::Bind(loaded_callback, base::Passed(&channel_ids)));
}

void MockPersistentStore::AddChannelID(
    const DefaultChannelIDStore::ChannelID& channel_id) {
  channel_ids_[channel_id.server_identifier()] = channel_id;
}

void MockPersistentStore::DeleteChannelID(
    const DefaultChannelIDStore::ChannelID& channel_id) {
  channel_ids_.erase(channel_id.server_identifier());
}

void MockPersistentStore::SetForceKeepSessionState() {}

void MockPersistentStore::Flush() {}

MockPersistentStore::~MockPersistentStore() = default;

bool DomainEquals(const std::string& domain1, const std::string& domain2) {
  return domain1 == domain2;
}

bool DomainNotEquals(const std::string& domain1, const std::string& domain2) {
  return !DomainEquals(domain1, domain2);
}

}  // namespace

using DefaultChannelIDStoreTest = TestWithScopedTaskEnvironment;

TEST_F(DefaultChannelIDStoreTest, TestLoading) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);

  persistent_store->AddChannelID(DefaultChannelIDStore::ChannelID(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));
  persistent_store->AddChannelID(DefaultChannelIDStore::ChannelID(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));

  // Make sure channel_ids load properly.
  DefaultChannelIDStore store(persistent_store.get());
  // Load has not occurred yet.
  EXPECT_EQ(0, store.GetChannelIDCount());
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set task.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(2, store.GetChannelIDCount());
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "twitter.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Set should be synchronous now that load is done.
  EXPECT_EQ(3, store.GetChannelIDCount());
}

//TODO(mattm): add more tests of without a persistent store?
TEST_F(DefaultChannelIDStoreTest, TestSettingAndGetting) {
  // No persistent store, all calls will be synchronous.
  DefaultChannelIDStore store(NULL);
  std::unique_ptr<crypto::ECPrivateKey> expected_key(
      crypto::ECPrivateKey::Create());

  std::unique_ptr<crypto::ECPrivateKey> key;
  EXPECT_EQ(0, store.GetChannelIDCount());
  EXPECT_EQ(ERR_FILE_NOT_FOUND,
            store.GetChannelID("verisign.com", &key,
                               base::Bind(&GetChannelIDCallbackNotCalled)));
  EXPECT_FALSE(key);
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time::FromInternalValue(123),
      expected_key->Copy()));
  EXPECT_EQ(OK, store.GetChannelID("verisign.com", &key,
                                   base::Bind(&GetChannelIDCallbackNotCalled)));
  EXPECT_TRUE(KeysEqual(expected_key.get(), key.get()));
}

TEST_F(DefaultChannelIDStoreTest, TestDuplicateChannelIds) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());
  std::unique_ptr<crypto::ECPrivateKey> expected_key(
      crypto::ECPrivateKey::Create());

  std::unique_ptr<crypto::ECPrivateKey> key;
  EXPECT_EQ(0, store.GetChannelIDCount());
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time::FromInternalValue(123),
      crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time::FromInternalValue(456),
      expected_key->Copy()));

  // Wait for load & queued set tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, store.GetChannelIDCount());
  EXPECT_EQ(OK, store.GetChannelID("verisign.com", &key,
                                   base::Bind(&GetChannelIDCallbackNotCalled)));
  EXPECT_TRUE(KeysEqual(expected_key.get(), key.get()));
}

TEST_F(DefaultChannelIDStoreTest, TestAsyncGet) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  std::unique_ptr<crypto::ECPrivateKey> expected_key(
      crypto::ECPrivateKey::Create());
  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "verisign.com", base::Time::FromInternalValue(123),
      expected_key->Copy()));

  DefaultChannelIDStore store(persistent_store.get());
  AsyncGetChannelIDHelper helper;
  std::unique_ptr<crypto::ECPrivateKey> key;
  EXPECT_EQ(0, store.GetChannelIDCount());
  EXPECT_EQ(ERR_IO_PENDING,
            store.GetChannelID("verisign.com", &key,
                               base::Bind(&AsyncGetChannelIDHelper::Callback,
                                          base::Unretained(&helper))));

  // Wait for load & queued get tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, store.GetChannelIDCount());
  EXPECT_FALSE(key);
  EXPECT_TRUE(helper.called_);
  EXPECT_THAT(helper.err_, IsOk());
  EXPECT_EQ("verisign.com", helper.server_identifier_);
  EXPECT_TRUE(KeysEqual(expected_key.get(), helper.key_.get()));
}

TEST_F(DefaultChannelIDStoreTest, TestDeleteAll) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());

  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set tasks.
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(3, store.GetChannelIDCount());
  int delete_finished = 0;
  store.DeleteAll(base::Bind(&CallCounter, &delete_finished));
  ASSERT_EQ(1, delete_finished);
  EXPECT_EQ(0, store.GetChannelIDCount());
}

TEST_F(DefaultChannelIDStoreTest, TestDeleteForDomains) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());

  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(3, store.GetChannelIDCount());

  // Whitelist deletion.
  int deletions_finished = 0;
  store.DeleteForDomainsCreatedBetween(
      base::Bind(&DomainEquals, base::ConstRef(std::string("verisign.com"))),
      base::Time(), base::Time(),
      base::Bind(&CallCounter, &deletions_finished));
  ASSERT_EQ(1, deletions_finished);
  EXPECT_EQ(2, store.GetChannelIDCount());
  ChannelIDStore::ChannelIDList channel_ids;
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids));
  EXPECT_EQ("google.com", channel_ids.begin()->server_identifier());
  EXPECT_EQ("harvard.com", channel_ids.back().server_identifier());

  // Blacklist deletion.
  store.DeleteForDomainsCreatedBetween(
      base::Bind(&DomainNotEquals, base::ConstRef(std::string("google.com"))),
      base::Time(), base::Time(),
      base::Bind(&CallCounter, &deletions_finished));
  ASSERT_EQ(2, deletions_finished);
  EXPECT_EQ(1, store.GetChannelIDCount());
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids));
  EXPECT_EQ("google.com", channel_ids.begin()->server_identifier());
}

TEST_F(DefaultChannelIDStoreTest, TestAsyncGetAndDeleteAll) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));

  ChannelIDStore::ChannelIDList pre_channel_ids;
  ChannelIDStore::ChannelIDList post_channel_ids;
  int delete_finished = 0;
  DefaultChannelIDStore store(persistent_store.get());

  store.GetAllChannelIDs(base::Bind(GetAllCallback, &pre_channel_ids));
  store.DeleteAll(base::Bind(&CallCounter, &delete_finished));
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &post_channel_ids));
  // Tasks have not run yet.
  EXPECT_EQ(0u, pre_channel_ids.size());
  // Wait for load & queued tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, store.GetChannelIDCount());
  EXPECT_EQ(2u, pre_channel_ids.size());
  EXPECT_EQ(0u, post_channel_ids.size());
}

TEST_F(DefaultChannelIDStoreTest, TestDelete) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());

  std::unique_ptr<crypto::ECPrivateKey> key;
  EXPECT_EQ(0, store.GetChannelIDCount());
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set task.
  base::RunLoop().RunUntilIdle();

  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));

  EXPECT_EQ(2, store.GetChannelIDCount());
  int delete_finished = 0;
  store.DeleteChannelID("verisign.com",
                              base::Bind(&CallCounter, &delete_finished));
  ASSERT_EQ(1, delete_finished);
  EXPECT_EQ(1, store.GetChannelIDCount());
  EXPECT_EQ(ERR_FILE_NOT_FOUND,
            store.GetChannelID("verisign.com", &key,
                               base::Bind(&GetChannelIDCallbackNotCalled)));
  EXPECT_EQ(OK, store.GetChannelID("google.com", &key,
                                   base::Bind(&GetChannelIDCallbackNotCalled)));
  int delete2_finished = 0;
  store.DeleteChannelID("google.com",
                        base::Bind(&CallCounter, &delete2_finished));
  ASSERT_EQ(1, delete2_finished);
  EXPECT_EQ(0, store.GetChannelIDCount());
  EXPECT_EQ(ERR_FILE_NOT_FOUND,
            store.GetChannelID("google.com", &key,
                               base::Bind(&GetChannelIDCallbackNotCalled)));
}

TEST_F(DefaultChannelIDStoreTest, TestAsyncDelete) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  std::unique_ptr<crypto::ECPrivateKey> expected_key(
      crypto::ECPrivateKey::Create());
  persistent_store->AddChannelID(
      ChannelIDStore::ChannelID("a.com", base::Time::FromInternalValue(1),
                                crypto::ECPrivateKey::Create()));
  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "b.com", base::Time::FromInternalValue(3), expected_key->Copy()));
  DefaultChannelIDStore store(persistent_store.get());
  int delete_finished = 0;
  store.DeleteChannelID("a.com",
                        base::Bind(&CallCounter, &delete_finished));

  AsyncGetChannelIDHelper a_helper;
  AsyncGetChannelIDHelper b_helper;
  std::unique_ptr<crypto::ECPrivateKey> key;
  EXPECT_EQ(0, store.GetChannelIDCount());
  EXPECT_EQ(ERR_IO_PENDING,
            store.GetChannelID("a.com", &key,
                               base::Bind(&AsyncGetChannelIDHelper::Callback,
                                          base::Unretained(&a_helper))));
  EXPECT_EQ(ERR_IO_PENDING,
            store.GetChannelID("b.com", &key,
                               base::Bind(&AsyncGetChannelIDHelper::Callback,
                                          base::Unretained(&b_helper))));

  EXPECT_EQ(0, delete_finished);
  EXPECT_FALSE(a_helper.called_);
  EXPECT_FALSE(b_helper.called_);
  // Wait for load & queued tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, delete_finished);
  EXPECT_EQ(1, store.GetChannelIDCount());
  EXPECT_FALSE(key);
  EXPECT_TRUE(a_helper.called_);
  EXPECT_THAT(a_helper.err_, IsError(ERR_FILE_NOT_FOUND));
  EXPECT_EQ("a.com", a_helper.server_identifier_);
  EXPECT_FALSE(a_helper.key_);
  EXPECT_TRUE(b_helper.called_);
  EXPECT_THAT(b_helper.err_, IsOk());
  EXPECT_EQ("b.com", b_helper.server_identifier_);
  EXPECT_TRUE(KeysEqual(expected_key.get(), b_helper.key_.get()));
}

TEST_F(DefaultChannelIDStoreTest, TestGetAll) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());

  EXPECT_EQ(0, store.GetChannelIDCount());
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "google.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "mit.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set tasks.
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(4, store.GetChannelIDCount());
  ChannelIDStore::ChannelIDList channel_ids;
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids));
  EXPECT_EQ(4u, channel_ids.size());
}

TEST_F(DefaultChannelIDStoreTest, TestInitializeFrom) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  DefaultChannelIDStore store(persistent_store.get());
  std::unique_ptr<crypto::ECPrivateKey> preexisting_key(
      crypto::ECPrivateKey::Create());
  std::unique_ptr<crypto::ECPrivateKey> both_key(
      crypto::ECPrivateKey::Create());
  std::unique_ptr<crypto::ECPrivateKey> copied_key(
      crypto::ECPrivateKey::Create());

  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "preexisting.com", base::Time(), preexisting_key->Copy()));
  store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>(
      "both.com", base::Time(), crypto::ECPrivateKey::Create()));
  // Wait for load & queued set tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(2, store.GetChannelIDCount());

  ChannelIDStore::ChannelIDList source_channel_ids;
  source_channel_ids.push_back(ChannelIDStore::ChannelID(
      "both.com", base::Time(),
      // Key differs from above to test that existing entries are overwritten.
      both_key->Copy()));
  source_channel_ids.push_back(ChannelIDStore::ChannelID(
      "copied.com", base::Time(), copied_key->Copy()));
  store.InitializeFrom(source_channel_ids);
  EXPECT_EQ(3, store.GetChannelIDCount());

  ChannelIDStore::ChannelIDList channel_ids;
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids));
  ASSERT_EQ(3u, channel_ids.size());

  auto channel_id = channel_ids.begin();
  EXPECT_EQ("both.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(both_key.get(), channel_id->key()));

  ++channel_id;
  EXPECT_EQ("copied.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(copied_key.get(), channel_id->key()));

  ++channel_id;
  EXPECT_EQ("preexisting.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(preexisting_key.get(), channel_id->key()));
}

TEST_F(DefaultChannelIDStoreTest, TestAsyncInitializeFrom) {
  scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
  std::unique_ptr<crypto::ECPrivateKey> preexisting_key(
      crypto::ECPrivateKey::Create());
  std::unique_ptr<crypto::ECPrivateKey> both_key(
      crypto::ECPrivateKey::Create());
  std::unique_ptr<crypto::ECPrivateKey> copied_key(
      crypto::ECPrivateKey::Create());

  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "preexisting.com", base::Time(), preexisting_key->Copy()));
  persistent_store->AddChannelID(ChannelIDStore::ChannelID(
      "both.com", base::Time(), crypto::ECPrivateKey::Create()));

  DefaultChannelIDStore store(persistent_store.get());
  ChannelIDStore::ChannelIDList source_channel_ids;
  source_channel_ids.push_back(ChannelIDStore::ChannelID(
      "both.com", base::Time(),
      // Key differs from above to test that existing entries are overwritten.
      both_key->Copy()));
  source_channel_ids.push_back(ChannelIDStore::ChannelID(
      "copied.com", base::Time(), copied_key->Copy()));
  store.InitializeFrom(source_channel_ids);
  EXPECT_EQ(0, store.GetChannelIDCount());
  // Wait for load & queued tasks.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(3, store.GetChannelIDCount());

  ChannelIDStore::ChannelIDList channel_ids;
  store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids));
  ASSERT_EQ(3u, channel_ids.size());

  auto channel_id = channel_ids.begin();
  EXPECT_EQ("both.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(both_key.get(), channel_id->key()));

  ++channel_id;
  EXPECT_EQ("copied.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(copied_key.get(), channel_id->key()));

  ++channel_id;
  EXPECT_EQ("preexisting.com", channel_id->server_identifier());
  EXPECT_TRUE(KeysEqual(preexisting_key.get(), channel_id->key()));
}

}  // namespace net
